diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-12-27 08:27:12 +0100 |
---|---|---|
committer | Thomas Wolf <thomas.wolf@paranor.ch> | 2021-12-27 08:30:43 +0100 |
commit | d986d97dfa992577005e7eee872629de66acca3b (patch) | |
tree | 56e14bc55deef35a745381ced1ac826a1a658a87 | |
parent | 6a24cdc5eac9ca351e4956f1cfbe4954d145666b (diff) | |
parent | f77519775d7cd5638be71e91f70ff11fd653e6c5 (diff) | |
download | jgit-d986d97dfa992577005e7eee872629de66acca3b.tar.gz jgit-d986d97dfa992577005e7eee872629de66acca3b.zip |
Merge branch 'master' into next
* master:
Revert "RefDirectory.scanRef: Re-use file existence check done in snapshot creation"
TreeRevFilter: fix wrong stop when the given path disappears
Add config reader for user-defined difftools
PackBitmapIndexV1: support parallel loading of reverse index
Change-Id: I7db97dabaef06e6fdbfa0e8ae7833a4b0d6f2013
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
19 files changed, 801 insertions, 46 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java index 2ce50c7827..e7bf48417d 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java @@ -12,10 +12,12 @@ package org.eclipse.jgit.pgm; import static org.junit.Assert.assertEquals; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool; import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.pgm.opt.CmdLineParser; import org.eclipse.jgit.pgm.opt.SubcommandHandler; @@ -135,16 +137,24 @@ public class DiffToolTest extends CLIRepositoryTestCase { @Test public void testToolHelp() throws Exception { - String[] expectedOutput = { - "git difftool --tool=<tool> may be set to one of the following:", + CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values(); + List<String> expectedOutput = new ArrayList<>(); + expectedOutput.add("git difftool --tool=<tool> may be set to one of the following:"); + for (CommandLineDiffTool defaultTool : defaultTools) { + String toolName = defaultTool.name(); + expectedOutput.add(toolName); + } + String[] userDefinedToolsHelp = { "user-defined:", "The following tools are valid, but not currently available:", "Some of the tools listed above only work in a windowed", - "environment. If run in a terminal-only session, they will fail.", }; + "environment. If run in a terminal-only session, they will fail.", + }; + expectedOutput.addAll(Arrays.asList(userDefinedToolsHelp)); String option = "--tool-help"; assertArrayOfLinesEquals("Incorrect output for option: " + option, - expectedOutput, runAndCaptureUsingInitRaw("difftool", option)); + expectedOutput.toArray(new String[0]), runAndCaptureUsingInitRaw("difftool", option)); } private RevCommit createUnstagedChanges() throws Exception { diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java index 9fc26c9356..d26842c641 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java @@ -199,20 +199,20 @@ class DiffTool extends TextBuiltin { } private void showToolHelp() throws IOException { - String availableToolNames = new String(); + StringBuilder availableToolNames = new StringBuilder(); for (String name : diffTools.getAvailableTools().keySet()) { - availableToolNames += String.format("\t\t{0}\n", name); //$NON-NLS-1$ + availableToolNames.append(String.format("\t\t%s\n", name)); //$NON-NLS-1$ } - String notAvailableToolNames = new String(); + StringBuilder notAvailableToolNames = new StringBuilder(); for (String name : diffTools.getNotAvailableTools().keySet()) { - notAvailableToolNames += String.format("\t\t{0}\n", name); //$NON-NLS-1$ + notAvailableToolNames.append(String.format("\t\t%s\n", name)); //$NON-NLS-1$ } - String userToolNames = new String(); + StringBuilder userToolNames = new StringBuilder(); Map<String, ExternalDiffTool> userTools = diffTools .getUserDefinedTools(); for (String name : userTools.keySet()) { - availableToolNames += String.format("\t\t{0}.cmd {1}\n", //$NON-NLS-1$ - name, userTools.get(name).getCommand()); + userToolNames.append(String.format("\t\t%s.cmd %s\n", //$NON-NLS-1$ + name, userTools.get(name).getCommand())); } outw.println(MessageFormat.format( CLIText.get().diffToolHelpSetToFollowing, availableToolNames, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java index f07d9d1afc..b141a86f76 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java @@ -9,9 +9,18 @@ */ package org.eclipse.jgit.internal.diffmergetool; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import org.eclipse.jgit.lib.internal.BooleanTriState; @@ -29,27 +38,64 @@ public class ExternalDiffToolTest extends ExternalToolTest { Set<String> actualToolNames = manager.getToolNames(); Set<String> expectedToolNames = Collections.emptySet(); assertEquals("Incorrect set of external diff tool names", - expectedToolNames, - actualToolNames); + expectedToolNames, actualToolNames); } @Test public void testAllTools() { DiffTools manager = new DiffTools(db); Set<String> actualToolNames = manager.getAvailableTools().keySet(); - Set<String> expectedToolNames = Collections.emptySet(); - assertEquals("Incorrect set of available external diff tools", - expectedToolNames, + Set<String> expectedToolNames = new LinkedHashSet<>(); + CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values(); + for (CommandLineDiffTool defaultTool : defaultTools) { + String toolName = defaultTool.name(); + expectedToolNames.add(toolName); + } + assertEquals("Incorrect set of external diff tools", expectedToolNames, actualToolNames); } @Test + public void testOverridePredefinedToolPath() { + String toolName = CommandLineDiffTool.guiffy.name(); + String customToolPath = "/usr/bin/echo"; + + FileBasedConfig config = db.getConfig(); + config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD, + "echo"); + config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_PATH, + customToolPath); + + DiffTools manager = new DiffTools(db); + Map<String, ExternalDiffTool> tools = manager.getUserDefinedTools(); + ExternalDiffTool diffTool = tools.get(toolName); + assertNotNull("Expected tool \"" + toolName + "\" to be user defined", + diffTool); + + String toolPath = diffTool.getPath(); + assertEquals("Expected external diff tool to have an overriden path", + customToolPath, toolPath); + } + + @Test public void testUserDefinedTools() { + FileBasedConfig config = db.getConfig(); + String customToolname = "customTool"; + config.setString(CONFIG_DIFFTOOL_SECTION, customToolname, + CONFIG_KEY_CMD, "echo"); + config.setString(CONFIG_DIFFTOOL_SECTION, customToolname, + CONFIG_KEY_PATH, "/usr/bin/echo"); + config.setString(CONFIG_DIFFTOOL_SECTION, customToolname, + CONFIG_KEY_PROMPT, "--no-prompt"); + config.setString(CONFIG_DIFFTOOL_SECTION, customToolname, + CONFIG_KEY_GUITOOL, "--no-gui"); + config.setString(CONFIG_DIFFTOOL_SECTION, customToolname, + CONFIG_KEY_TRUST_EXIT_CODE, "--no-trust-exit-code"); DiffTools manager = new DiffTools(db); Set<String> actualToolNames = manager.getUserDefinedTools().keySet(); - Set<String> expectedToolNames = Collections.emptySet(); - assertEquals("Incorrect set of user defined external diff tools", - expectedToolNames, + Set<String> expectedToolNames = new LinkedHashSet<>(); + expectedToolNames.add(customToolname); + assertEquals("Incorrect set of external diff tools", expectedToolNames, actualToolNames); } @@ -59,8 +105,7 @@ public class ExternalDiffToolTest extends ExternalToolTest { Set<String> actualToolNames = manager.getNotAvailableTools().keySet(); Set<String> expectedToolNames = Collections.emptySet(); assertEquals("Incorrect set of not available external diff tools", - expectedToolNames, - actualToolNames); + expectedToolNames, actualToolNames); } @Test @@ -80,8 +125,7 @@ public class ExternalDiffToolTest extends ExternalToolTest { int compareResult = manager.compare(newPath, oldPath, newId, oldId, toolName, prompt, gui, trustExitCode); assertEquals("Incorrect compare result for external diff tool", - expectedCompareResult, - compareResult); + expectedCompareResult, compareResult); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java index 4f1314057f..070d666ee5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTest.java @@ -290,6 +290,31 @@ public class DfsBlockCacheTest { assertEquals(1, cache.getMissCount()[0]); } + @SuppressWarnings("resource") + @Test + public void highConcurrencyParallelReads_oneRepoParallelReverseIndex() + throws Exception { + InMemoryRepository r1 = createRepoWithBitmap("test"); + resetCache(); + + DfsReader reader = (DfsReader) r1.newObjectReader(); + reader.getOptions().setLoadRevIndexInParallel(true); + for (DfsPackFile pack : r1.getObjectDatabase().getPacks()) { + // Only load non-garbage pack with bitmap. + if (pack.isGarbage()) { + continue; + } + asyncRun(() -> pack.getBitmapIndex(reader)); + asyncRun(() -> pack.getPackIndex(reader)); + asyncRun(() -> pack.getBitmapIndex(reader)); + } + waitForExecutorPoolTermination(); + + assertEquals(1, cache.getMissCount()[PackExt.BITMAP_INDEX.ordinal()]); + assertEquals(1, cache.getMissCount()[PackExt.INDEX.ordinal()]); + assertEquals(1, cache.getMissCount()[0]); + } + private void resetCache() { resetCache(32); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java index 31629f3de9..5cce11aa1f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java @@ -15,6 +15,7 @@ import static org.junit.Assert.assertNull; import java.util.Collections; +import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.TreeFilter; @@ -253,4 +254,23 @@ public class RevWalkPathFilter1Test extends RevWalkTestCase { assertEquals(0, a.getParentCount()); assertNull(rw.next()); } + + @Test + public void testStopWhenPathDisappears() throws Exception { + DirCacheEntry file1 = file("src/d1/file1", blob("a")); + DirCacheEntry file2 = file("src/d1/file2", blob("a")); + DirCacheEntry file3 = file("src/d1/file3", blob("a")); + RevCommit a = commit(tree(file1)); + RevCommit b = commit(tree(file1, file2), a); + RevCommit c = commit(tree(file1, file3), a); + RevCommit d = commit(tree(file1, file2, file3), b, c); + filter("src/d1"); + markStart(d); + rw.setRewriteParents(false); + + assertCommit(d, rw.next()); + assertCommit(c, rw.next()); + assertCommit(b, rw.next()); + assertCommit(a, rw.next()); + } } diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index fe0765ea09..1a3978f3ae 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -72,6 +72,7 @@ Export-Package: org.eclipse.jgit.annotations;version="7.0.0", org.eclipse.jgit.http.test", org.eclipse.jgit.internal.diffmergetool;version="7.0.0"; x-friends:="org.eclipse.jgit.test, + org.eclipse.jgit.pgm.test, org.eclipse.jgit.pgm", org.eclipse.jgit.internal.fsck;version="7.0.0"; x-friends:="org.eclipse.jgit.test", diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java new file mode 100644 index 0000000000..509515c37a --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineDiffTool.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +/** + * Pre-defined command line diff tools. + * + * Adds same diff tools as also pre-defined in C-Git + * <p> + * see "git-core\mergetools\" + * </p> + * <p> + * see links to command line parameter description for the tools + * </p> + * + * <pre> + * araxis + * bc + * bc3 + * codecompare + * deltawalker + * diffmerge + * diffuse + * ecmerge + * emerge + * examdiff + * guiffy + * gvimdiff + * gvimdiff2 + * gvimdiff3 + * kdiff3 + * kompare + * meld + * opendiff + * p4merge + * tkdiff + * vimdiff + * vimdiff2 + * vimdiff3 + * winmerge + * xxdiff + * </pre> + * + */ +@SuppressWarnings("nls") +public enum CommandLineDiffTool { + /** + * See: <a href= + * "https://www.araxis.com/merge/documentation-windows/command-line.en">https://www.araxis.com/merge/documentation-windows/command-line.en</a> + */ + araxis("compare", "-wait -2 \"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a> + */ + bc("bcomp", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a> + */ + bc3("bcompare", bc), + /** + * See: <a href= + * "https://www.devart.com/codecompare/docs/index.html?comparing_via_command_line.htm">https://www.devart.com/codecompare/docs/index.html?comparing_via_command_line.htm</a> + */ + codecompare("CodeCompare", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.deltawalker.com/integrate/command-line">https://www.deltawalker.com/integrate/command-line</a> + */ + deltawalker("DeltaWalker", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html">https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html</a> + */ + diffmerge("diffmerge", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://diffuse.sourceforge.net/manual.html#introduction-usage">http://diffuse.sourceforge.net/manual.html#introduction-usage</a> + */ + diffuse("diffuse", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp">http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp</a> + */ + ecmerge("ecmerge", "--default --mode=diff2 \"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html">https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html</a> + */ + emerge("emacs", "-f emerge-files-command \"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options">https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options</a> + */ + examdiff("ExamDiff", "\"$LOCAL\" \"$REMOTE\" -nh"), + /** + * See: <a href= + * "https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html">https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html</a> + */ + guiffy("guiffy", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + gvimdiff("gviewdiff", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + gvimdiff2(gvimdiff), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + gvimdiff3(gvimdiff), + /** + * See: <a href= + * "http://kdiff3.sourceforge.net/doc/documentation.html">http://kdiff3.sourceforge.net/doc/documentation.html</a> + */ + kdiff3("kdiff3", + "--L1 \"$MERGED (A)\" --L2 \"$MERGED (B)\" \"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://docs.kde.org/trunk5/en/kdesdk/kompare/commandline-options.html">https://docs.kde.org/trunk5/en/kdesdk/kompare/commandline-options.html</a> + */ + kompare("kompare", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "ttp://meldmerge.org/help/file-mode.html">http://meldmerge.org/help/file-mode.html</a> + */ + meld("meld", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://www.manpagez.com/man/1/opendiff/">http://www.manpagez.com/man/1/opendiff/</a> + * <p> + * Hint: check the ' | cat' for the call + * </p> + */ + opendiff("opendiff", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html">https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html</a> + */ + p4merge("p4merge", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://linux.math.tifr.res.in/manuals/man/tkdiff.html">http://linux.math.tifr.res.in/manuals/man/tkdiff.html</a> + */ + tkdiff("tkdiff", "\"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff("viewdiff", gvimdiff), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff2(vimdiff), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff3(vimdiff), + /** + * See: <a href= + * "http://manual.winmerge.org/Command_line.html">http://manual.winmerge.org/Command_line.html</a> + * <p> + * Hint: check how 'mergetool_find_win32_cmd "WinMergeU.exe" "WinMerge"' + * works + * </p> + */ + winmerge("WinMergeU", "-u -e \"$LOCAL\" \"$REMOTE\""), + /** + * See: <a href= + * "http://furius.ca/xxdiff/doc/xxdiff-doc.html">http://furius.ca/xxdiff/doc/xxdiff-doc.html</a> + */ + xxdiff("xxdiff", + "-R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' \"$LOCAL\" \"$REMOTE\""); + + CommandLineDiffTool(String path, String parameters) { + this.path = path; + this.parameters = parameters; + } + + CommandLineDiffTool(CommandLineDiffTool from) { + this(from.getPath(), from.getParameters()); + } + + CommandLineDiffTool(String path, CommandLineDiffTool from) { + this(path, from.getParameters()); + } + + private final String path; + + private final String parameters; + + /** + * @return path + */ + public String getPath() { + return path; + } + + /** + * @return parameters as one string + */ + public String getParameters() { + return parameters; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java new file mode 100644 index 0000000000..551f634f2d --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffToolConfig.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Config.SectionParser; +import org.eclipse.jgit.lib.internal.BooleanTriState; + +/** + * Keeps track of difftool related configuration options. + */ +public class DiffToolConfig { + + /** Key for {@link Config#get(SectionParser)}. */ + public static final Config.SectionParser<DiffToolConfig> KEY = DiffToolConfig::new; + + private final String toolName; + + private final String guiToolName; + + private final boolean prompt; + + private final BooleanTriState trustExitCode; + + private final Map<String, ExternalDiffTool> tools; + + private DiffToolConfig(Config rc) { + toolName = rc.getString(CONFIG_DIFF_SECTION, null, CONFIG_KEY_TOOL); + guiToolName = rc.getString(CONFIG_DIFF_SECTION, null, + CONFIG_KEY_GUITOOL); + prompt = rc.getBoolean(CONFIG_DIFFTOOL_SECTION, CONFIG_KEY_PROMPT, + true); + String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, null, + CONFIG_KEY_TRUST_EXIT_CODE); + if (trustStr != null) { + trustExitCode = Boolean.parseBoolean(trustStr) + ? BooleanTriState.TRUE + : BooleanTriState.FALSE; + } else { + trustExitCode = BooleanTriState.UNSET; + } + tools = new HashMap<>(); + Set<String> subsections = rc.getSubsections(CONFIG_DIFFTOOL_SECTION); + for (String name : subsections) { + String cmd = rc.getString(CONFIG_DIFFTOOL_SECTION, name, + CONFIG_KEY_CMD); + String path = rc.getString(CONFIG_DIFFTOOL_SECTION, name, + CONFIG_KEY_PATH); + if ((cmd != null) || (path != null)) { + tools.put(name, new UserDefinedDiffTool(name, path, cmd)); + } + } + } + + /** + * @return the default diff tool name (diff.tool) + */ + public String getDefaultToolName() { + return toolName; + } + + /** + * @return the default GUI diff tool name (diff.guitool) + */ + public String getDefaultGuiToolName() { + return guiToolName; + } + + /** + * @return the diff tool "prompt" option (difftool.prompt) + */ + public boolean isPrompt() { + return prompt; + } + + /** + * @return the diff tool "trust exit code" option (difftool.trustExitCode) + */ + public boolean isTrustExitCode() { + return trustExitCode == BooleanTriState.TRUE; + } + + /** + * @return the tools map + */ + public Map<String, ExternalDiffTool> getTools() { + return tools; + } + + /** + * @return the tool names + */ + public Set<String> getToolNames() { + return tools.keySet(); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java index cb0640d2e8..39729a4eec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java @@ -23,6 +23,8 @@ import org.eclipse.jgit.lib.internal.BooleanTriState; */ public class DiffTools { + private final DiffToolConfig config; + private Map<String, ExternalDiffTool> predefinedTools; private Map<String, ExternalDiffTool> userDefinedTools; @@ -31,9 +33,10 @@ public class DiffTools { * Creates the external diff-tools manager for given repository. * * @param repo - * the repository database + * the repository */ public DiffTools(Repository repo) { + config = repo.getConfig().get(DiffToolConfig.KEY); setupPredefinedTools(); setupUserDefinedTools(); } @@ -69,7 +72,7 @@ public class DiffTools { * @return the tool names */ public Set<String> getToolNames() { - return Collections.emptySet(); + return config.getToolNames(); } /** @@ -112,10 +115,29 @@ public class DiffTools { private void setupPredefinedTools() { predefinedTools = new TreeMap<>(); + for (CommandLineDiffTool tool : CommandLineDiffTool.values()) { + predefinedTools.put(tool.name(), new PreDefinedDiffTool(tool)); + } } private void setupUserDefinedTools() { userDefinedTools = new TreeMap<>(); + Map<String, ExternalDiffTool> userTools = config.getTools(); + for (String name : userTools.keySet()) { + ExternalDiffTool userTool = userTools.get(name); + // if difftool.<name>.cmd is defined we have user defined tool + if (userTool.getCommand() != null) { + userDefinedTools.put(name, userTool); + } else if (userTool.getPath() != null) { + // if difftool.<name>.path is defined we just overload the path + // of predefined tool + PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefinedTools + .get(name); + if (predefTool != null) { + predefTool.setPath(userTool.getPath()); + } + } + } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java new file mode 100644 index 0000000000..1c69fb4911 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedDiffTool.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +/** + * The pre-defined diff tool. + */ +public class PreDefinedDiffTool extends UserDefinedDiffTool { + + /** + * Create a pre-defined diff tool + * + * @param name + * the name + * @param path + * the path + * @param parameters + * the tool parameters as one string that is used together with + * path as command + */ + public PreDefinedDiffTool(String name, String path, String parameters) { + super(name, path, parameters); + } + + /** + * Creates the pre-defined diff tool + * + * @param tool + * the command line diff tool + * + */ + public PreDefinedDiffTool(CommandLineDiffTool tool) { + this(tool.name(), tool.getPath(), tool.getParameters()); + } + + /** + * @param path + */ + @Override + public void setPath(String path) { + // handling of spaces in path + if (path.contains(" ")) { //$NON-NLS-1$ + // add quotes before if needed + if (!path.startsWith("\"")) { //$NON-NLS-1$ + path = "\"" + path; //$NON-NLS-1$ + } + // add quotes after if needed + if (!path.endsWith("\"")) { //$NON-NLS-1$ + path = path + "\""; //$NON-NLS-1$ + } + } + super.setPath(path); + } + + /** + * {@inheritDoc} + * + * @return the concatenated path and command of the pre-defined diff tool + */ + @Override + public String getCommand() { + return getPath() + " " + super.getCommand(); //$NON-NLS-1$ + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java new file mode 100644 index 0000000000..012296eb35 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedDiffTool.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +/** + * The user-defined diff tool. + */ +public class UserDefinedDiffTool implements ExternalDiffTool { + + /** + * the diff tool name + */ + private final String name; + + /** + * the diff tool path + */ + private String path; + + /** + * the diff tool command + */ + private final String cmd; + + /** + * Creates the diff tool + * + * @param name + * the name + * @param path + * the path + * @param cmd + * the command + */ + public UserDefinedDiffTool(String name, String path, String cmd) { + this.name = name; + this.path = path; + this.cmd = cmd; + } + + /** + * @return the diff tool name + */ + @Override + public String getName() { + return name; + } + + /** + * The path of the diff tool. + * + * <p> + * The path to a pre-defined external diff tool can be overridden by + * specifying {@code difftool.<tool>.path} in a configuration file. + * </p> + * <p> + * For a user defined diff tool (that does not override a pre-defined diff + * tool), the path is ignored when invoking the tool. + * </p> + * + * @return the diff tool path + * + * @see <a href= + * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a> + */ + @Override + public String getPath() { + return path; + } + + /** + * The command of the diff tool. + * + * <p> + * A pre-defined external diff tool can be overridden using the tools name + * in a configuration file. The overwritten tool is then a user defined tool + * and the command of the diff tool is specified with + * {@code difftool.<tool>.cmd}. This command must work without prepending + * the value of {@link #getPath()} and can sometimes include tool + * parameters. + * </p> + * + * @return the diff tool command + * + * @see <a href= + * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a> + */ + @Override + public String getCommand() { + return cmd; + } + + /** + * Overrides the path for the given tool. Equivalent to setting + * {@code difftool.<tool>.path}. + * + * @param path + * the new diff tool path + * + * @see <a href= + * "https://git-scm.com/docs/git-difftool">https://git-scm.com/docs/git-difftool</a> + */ + public void setPath(String path) { + this.path = path; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java index bb76df1d5d..f7a2c94d48 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java @@ -1061,7 +1061,8 @@ public final class DfsPackFile extends BlockBasedFile { } in = new BufferedInputStream(in, bs); bmidx = PackBitmapIndex.read(in, () -> idx(ctx), - () -> getReverseIdx(ctx)); + () -> getReverseIdx(ctx), + ctx.getOptions().shouldLoadRevIndexInParallel()); } finally { size = rc.position(); ctx.stats.readBitmapIdxBytes += size; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java index 89de53460c..146f76167d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderOptions.java @@ -34,6 +34,8 @@ public class DfsReaderOptions { private int streamPackBufferSize; + private boolean loadRevIndexInParallel; + /** * Create a default reader configuration. */ @@ -113,6 +115,28 @@ public class DfsReaderOptions { } /** + * Check if reverse index should be loaded in parallel. + * + * @return true if reverse index is loaded in parallel for bitmap index. + */ + public boolean shouldLoadRevIndexInParallel() { + return loadRevIndexInParallel; + } + + /** + * Enable (or disable) parallel loading of reverse index. + * + * @param loadRevIndexInParallel + * whether to load reverse index in parallel. + * @return {@code this} + */ + public DfsReaderOptions setLoadRevIndexInParallel( + boolean loadRevIndexInParallel) { + this.loadRevIndexInParallel = loadRevIndexInParallel; + return this; + } + + /** * Update properties by setting fields from the configuration. * <p> * If a property is not defined in the configuration, then it is left diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java index 5ab973f533..6088c152a1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileSnapshot.java @@ -420,15 +420,6 @@ public class FileSnapshot { return equals(other); } - /** - * Check if the file exists - * - * @return true if the file exists - */ - public boolean fileExists() { - return !MISSING_FILEKEY.equals(this.fileKey); - } - /** {@inheritDoc} */ @Override public int hashCode() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java index 8401f0718a..8fb17fcf21 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java @@ -95,7 +95,7 @@ public abstract class PackBitmapIndex { */ public static PackBitmapIndex read(InputStream fd, PackIndex packIndex, PackReverseIndex reverseIndex) throws IOException { - return new PackBitmapIndexV1(fd, () -> packIndex, () -> reverseIndex); + return new PackBitmapIndexV1(fd, packIndex, reverseIndex); } /** @@ -114,6 +114,8 @@ public abstract class PackBitmapIndex { * @param reverseIndexSupplier * the supplier for pack reverse index for the corresponding pack * file. + * @param loadParallelRevIndex + * whether reverse index should be loaded in parallel * @return a copy of the index in-memory. * @throws java.io.IOException * the stream cannot be read. @@ -122,10 +124,11 @@ public abstract class PackBitmapIndex { */ public static PackBitmapIndex read(InputStream fd, SupplierWithIOException<PackIndex> packIndexSupplier, - SupplierWithIOException<PackReverseIndex> reverseIndexSupplier) + SupplierWithIOException<PackReverseIndex> reverseIndexSupplier, + boolean loadParallelRevIndex) throws IOException { return new PackBitmapIndexV1(fd, packIndexSupplier, - reverseIndexSupplier); + reverseIndexSupplier, loadParallelRevIndex); } /** Footer checksum applied on the bottom of the pack file. */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java index 6846e3bcad..21aba3e6a3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java @@ -17,6 +17,12 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.internal.JGitText; @@ -40,6 +46,23 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex { private static final int MAX_XOR_OFFSET = 126; + private static final ExecutorService executor = Executors + .newCachedThreadPool(new ThreadFactory() { + private final ThreadFactory baseFactory = Executors + .defaultThreadFactory(); + + private final AtomicInteger threadNumber = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable runnable) { + Thread thread = baseFactory.newThread(runnable); + thread.setName("JGit-PackBitmapIndexV1-" //$NON-NLS-1$ + + threadNumber.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + }); + private final PackIndex packIndex; private final PackReverseIndex reverseIndex; private final EWAHCompressedBitmap commits; @@ -49,15 +72,28 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex { private final ObjectIdOwnerMap<StoredBitmap> bitmaps; + PackBitmapIndexV1(final InputStream fd, PackIndex packIndex, + PackReverseIndex reverseIndex) throws IOException { + this(fd, () -> packIndex, () -> reverseIndex, false); + } + PackBitmapIndexV1(final InputStream fd, SupplierWithIOException<PackIndex> packIndexSupplier, - SupplierWithIOException<PackReverseIndex> reverseIndexSupplier) + SupplierWithIOException<PackReverseIndex> reverseIndexSupplier, + boolean loadParallelRevIndex) throws IOException { // An entry is object id, xor offset, flag byte, and a length encoded // bitmap. The object id is an int32 of the nth position sorted by name. super(new ObjectIdOwnerMap<StoredBitmap>()); this.bitmaps = getBitmaps(); + // Optionally start loading reverse index in parallel to loading bitmap + // from storage. + Future<PackReverseIndex> reverseIndexFuture = null; + if (loadParallelRevIndex) { + reverseIndexFuture = executor.submit(reverseIndexSupplier::get); + } + final byte[] scratch = new byte[32]; IO.readFully(fd, scratch, 0, scratch.length); @@ -164,7 +200,18 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex { bitmaps.add(sb); } - this.reverseIndex = reverseIndexSupplier.get(); + PackReverseIndex computedReverseIndex; + if (loadParallelRevIndex && reverseIndexFuture != null) { + try { + computedReverseIndex = reverseIndexFuture.get(); + } catch (InterruptedException | ExecutionException e) { + // Fallback to loading reverse index through a supplier. + computedReverseIndex = reverseIndexSupplier.get(); + } + } else { + computedReverseIndex = reverseIndexSupplier.get(); + } + this.reverseIndex = computedReverseIndex; } /** {@inheritDoc} */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java index 2167262dd5..07e38147f7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java @@ -1092,10 +1092,6 @@ public class RefDirectory extends RefDatabase { final int limit = 4096; final byte[] buf; FileSnapshot otherSnapshot = FileSnapshot.save(path); - if (!otherSnapshot.fileExists()) { - return null; - } - try { buf = IO.readSome(path, limit); } catch (FileNotFoundException noFile) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index 24eebc6a19..4b21e4be4e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -1,7 +1,8 @@ /* * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> - * Copyright (C) 2012, 2020, Robin Rosenberg and others + * Copyright (C) 2012-2013, Robin Rosenberg + * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -29,6 +30,48 @@ public final class ConfigConstants { /** The "diff" section */ public static final String CONFIG_DIFF_SECTION = "diff"; + /** + * The "tool" key within "diff" section + * + * @since 6.1 + */ + public static final String CONFIG_KEY_TOOL = "tool"; + + /** + * The "guitool" key within "diff" section + * + * @since 6.1 + */ + public static final String CONFIG_KEY_GUITOOL = "guitool"; + + /** + * The "difftool" section + * + * @since 6.1 + */ + public static final String CONFIG_DIFFTOOL_SECTION = "difftool"; + + /** + * The "prompt" key within "difftool" section + * + * @since 6.1 + */ + public static final String CONFIG_KEY_PROMPT = "prompt"; + + /** + * The "trustExitCode" key within "difftool" section + * + * @since 6.1 + */ + public static final String CONFIG_KEY_TRUST_EXIT_CODE = "trustExitCode"; + + /** + * The "cmd" key within "difftool.*." section + * + * @since 6.1 + */ + public static final String CONFIG_KEY_CMD = "cmd"; + /** The "dfs" section */ public static final String CONFIG_DFS_SECTION = "dfs"; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java index e465024311..822fc5320c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java @@ -211,7 +211,10 @@ public class TreeRevFilter extends RevFilter { // "empty tree root" and thus their history is not relevant. // Cut our grandparents to be an empty list. // - pList[i].parents = RevCommit.NO_PARENTS; + tw.reset(pList[i].getTree()); + if (!tw.next()) { + pList[i].parents = RevCommit.NO_PARENTS; + } } // We have an interesting difference relative to this parent. |