diff options
Diffstat (limited to 'org.eclipse.jgit')
56 files changed, 702 insertions, 191 deletions
diff --git a/org.eclipse.jgit/BUCK b/org.eclipse.jgit/BUCK index 2bae6dcf25..73e2080576 100644 --- a/org.eclipse.jgit/BUCK +++ b/org.eclipse.jgit/BUCK @@ -9,7 +9,6 @@ java_library( '//lib:javaewah', '//lib:jsch', '//lib:httpcomponents', - '//lib:servlet-api', '//lib:slf4j-api', ], visibility = ['PUBLIC'], diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD new file mode 100644 index 0000000000..a9b01e9ea6 --- /dev/null +++ b/org.eclipse.jgit/BUILD @@ -0,0 +1,33 @@ +package(default_visibility = ["//visibility:public"]) + +INSECURE_CIPHER_FACTORY = [ + "src/org/eclipse/jgit/transport/InsecureCipherFactory.java", +] + +SRCS = glob( + ["src/**"], + exclude = INSECURE_CIPHER_FACTORY, +) + +RESOURCES = glob(["resources/**"]) + +java_library( + name = "jgit", + srcs = SRCS, + resource_strip_prefix = "org.eclipse.jgit/resources", + resources = RESOURCES, + deps = [ + ":insecure_cipher_factory", + "@httpclient//jar", + "@javaewah//jar", + "@jsch//jar", + "@log_api//jar", + "@servlet_api_3_1//jar", + ], +) + +java_library( + name = "insecure_cipher_factory", + srcs = INSECURE_CIPHER_FACTORY, + javacopts = ["-Xep:InsecureCipherMode:OFF"], +) diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 22d42751b4..8b78628209 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -2,12 +2,12 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 4.6.1.qualifier +Bundle-Version: 4.7.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.jgit.annotations;version="4.6.1", - org.eclipse.jgit.api;version="4.6.1"; +Export-Package: org.eclipse.jgit.annotations;version="4.7.0", + org.eclipse.jgit.api;version="4.7.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, @@ -21,47 +21,51 @@ Export-Package: org.eclipse.jgit.annotations;version="4.6.1", org.eclipse.jgit.submodule, org.eclipse.jgit.transport, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="4.6.1", - org.eclipse.jgit.blame;version="4.6.1"; + org.eclipse.jgit.api.errors;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors", + org.eclipse.jgit.attributes;version="4.7.0", + org.eclipse.jgit.blame;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff", - org.eclipse.jgit.diff;version="4.6.1"; + org.eclipse.jgit.diff;version="4.7.0"; uses:="org.eclipse.jgit.patch, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util", - org.eclipse.jgit.dircache;version="4.6.1"; + org.eclipse.jgit.dircache;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.util, org.eclipse.jgit.events, org.eclipse.jgit.attributes", - org.eclipse.jgit.errors;version="4.6.1"; + org.eclipse.jgit.errors;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.transport, org.eclipse.jgit.dircache", - org.eclipse.jgit.events;version="4.6.1";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="4.6.1", - org.eclipse.jgit.gitrepo;version="4.6.1"; + org.eclipse.jgit.events;version="4.7.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.fnmatch;version="4.7.0", + org.eclipse.jgit.gitrepo;version="4.7.0"; uses:="org.eclipse.jgit.api, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.xml.sax.helpers, org.xml.sax", - org.eclipse.jgit.gitrepo.internal;version="4.6.1";x-internal:=true, - org.eclipse.jgit.hooks;version="4.6.1";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.ignore;version="4.6.1", - org.eclipse.jgit.ignore.internal;version="4.6.1";x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="4.6.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.ketch;version="4.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.dfs;version="4.6.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server,org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.storage.file;version="4.6.1"; + org.eclipse.jgit.gitrepo.internal;version="4.7.0";x-internal:=true, + org.eclipse.jgit.hooks;version="4.7.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.ignore;version="4.7.0", + org.eclipse.jgit.ignore.internal;version="4.7.0";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.internal;version="4.7.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", + org.eclipse.jgit.internal.ketch;version="4.7.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.storage.dfs;version="4.7.0"; + x-friends:="org.eclipse.jgit.test, + org.eclipse.jgit.http.server, + org.eclipse.jgit.http.test, + org.eclipse.jgit.lfs.test", + org.eclipse.jgit.internal.storage.file;version="4.7.0"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, @@ -69,9 +73,9 @@ Export-Package: org.eclipse.jgit.annotations;version="4.6.1", org.eclipse.jgit.lfs, org.eclipse.jgit.pgm, org.eclipse.jgit.pgm.test", - org.eclipse.jgit.internal.storage.pack;version="4.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftree;version="4.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.lib;version="4.6.1"; + org.eclipse.jgit.internal.storage.pack;version="4.7.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.storage.reftree;version="4.7.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.lib;version="4.7.0"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, @@ -81,32 +85,32 @@ Export-Package: org.eclipse.jgit.annotations;version="4.6.1", org.eclipse.jgit.treewalk, org.eclipse.jgit.transport, org.eclipse.jgit.submodule", - org.eclipse.jgit.merge;version="4.6.1"; + org.eclipse.jgit.merge;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.diff, org.eclipse.jgit.dircache, org.eclipse.jgit.api", - org.eclipse.jgit.nls;version="4.6.1", - org.eclipse.jgit.notes;version="4.6.1"; + org.eclipse.jgit.nls;version="4.7.0", + org.eclipse.jgit.notes;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk", - org.eclipse.jgit.revwalk;version="4.6.1"; + org.eclipse.jgit.patch;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff", + org.eclipse.jgit.revplot;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk", + org.eclipse.jgit.revwalk;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.revwalk.filter", - org.eclipse.jgit.revwalk.filter;version="4.6.1";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="4.6.1";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk", - org.eclipse.jgit.transport;version="4.6.1"; + org.eclipse.jgit.revwalk.filter;version="4.7.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.file;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.pack;version="4.7.0";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.submodule;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk", + org.eclipse.jgit.transport;version="4.7.0"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.revwalk, org.eclipse.jgit.internal.storage.pack, @@ -118,29 +122,28 @@ Export-Package: org.eclipse.jgit.annotations;version="4.6.1", org.eclipse.jgit.transport.http, org.eclipse.jgit.errors, org.eclipse.jgit.storage.pack", - org.eclipse.jgit.transport.http;version="4.6.1";uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="4.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", - org.eclipse.jgit.treewalk;version="4.6.1"; + org.eclipse.jgit.transport.http;version="4.7.0";uses:="javax.net.ssl", + org.eclipse.jgit.transport.resolver;version="4.7.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", + org.eclipse.jgit.treewalk;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.attributes, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, org.eclipse.jgit.dircache", - org.eclipse.jgit.treewalk.filter;version="4.6.1";uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="4.6.1"; + org.eclipse.jgit.treewalk.filter;version="4.7.0";uses:="org.eclipse.jgit.treewalk", + org.eclipse.jgit.util;version="4.7.0"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.transport.http, org.eclipse.jgit.storage.file, org.ietf.jgss", - org.eclipse.jgit.util.io;version="4.6.1", - org.eclipse.jgit.util.time;version="4.6.1" + org.eclipse.jgit.util.io;version="4.7.0", + org.eclipse.jgit.util.time;version="4.7.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.37,0.2.0)", javax.crypto, javax.net.ssl, - javax.servlet.http;version="[2.5.0,3.2.0)", org.slf4j;version="[1.7.0,2.0.0)", org.xml.sax, org.xml.sax.helpers diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index e310d9b280..9287b6f2e9 100644 --- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit - Sources Bundle-SymbolicName: org.eclipse.jgit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 4.6.1.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="4.6.1.qualifier";roots="." +Bundle-Version: 4.7.0.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="4.7.0.qualifier";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 1aee726dd3..6465a00b69 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml @@ -53,7 +53,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>4.6.1-SNAPSHOT</version> + <version>4.7.0-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit</artifactId> @@ -89,11 +89,6 @@ <artifactId>slf4j-api</artifactId> </dependency> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - <scope>provided</scope> - </dependency> </dependencies> <build> diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index b9b74bfc21..8bf2155d93 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -31,6 +31,7 @@ badGroupHeader=Bad group header badObjectType=Bad object type: {0} badRef=Bad ref: {0}: {1} badSectionEntry=Bad section entry: {0} +badShallowLine=Bad shallow line: {0} bareRepositoryNoWorkdirAndIndex=Bare Repository has neither a working tree, nor an index base64InputNotProperlyPadded=Base64 input not properly padded. baseLengthIncorrect=base length incorrect @@ -187,7 +188,7 @@ corruptObjectTruncatedInMode=truncated in mode corruptObjectTruncatedInName=truncated in name corruptObjectTruncatedInObjectId=truncated in object id corruptObjectZeroId=entry points to null SHA-1 -corruptUseCnt=close() called when useCnt is already zero +corruptUseCnt=close() called when useCnt is already zero for {0} couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java index dd5da1582f..b065b9484b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -151,23 +151,35 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { } } + private static boolean isNonEmptyDirectory(File dir) { + if (dir != null && dir.exists()) { + File[] files = dir.listFiles(); + return files != null && files.length != 0; + } + return false; + } + private Repository init(URIish u) throws GitAPIException { InitCommand command = Git.init(); command.setBare(bare); - if (directory == null && gitDir == null) + if (directory == null && gitDir == null) { directory = new File(u.getHumanishName(), Constants.DOT_GIT); + } validateDirs(directory, gitDir, bare); - if (directory != null && directory.exists() - && directory.listFiles().length != 0) + if (isNonEmptyDirectory(directory)) { throw new JGitInternalException(MessageFormat.format( JGitText.get().cloneNonEmptyDirectory, directory.getName())); - if (gitDir != null && gitDir.exists() && gitDir.listFiles().length != 0) + } + if (isNonEmptyDirectory(gitDir)) { throw new JGitInternalException(MessageFormat.format( JGitText.get().cloneNonEmptyDirectory, gitDir.getName())); - if (directory != null) + } + if (directory != null) { command.setDirectory(directory); - if (gitDir != null) + } + if (gitDir != null) { command.setGitDir(gitDir); + } return command.call().getRepository(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java index d0f729cc62..0f38db53ba 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java @@ -159,6 +159,38 @@ public class GarbageCollectCommand extends GitCommand<Properties> { return this; } + /** + * Whether to preserve old pack files instead of deleting them. + * + * @since 4.7 + * @param preserveOldPacks + * whether to preserve old pack files + * @return this instance + */ + public GarbageCollectCommand setPreserveOldPacks(boolean preserveOldPacks) { + if (pconfig == null) + pconfig = new PackConfig(repo); + + pconfig.setPreserveOldPacks(preserveOldPacks); + return this; + } + + /** + * Whether to prune preserved pack files in the preserved directory. + * + * @since 4.7 + * @param prunePreserved + * whether to prune preserved pack files + * @return this instance + */ + public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) { + if (pconfig == null) + pconfig = new PackConfig(repo); + + pconfig.setPrunePreserved(prunePreserved); + return this; + } + @Override public Properties call() throws GitAPIException { checkCallable(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java index ced1863719..2daa0d1a3b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java @@ -50,6 +50,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import org.eclipse.jgit.api.MergeResult.MergeStatus; @@ -134,7 +135,7 @@ public class MergeCommand extends GitCommand<MergeResult> { FF_ONLY; public String toConfigValue() { - return "--" + name().toLowerCase().replace('_', '-'); //$NON-NLS-1$ + return "--" + name().toLowerCase(Locale.ROOT).replace('_', '-'); //$NON-NLS-1$ } public boolean matchConfigValue(String in) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index b8ee1ec0b3..fc8bb874fb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java @@ -232,19 +232,19 @@ public class StashApplyCommand extends GitCommand<ObjectId> { untrackedMerger.setBase(null); boolean ok = untrackedMerger.merge(headCommit, untrackedCommit); - if (ok) + if (ok) { try { RevTree untrackedTree = revWalk - .parseTree(untrackedMerger - .getResultTreeId()); + .parseTree(untrackedCommit); resetUntracked(untrackedTree); } catch (CheckoutConflictException e) { throw new StashApplyFailureException( - JGitText.get().stashApplyConflict); + JGitText.get().stashApplyConflict, e); } - else + } else { throw new StashApplyFailureException( JGitText.get().stashApplyConflict); + } } } else { throw new StashApplyFailureException( diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java index 819442cbea..fa7cc0df87 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java @@ -682,7 +682,7 @@ public class DiffFormatter implements AutoCloseable { } private static byte[] writeGitLinkText(AbbreviatedObjectId id) { - if (id.toObjectId().equals(ObjectId.zeroId())) { + if (ObjectId.zeroId().equals(id.toObjectId())) { return EMPTY; } return encodeASCII("Subproject commit " + id.name() //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java new file mode 100644 index 0000000000..c2833a1614 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CancelledException.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 Ericsson + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.errors; + +import java.io.IOException; + +/** + * Thrown when an operation was canceled + * + * @since 4.7 + */ +public class CancelledException extends IOException { + private static final long serialVersionUID = 1L; + + /** + * @param message + */ + public CancelledException(String message) { + super(message); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java index 8a35d35fea..55ded92a17 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java @@ -57,6 +57,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.gitrepo.RepoProject.CopyFile; import org.eclipse.jgit.gitrepo.internal.RepoText; @@ -324,7 +325,7 @@ public class ManifestParser extends DefaultHandler { * * @return filtered projects list reference, never null */ - public List<RepoProject> getFilteredProjects() { + public @NonNull List<RepoProject> getFilteredProjects() { return filteredProjects; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java index 86dbabca0b..d18cd97489 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -181,9 +181,8 @@ public class RepoCommand extends GitCommand<RevCommit> { throws GitAPIException, IOException { File dir = FileUtils.createTempDir("jgit_", ".git", null); //$NON-NLS-1$ //$NON-NLS-2$ try (Git git = Git.cloneRepository().setBare(true).setDirectory(dir) - .setURI(uri).call(); - Repository repo = git.getRepository()) { - return readFileFromRepo(repo, ref, path); + .setURI(uri).call()) { + return readFileFromRepo(git.getRepository(), ref, path); } finally { FileUtils.delete(dir, FileUtils.RECURSIVE); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java index 4e90d8c3cb..64c2a74554 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/AbstractMatcher.java @@ -46,8 +46,6 @@ package org.eclipse.jgit.ignore.internal; * Base class for default methods as {@link #toString()} and such. * <p> * This class is immutable and thread safe. - * - * @since 3.6 */ public abstract class AbstractMatcher implements IMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java index 8bb4dfb564..4c13e2ff6a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/IMatcher.java @@ -44,8 +44,6 @@ package org.eclipse.jgit.ignore.internal; /** * Generic string matcher - * - * @since 3.6 */ public interface IMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java index 3d0ad09124..3ebc6afb2c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/LeadingAsteriskMatcher.java @@ -44,8 +44,6 @@ package org.eclipse.jgit.ignore.internal; /** * Matcher for simple regex patterns starting with an asterisk, e.g. "*.tmp" - * - * @since 3.6 */ public class LeadingAsteriskMatcher extends NameMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java index 8beae8379e..888b989b62 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/NameMatcher.java @@ -47,8 +47,6 @@ import static org.eclipse.jgit.ignore.internal.Strings.getPathSeparator; /** * Matcher built from patterns for file names (single path segments). This class * is immutable and thread safe. - * - * @since 3.6 */ public class NameMatcher extends AbstractMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java index c3f6694a7a..adf13292bf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java @@ -59,8 +59,6 @@ import org.eclipse.jgit.ignore.internal.Strings.PatternState; * Matcher built by patterns consists of multiple path segments. * <p> * This class is immutable and thread safe. - * - * @since 3.6 */ public class PathMatcher extends AbstractMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java index 70c5199030..1c467fe71b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java @@ -58,8 +58,6 @@ import org.eclipse.jgit.internal.JGitText; /** * Various {@link String} related utility methods, written mostly to avoid * generation of new String objects (e.g. via splitting Strings etc). - * - * @since 3.6 */ public class Strings { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java index b927d27dbe..c7064ac851 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/TrailingAsteriskMatcher.java @@ -44,8 +44,6 @@ package org.eclipse.jgit.ignore.internal; /** * Matcher for simple patterns ending with an asterisk, e.g. "Makefile.*" - * - * @since 3.6 */ public class TrailingAsteriskMatcher extends NameMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java index 8f9815283d..f64050f83c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildCardMatcher.java @@ -53,8 +53,6 @@ import org.eclipse.jgit.errors.InvalidPatternException; * glob wildcards to Java {@link Pattern}'s. * <p> * This class is immutable and thread safe. - * - * @since 3.6 */ public class WildCardMatcher extends NameMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java index d578654375..2f24e02410 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/WildMatcher.java @@ -47,8 +47,6 @@ package org.eclipse.jgit.ignore.internal; * matcher matches any path. * <p> * This class is immutable and thread safe. - * - * @since 3.6 */ public final class WildMatcher extends AbstractMatcher { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index ada5bf7116..244356c13b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -90,6 +90,7 @@ public class JGitText extends TranslationBundle { /***/ public String badObjectType; /***/ public String badRef; /***/ public String badSectionEntry; + /***/ public String badShallowLine; /***/ public String bareRepositoryNoWorkdirAndIndex; /***/ public String base64InputNotProperlyPadded; /***/ public String baseLengthIncorrect; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java index 047c86f289..9f7f350833 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/BeforeDfsPackIndexLoadedListener.java @@ -47,8 +47,6 @@ import org.eclipse.jgit.events.RepositoryListener; /** * Receives {@link BeforeDfsPackIndexLoadedEvent}s. - * - * @since 2.2 */ public interface BeforeDfsPackIndexLoadedListener extends RepositoryListener { /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java index 089bfa471d..feadedbc88 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java @@ -122,7 +122,6 @@ public class DfsBlockCacheConfig { /** * @return the estimated number of threads concurrently accessing the cache. * <b>Default is 32.</b> - * @since 4.6 */ public int getConcurrencyLevel() { return concurrencyLevel; @@ -133,7 +132,6 @@ public class DfsBlockCacheConfig { * the estimated number of threads concurrently accessing the * cache. * @return {@code this} - * @since 4.6 */ public DfsBlockCacheConfig setConcurrencyLevel( final int newConcurrencyLevel) { @@ -145,7 +143,6 @@ public class DfsBlockCacheConfig { * @return highest percentage of {@link #getBlockLimit()} a single pack can * occupy while being copied by the pack reuse strategy. <b>Default * is 0.30, or 30%</b>. - * @since 4.0 */ public double getStreamRatio() { return streamRatio; @@ -155,7 +152,6 @@ public class DfsBlockCacheConfig { * @param ratio * percentage of cache to occupy with a copied pack. * @return {@code this} - * @since 4.0 */ public DfsBlockCacheConfig setStreamRatio(double ratio) { streamRatio = Math.max(0, Math.min(ratio, 1.0)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java index 6f760caea1..56ff1b5c2e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java @@ -43,9 +43,12 @@ package org.eclipse.jgit.internal.storage.dfs; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.RECEIVE; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; @@ -55,6 +58,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -63,6 +67,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.file.PackReverseIndex; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.internal.storage.pack.PackWriter; import org.eclipse.jgit.internal.storage.reftree.RefTreeNames; @@ -253,7 +258,7 @@ public class DfsGarbageCollector { for (Ref ref : refsBefore) { if (ref.isSymbolic() || ref.getObjectId() == null) continue; - if (isHead(ref)) + if (isHead(ref) || isTag(ref)) allHeads.add(ref.getObjectId()); else if (RefTreeNames.isRefTree(refdb, ref.getName())) txnHeads.add(ref.getObjectId()); @@ -390,7 +395,8 @@ public class DfsGarbageCollector { pw.setTagTargets(tagTargets); pw.preparePack(pm, allHeads, PackWriter.NONE); if (0 < pw.getObjectCount()) - writePack(GC, pw, pm); + writePack(GC, pw, pm, + estimateGcPackSize(INSERT, RECEIVE, COMPACT, GC)); } } @@ -403,7 +409,8 @@ public class DfsGarbageCollector { pw.excludeObjects(packedObjs); pw.preparePack(pm, nonHeads, allHeads); if (0 < pw.getObjectCount()) - writePack(GC_REST, pw, pm); + writePack(GC_REST, pw, pm, + estimateGcPackSize(INSERT, RECEIVE, COMPACT, GC_REST)); } } @@ -416,7 +423,7 @@ public class DfsGarbageCollector { pw.excludeObjects(packedObjs); pw.preparePack(pm, txnHeads, PackWriter.NONE); if (0 < pw.getObjectCount()) - writePack(GC_TXN, pw, pm); + writePack(GC_TXN, pw, pm, 0 /* unknown pack size */); } } @@ -432,21 +439,29 @@ public class DfsGarbageCollector { pw.setDeltaBaseAsOffset(true); pw.setReuseDeltaCommits(true); pm.beginTask(JGitText.get().findingGarbage, objectsBefore()); + long estimatedPackSize = 12 + 20; // header and trailer sizes. for (DfsPackFile oldPack : packsBefore) { PackIndex oldIdx = oldPack.getPackIndex(ctx); + PackReverseIndex oldRevIdx = oldPack.getReverseIdx(ctx); + long maxOffset = oldPack.getPackDescription().getFileSize(PACK) + - 20; // pack size - trailer size. for (PackIndex.MutableEntry ent : oldIdx) { pm.update(1); ObjectId id = ent.toObjectId(); if (pool.lookupOrNull(id) != null || anyPackHas(id)) continue; - int type = oldPack.getObjectType(ctx, ent.getOffset()); + long offset = ent.getOffset(); + int type = oldPack.getObjectType(ctx, offset); pw.addObject(pool.lookupAny(id, type)); + long objSize = oldRevIdx.findNextOffset(offset, maxOffset) + - offset; + estimatedPackSize += objSize; } } pm.endTask(); if (0 < pw.getObjectCount()) - writePack(UNREACHABLE_GARBAGE, pw, pm); + writePack(UNREACHABLE_GARBAGE, pw, pm, estimatedPackSize); } } @@ -461,6 +476,10 @@ public class DfsGarbageCollector { return ref.getName().startsWith(Constants.R_HEADS); } + private static boolean isTag(Ref ref) { + return ref.getName().startsWith(Constants.R_TAGS); + } + private int objectsBefore() { int cnt = 0; for (DfsPackFile p : packsBefore) @@ -475,9 +494,24 @@ public class DfsGarbageCollector { return pw; } + private long estimateGcPackSize(PackSource first, PackSource... rest) { + EnumSet<PackSource> sourceSet = EnumSet.of(first, rest); + // Every pack file contains 12 bytes of header and 20 bytes of trailer. + // Include the final pack file header and trailer size here and ignore + // the same from individual pack files. + long size = 32; + for (DfsPackDescription pack : getSourcePacks()) { + if (sourceSet.contains(pack.getPackSource())) { + size += pack.getFileSize(PACK) - 32; + } + } + return size; + } + private DfsPackDescription writePack(PackSource source, PackWriter pw, - ProgressMonitor pm) throws IOException { - DfsPackDescription pack = repo.getObjectDatabase().newPack(source); + ProgressMonitor pm, long estimatedPackSize) throws IOException { + DfsPackDescription pack = repo.getObjectDatabase().newPack(source, + estimatedPackSize); newPackDesc.add(pack); try (DfsOutputStream out = objdb.writeFile(pack, PACK)) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java index b1d6c0dd19..b68527544a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java @@ -266,6 +266,32 @@ public abstract class DfsObjDatabase extends ObjectDatabase { throws IOException; /** + * Generate a new unique name for a pack file. + * + * <p> + * Default implementation of this method would be equivalent to + * {@code newPack(source).setEstimatedPackSize(estimatedPackSize)}. But the + * clients can override this method to use the given + * {@code estomatedPackSize} value more efficiently in the process of + * creating a new {@link DfsPackDescription} object. + * + * @param source + * where the pack stream is created. + * @param estimatedPackSize + * the estimated size of the pack. + * @return a unique name for the pack file. Must not collide with any other + * pack file name in the same DFS. + * @throws IOException + * a new unique pack description cannot be generated. + */ + protected DfsPackDescription newPack(PackSource source, + long estimatedPackSize) throws IOException { + DfsPackDescription pack = newPack(source); + pack.setEstimatedPackSize(estimatedPackSize); + return pack; + } + + /** * Commit a pack and index pair that was written to the DFS. * <p> * Committing the pack/index pair makes them visible to readers. The JGit diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java index 11aef7feaf..ba3b39360b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java @@ -224,7 +224,8 @@ public class DfsPackCompactor { } boolean rollback = true; - DfsPackDescription pack = objdb.newPack(COMPACT); + DfsPackDescription pack = objdb.newPack(COMPACT, + estimatePackSize()); try { writePack(objdb, pack, pw, pm); writeIndex(objdb, pack, pw); @@ -251,6 +252,17 @@ public class DfsPackCompactor { } } + private long estimatePackSize() { + // Every pack file contains 12 bytes of header and 20 bytes of trailer. + // Include the final pack file header and trailer size here and ignore + // the same from individual pack files. + long size = 32; + for (DfsPackFile pack : srcPacks) { + size += pack.getPackDescription().getFileSize(PACK) - 32; + } + return size; + } + /** @return all of the source packs that fed into this compaction. */ public List<DfsPackDescription> getSourcePacks() { return toPrune(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java index 2b9d0e55c7..0411bbe5e4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackDescription.java @@ -81,6 +81,8 @@ public class DfsPackDescription implements Comparable<DfsPackDescription> { private int indexVersion; + private long estimatedPackSize; + /** * Initialize a description by pack name and repository. * <p> @@ -189,6 +191,25 @@ public class DfsPackDescription implements Comparable<DfsPackDescription> { return size == null ? 0 : size.longValue(); } + /** + * @param estimatedPackSize + * estimated size of the .pack file in bytes. If 0 the pack file + * size is unknown. + * @return {@code this} + */ + public DfsPackDescription setEstimatedPackSize(long estimatedPackSize) { + this.estimatedPackSize = Math.max(0, estimatedPackSize); + return this; + } + + /** + * @return estimated size of the .pack file in bytes. If 0 the pack file + * size is unknown. + */ + public long getEstimatedPackSize() { + return estimatedPackSize; + } + /** @return number of objects in the pack. */ public long getObjectCount() { return objectCount; 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 4eabb03163..f15d427f8d 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 @@ -187,7 +187,6 @@ public final class DfsPackFile { /** * @return whether the pack index file is loaded and cached in memory. - * @since 2.2 */ public boolean isIndexLoaded() { DfsBlockCache.Ref<PackIndex> idxref = index; @@ -499,6 +498,7 @@ public final class DfsPackFile { rc.setReadAheadBytes(ctx.getOptions().getStreamPackBufferSize()); long position = 12; long remaining = length - (12 + 20); + boolean packHeadSkipped = false; while (0 < remaining) { DfsBlock b = cache.get(key, alignToBlock(position)); if (b != null) { @@ -508,6 +508,7 @@ public final class DfsPackFile { position += n; remaining -= n; rc.position(position); + packHeadSkipped = true; continue; } @@ -517,7 +518,14 @@ public final class DfsPackFile { throw packfileIsTruncated(); else if (n > remaining) n = (int) remaining; - out.write(buf.array(), 0, n); + + if (!packHeadSkipped) { + // Need skip the 'PACK' header for the first read + out.write(buf.array(), 12, n - 12); + packHeadSkipped = true; + } else { + out.write(buf.array(), 0, n); + } position += n; remaining -= n; } 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 84198077eb..d07c13d0b0 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 @@ -109,7 +109,6 @@ public class DfsReaderOptions { /** * @return number of bytes to use for buffering when streaming a pack file * during copying. If 0 the block size of the pack is used. - * @since 4.0 */ public int getStreamPackBufferSize() { return streamPackBufferSize; @@ -120,7 +119,6 @@ public class DfsReaderOptions { * new buffer size in bytes for buffers used when streaming pack * files during copying. * @return {@code this} - * @since 4.0 */ public DfsReaderOptions setStreamPackBufferSize(int bufsz) { streamPackBufferSize = Math.max(0, bufsz); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java index fd213977a8..bdcf9f9a14 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java @@ -63,7 +63,6 @@ public class InMemoryRepository extends DfsRepository { * * @param repoDesc * description of the repository. - * @since 2.0 */ public InMemoryRepository(DfsRepositoryDescription repoDesc) { this(new Builder().setRepositoryDescription(repoDesc)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index 0388acbbaf..16315a5b55 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -55,6 +55,7 @@ import java.io.IOException; import java.text.MessageFormat; import java.text.ParseException; import java.util.HashSet; +import java.util.Locale; import java.util.Objects; import java.util.Set; @@ -342,7 +343,7 @@ public class FileRepository extends Repository { if (symLinks != null) cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_SYMLINKS, symLinks.name() - .toLowerCase()); + .toLowerCase(Locale.ROOT)); cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0); cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index e3e73e25f7..87a5ee5ae4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -79,11 +79,14 @@ import java.util.stream.Stream; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.CancelledException; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.ObjectDirectory; +import org.eclipse.jgit.internal.storage.file.ObjectDirectoryInserter; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.internal.storage.pack.PackWriter; import org.eclipse.jgit.internal.storage.reftree.RefTreeNames; @@ -93,6 +96,8 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdSet; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref.Storage; @@ -219,11 +224,41 @@ public class GC { } /** + * Loosen objects in a pack file which are not also in the newly-created + * pack files. + * + * @param inserter + * @param reader + * @param pack + * @param existing + * @throws IOException + */ + private void loosen(ObjectDirectoryInserter inserter, ObjectReader reader, PackFile pack, HashSet<ObjectId> existing) + throws IOException { + for (PackIndex.MutableEntry entry : pack) { + ObjectId oid = entry.toObjectId(); + if (existing.contains(oid)) { + continue; + } + existing.add(oid); + ObjectLoader loader = reader.open(oid); + inserter.insert(loader.getType(), + loader.getSize(), + loader.openStream(), + true /* create this object even though it's a duplicate */); + } + } + + /** * Delete old pack files. What is 'old' is defined by specifying a set of * old pack files and a set of new pack files. Each pack file contained in - * old pack files but not contained in new pack files will be deleted. If an - * expirationDate is set then pack files which are younger than the - * expirationDate will not be deleted. + * old pack files but not contained in new pack files will be deleted. If + * preserveOldPacks is set, keep a copy of the pack file in the preserve + * directory. If an expirationDate is set then pack files which are younger + * than the expirationDate will not be deleted nor preserved. + * <p> + * If we're not immediately expiring loose objects, loosen any objects + * in the old pack files which aren't in the new pack files. * * @param oldPacks * @param newPacks @@ -232,8 +267,21 @@ public class GC { */ private void deleteOldPacks(Collection<PackFile> oldPacks, Collection<PackFile> newPacks) throws ParseException, IOException { + HashSet<ObjectId> ids = new HashSet<>(); + for (PackFile pack : newPacks) { + for (PackIndex.MutableEntry entry : pack) { + ids.add(entry.toObjectId()); + } + } + ObjectReader reader = repo.newObjectReader(); + ObjectDirectory dir = repo.getObjectDatabase(); + ObjectDirectoryInserter inserter = dir.newInserter(); + boolean shouldLoosen = getExpireDate() < Long.MAX_VALUE; + + prunePreserved(); long packExpireDate = getPackExpireDate(); oldPackLoop: for (PackFile oldPack : oldPacks) { + checkCancelled(); String oldName = oldPack.getPackName(); // check whether an old pack file is also among the list of new // pack files. Then we must not delete it. @@ -245,15 +293,56 @@ public class GC { && repo.getFS().lastModified( oldPack.getPackFile()) < packExpireDate) { oldPack.close(); + if (shouldLoosen) { + loosen(inserter, reader, oldPack, ids); + } prunePack(oldName); } } - // close the complete object database. Thats my only chance to force + // close the complete object database. That's my only chance to force // rescanning and to detect that certain pack files are now deleted. repo.getObjectDatabase().close(); } /** + * Deletes old pack file, unless 'preserve-oldpacks' is set, in which case it + * moves the pack file to the preserved directory + * + * @param packFile + * @param packName + * @param ext + * @param deleteOptions + * @throws IOException + */ + private void removeOldPack(File packFile, String packName, PackExt ext, + int deleteOptions) throws IOException { + if (pconfig != null && pconfig.isPreserveOldPacks()) { + File oldPackDir = repo.getObjectDatabase().getPreservedDirectory(); + FileUtils.mkdir(oldPackDir, true); + + String oldPackName = "pack-" + packName + ".old-" + ext.getExtension(); //$NON-NLS-1$ //$NON-NLS-2$ + File oldPackFile = new File(oldPackDir, oldPackName); + FileUtils.rename(packFile, oldPackFile); + } else { + FileUtils.delete(packFile, deleteOptions); + } + } + + /** + * Delete the preserved directory including all pack files within + */ + private void prunePreserved() { + if (pconfig != null && pconfig.isPrunePreserved()) { + try { + FileUtils.delete(repo.getObjectDatabase().getPreservedDirectory(), + FileUtils.RECURSIVE | FileUtils.RETRY | FileUtils.SKIP_MISSING); + } catch (IOException e) { + // Deletion of the preserved pack files failed. Silently return. + } + } + } + + /** * Delete files associated with a single pack file. First try to delete the * ".pack" file because on some platforms the ".pack" file may be locked and * can't be deleted. In such a case it is better to detect this early and @@ -272,7 +361,7 @@ public class GC { for (PackExt ext : extensions) if (PackExt.PACK.equals(ext)) { File f = nameFor(packName, "." + ext.getExtension()); //$NON-NLS-1$ - FileUtils.delete(f, deleteOptions); + removeOldPack(f, packName, ext, deleteOptions); break; } // The .pack file has been deleted. Delete as many as the other @@ -281,7 +370,7 @@ public class GC { for (PackExt ext : extensions) { if (!PackExt.PACK.equals(ext)) { File f = nameFor(packName, "." + ext.getExtension()); //$NON-NLS-1$ - FileUtils.delete(f, deleteOptions); + removeOldPack(f, packName, ext, deleteOptions); } } } catch (IOException e) { @@ -306,6 +395,7 @@ public class GC { pm.beginTask(JGitText.get().pruneLoosePackedObjects, fanout.length); try { for (String d : fanout) { + checkCancelled(); pm.update(1); if (d.length() != 2) continue; @@ -313,6 +403,7 @@ public class GC { if (entries == null) continue; for (String e : entries) { + checkCancelled(); if (e.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) continue; ObjectId id; @@ -324,11 +415,13 @@ public class GC { continue; } boolean found = false; - for (PackFile p : packs) + for (PackFile p : packs) { + checkCancelled(); if (p.hasObject(id)) { found = true; break; } + } if (found) FileUtils.delete(objdb.fileFor(id), FileUtils.RETRY | FileUtils.SKIP_MISSING @@ -369,6 +462,7 @@ public class GC { fanout.length); try { for (String d : fanout) { + checkCancelled(); pm.update(1); if (d.length() != 2) continue; @@ -376,6 +470,7 @@ public class GC { if (entries == null) continue; for (File f : entries) { + checkCancelled(); String fName = f.getName(); if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) continue; @@ -404,6 +499,8 @@ public class GC { if (deletionCandidates.isEmpty()) return; + checkCancelled(); + // From the set of current refs remove all those which have been handled // during last repack(). Only those refs will survive which have been // added or modified since the last repack. Only these can save existing @@ -433,11 +530,14 @@ public class GC { // leave this method. ObjectWalk w = new ObjectWalk(repo); try { - for (Ref cr : newRefs) + for (Ref cr : newRefs) { + checkCancelled(); w.markStart(w.parseAny(cr.getObjectId())); + } if (lastPackedRefs != null) - for (Ref lpr : lastPackedRefs) + for (Ref lpr : lastPackedRefs) { w.markUninteresting(w.parseAny(lpr.getObjectId())); + } removeReferenced(deletionCandidates, w); } finally { w.dispose(); @@ -455,11 +555,15 @@ public class GC { ObjectWalk w = new ObjectWalk(repo); try { for (Ref ar : getAllRefs()) - for (ObjectId id : listRefLogObjects(ar, lastRepackTime)) + for (ObjectId id : listRefLogObjects(ar, lastRepackTime)) { + checkCancelled(); w.markStart(w.parseAny(id)); + } if (lastPackedRefs != null) - for (Ref lpr : lastPackedRefs) + for (Ref lpr : lastPackedRefs) { + checkCancelled(); w.markUninteresting(w.parseAny(lpr.getObjectId())); + } removeReferenced(deletionCandidates, w); } finally { w.dispose(); @@ -468,6 +572,8 @@ public class GC { if (deletionCandidates.isEmpty()) return; + checkCancelled(); + // delete all candidates which have survived: these are unreferenced // loose objects. Make a last check, though, to avoid deleting objects // that could have been referenced while the candidates list was being @@ -536,6 +642,7 @@ public class GC { IncorrectObjectTypeException, IOException { RevObject ro = w.next(); while (ro != null) { + checkCancelled(); if (id2File.remove(ro.getId()) != null) if (id2File.isEmpty()) return; @@ -543,6 +650,7 @@ public class GC { } ro = w.nextObject(); while (ro != null) { + checkCancelled(); if (id2File.remove(ro.getId()) != null) if (id2File.isEmpty()) return; @@ -576,6 +684,7 @@ public class GC { pm.beginTask(JGitText.get().packRefs, refs.size()); try { for (Ref ref : refs) { + checkCancelled(); if (!ref.isSymbolic() && ref.getStorage().isLoose()) refsToBePacked.add(ref.getName()); pm.update(1); @@ -614,10 +723,11 @@ public class GC { RefDatabase refdb = repo.getRefDatabase(); for (Ref ref : refsBefore) { + checkCancelled(); nonHeads.addAll(listRefLogObjects(ref, 0)); if (ref.isSymbolic() || ref.getObjectId() == null) continue; - if (ref.getName().startsWith(Constants.R_HEADS)) + if (isHead(ref) || isTag(ref)) allHeads.add(ref.getObjectId()); else if (RefTreeNames.isRefTree(refdb, ref.getName())) txnHeads.add(ref.getObjectId()); @@ -628,9 +738,11 @@ public class GC { } List<ObjectIdSet> excluded = new LinkedList<ObjectIdSet>(); - for (final PackFile f : repo.getObjectDatabase().getPacks()) + for (final PackFile f : repo.getObjectDatabase().getPacks()) { + checkCancelled(); if (f.shouldBeKept()) excluded.add(f.getIndex()); + } tagTargets.addAll(allHeads); nonHeads.addAll(indexObjects); @@ -671,6 +783,14 @@ public class GC { return ret; } + private static boolean isHead(Ref ref) { + return ref.getName().startsWith(Constants.R_HEADS); + } + + private static boolean isTag(Ref ref) { + return ref.getName().startsWith(Constants.R_TAGS); + } + /** * Deletes orphans * <p> @@ -763,6 +883,7 @@ public class GC { all.addAll(refs); // add additional refs which start with refs/ for (Ref r : addl) { + checkCancelled(); if (r.getName().startsWith(Constants.R_REFS)) { all.add(r); } @@ -800,6 +921,7 @@ public class GC { Set<ObjectId> ret = new HashSet<ObjectId>(); while (treeWalk.next()) { + checkCancelled(); ObjectId objectId = treeWalk.getObjectId(0); switch (treeWalk.getRawMode(0) & FileMode.TYPE_MASK) { case FileMode.TYPE_MISSING: @@ -827,6 +949,7 @@ public class GC { private PackFile writePack(@NonNull Set<? extends ObjectId> want, @NonNull Set<? extends ObjectId> have, Set<ObjectId> tagTargets, List<ObjectIdSet> excludeObjects) throws IOException { + checkCancelled(); File tmpPack = null; Map<PackExt, File> tmpExts = new TreeMap<PackExt, File>( new Comparator<PackExt>() { @@ -858,6 +981,7 @@ public class GC { pw.preparePack(pm, want, have); if (pw.getObjectCount() == 0) return null; + checkCancelled(); // create temporary files String id = pw.computeName().getName(); @@ -974,6 +1098,12 @@ public class GC { return new File(packdir, "pack-" + name + ext); //$NON-NLS-1$ } + private void checkCancelled() throws CancelledException { + if (pm.isCancelled()) { + throw new CancelledException(JGitText.get().operationCanceled); + } + } + /** * A class holding statistical data for a FileRepository regarding how many * objects are stored as loose or packed objects @@ -1125,7 +1255,6 @@ public class GC { * influence how packs are written and to implement something similar to * "git gc --aggressive" * - * @since 3.6 * @param pconfig * the {@link PackConfig} used when writing packs */ @@ -1198,7 +1327,6 @@ public class GC { * * @param auto * defines whether gc should do automatic housekeeping - * @since 4.5 */ public void setAuto(boolean auto) { this.automatic = auto; @@ -1257,9 +1385,10 @@ public class GC { new DirectoryStream.Filter<Path>() { public boolean accept(Path file) throws IOException { - return Files.isRegularFile(file) && PATTERN_LOOSE_OBJECT - .matcher(file.getFileName().toString()) - .matches(); + Path fileName = file.getFileName(); + return Files.isRegularFile(file) && fileName != null + && PATTERN_LOOSE_OBJECT + .matcher(fileName.toString()).matches(); } })) { for (Iterator<Path> iter = stream.iterator(); iter.hasNext(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java index ce9677a62d..fcc8d7178c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java @@ -150,7 +150,6 @@ public class LockFile { * * @param f * the file that will be locked. - * @since 4.2 */ public LockFile(final File f) { ref = f; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java index ea80528518..eec7fb7c3a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java @@ -125,6 +125,8 @@ public class ObjectDirectory extends FileObjectDatabase { private final File packDirectory; + private final File preservedDirectory; + private final File alternatesFile; private final AtomicReference<PackList> packList; @@ -165,6 +167,7 @@ public class ObjectDirectory extends FileObjectDatabase { objects = dir; infoDirectory = new File(objects, "info"); //$NON-NLS-1$ packDirectory = new File(objects, "pack"); //$NON-NLS-1$ + preservedDirectory = new File(packDirectory, "preserved"); //$NON-NLS-1$ alternatesFile = new File(infoDirectory, "alternates"); //$NON-NLS-1$ packList = new AtomicReference<PackList>(NO_PACKS); unpackedObjectCache = new UnpackedObjectCache(); @@ -189,6 +192,13 @@ public class ObjectDirectory extends FileObjectDatabase { return objects; } + /** + * @return the location of the <code>preserved</code> directory. + */ + public final File getPreservedDirectory() { + return preservedDirectory; + } + @Override public boolean exists() { return fs.exists(objects); @@ -690,8 +700,14 @@ public class ObjectDirectory extends FileObjectDatabase { final BufferedReader reader = open(shallowFile); try { String line; - while ((line = reader.readLine()) != null) - shallowCommitsIds.add(ObjectId.fromString(line)); + while ((line = reader.readLine()) != null) { + try { + shallowCommitsIds.add(ObjectId.fromString(line)); + } catch (IllegalArgumentException ex) { + throw new IOException(MessageFormat + .format(JGitText.get().badShallowLine, line)); + } + } } finally { reader.close(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java index 9820e0ea39..a510431f37 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java @@ -86,34 +86,71 @@ class ObjectDirectoryInserter extends ObjectInserter { @Override public ObjectId insert(int type, byte[] data, int off, int len) throws IOException { + return insert(type, data, off, len, false); + } + + /** + * Insert a loose object into the database. If createDuplicate is true, + * write the loose object even if we already have it in the loose or packed + * ODB. + * + * @param type + * @param data + * @param off + * @param len + * @param createDuplicate + * @return ObjectId + * @throws IOException + */ + private ObjectId insert( + int type, byte[] data, int off, int len, boolean createDuplicate) + throws IOException { ObjectId id = idFor(type, data, off, len); - if (db.has(id)) { + if (!createDuplicate && db.has(id)) { return id; } else { File tmp = toTemp(type, data, off, len); - return insertOneObject(tmp, id); + return insertOneObject(tmp, id, createDuplicate); } } @Override public ObjectId insert(final int type, long len, final InputStream is) throws IOException { + return insert(type, len, is, false); + } + + /** + * Insert a loose object into the database. If createDuplicate is true, + * write the loose object even if we already have it in the loose or packed + * ODB. + * + * @param type + * @param len + * @param is + * @param createDuplicate + * @return ObjectId + * @throws IOException + */ + ObjectId insert(int type, long len, InputStream is, boolean createDuplicate) + throws IOException { if (len <= buffer().length) { byte[] buf = buffer(); int actLen = IO.readFully(is, buf, 0); - return insert(type, buf, 0, actLen); + return insert(type, buf, 0, actLen, createDuplicate); } else { MessageDigest md = digest(); File tmp = toTemp(md, type, len, is); ObjectId id = ObjectId.fromRaw(md.digest()); - return insertOneObject(tmp, id); + return insertOneObject(tmp, id, createDuplicate); } } - private ObjectId insertOneObject(final File tmp, final ObjectId id) + private ObjectId insertOneObject( + File tmp, ObjectId id, boolean createDuplicate) throws IOException, ObjectWritingException { - switch (db.insertUnpackedObject(tmp, id, false /* no duplicate */)) { + switch (db.insertUnpackedObject(tmp, id, createDuplicate)) { case INSERTED: case EXISTS_PACKED: case EXISTS_LOOSE: diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java index b385b8ab73..edf44fb6ec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java @@ -46,6 +46,7 @@ package org.eclipse.jgit.internal.storage.file; import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP; import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import java.io.EOFException; @@ -241,7 +242,7 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { */ public boolean shouldBeKept() { if (keepFile == null) - keepFile = new File(packFile.getPath() + ".keep"); //$NON-NLS-1$ + keepFile = extFile(KEEP); return keepFile.exists(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java index fc802666bc..24d2c790ee 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java @@ -74,8 +74,6 @@ import org.eclipse.jgit.util.FileUtils; /** * Utility for writing reflog entries - * - * @since 2.0 */ public class ReflogWriter { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java index 4ee27cc845..248692f93f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackExt.java @@ -53,6 +53,9 @@ public class PackExt { /** A pack index file extension. */ public static final PackExt INDEX = newPackExt("idx"); //$NON-NLS-1$ + /** A keep pack file extension. */ + public static final PackExt KEEP = newPackExt("keep"); //$NON-NLS-1$ + /** A pack bitmap index file extension. */ public static final PackExt BITMAP_INDEX = newPackExt("bitmap"); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java index 8b4d2e6d35..ffab1a7465 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java @@ -164,7 +164,7 @@ public class PackWriter implements AutoCloseable { private static final int PACK_VERSION_GENERATED = 2; /** Empty set of objects for {@code preparePack()}. */ - public static Set<ObjectId> NONE = Collections.emptySet(); + public static final Set<ObjectId> NONE = Collections.emptySet(); private static final Map<WeakReference<PackWriter>, Boolean> instances = new ConcurrentHashMap<WeakReference<PackWriter>, Boolean>(); @@ -369,7 +369,6 @@ public class PackWriter implements AutoCloseable { * the callback to set * * @return this object for chaining. - * @since 4.1 */ public PackWriter setObjectCountCallback(ObjectCountCallback callback) { this.callback = callback; @@ -381,7 +380,6 @@ public class PackWriter implements AutoCloseable { * * @param clientShallowCommits * the shallow commits in the client - * @since 4.1 */ public void setClientShallowCommits(Set<ObjectId> clientShallowCommits) { stats.clientShallowCommits = Collections @@ -742,8 +740,6 @@ public class PackWriter implements AutoCloseable { * Must not be {@code null}. * @throws IOException * an I/O problem occured while reading objects. - * - * @since 4.5 */ public void preparePack(ProgressMonitor countingMonitor, @NonNull Set<? extends ObjectId> want, @@ -1089,8 +1085,6 @@ public class PackWriter implements AutoCloseable { /** * Release all resources used by this writer. - * - * @since 4.0 */ @Override public void close() { @@ -2258,8 +2252,6 @@ public class PackWriter implements AutoCloseable { * @return the count of objects that needed to be discovered through an * object walk because they were not found in bitmap indices. * Returns -1 if no bitmap indices were found. - * - * @since 4.0 */ public long getBitmapIndexMisses() { return statistics.getBitmapIndexMisses(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 8fe8a96e99..ec771a24f0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -58,6 +58,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -895,7 +896,7 @@ public class Config { if (value instanceof ConfigEnum) n = ((ConfigEnum) value).toConfigValue(); else - n = value.name().toLowerCase().replace('_', ' '); + n = value.name().toLowerCase(Locale.ROOT).replace('_', ' '); setString(section, subsection, name, n); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index c5b2ef8e5b..6be97ffda6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -4,6 +4,7 @@ * Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2012, Daniel Megert <daniel_megert@ch.ibm.com> + * Copyright (C) 2017, Wim Jongman <wim.jongman@remainsoftware.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -888,11 +889,12 @@ public abstract class Repository implements AutoCloseable { } else if (newCount == -1) { // should not happen, only log when useCnt became negative to // minimize number of log entries + String message = MessageFormat.format(JGitText.get().corruptUseCnt, + toString()); if (LOG.isDebugEnabled()) { - IllegalStateException e = new IllegalStateException(); - LOG.debug(JGitText.get().corruptUseCnt, e); + LOG.debug(message, new IllegalStateException()); } else { - LOG.warn(JGitText.get().corruptUseCnt); + LOG.warn(message); } if (RepositoryCache.isCached(this)) { closedAt.set(System.currentTimeMillis()); @@ -1887,4 +1889,40 @@ public abstract class Repository implements AutoCloseable { public void autoGC(ProgressMonitor monitor) { // default does nothing } + + /** + * Normalizes the passed branch name into a possible valid branch name. The + * validity of the returned name should be checked by a subsequent call to + * {@link #isValidRefName(String)}. + * <p/> + * Future implementations of this method could be more restrictive or more + * lenient about the validity of specific characters in the returned name. + * <p/> + * The current implementation returns a trimmed string only containing word + * characters ([a-zA-Z_0-9]) and hyphens ('-'). Colons are replaced by + * hyphens. Repeating underscores and hyphens are replaced by a single + * occurrence. Underscores and hyphens at the beginning of the string are + * removed. + * + * @param name + * The name to normalize. + * + * @return The normalized String or null if null was passed. + * @since 4.7 + * @see #isValidRefName(String) + */ + public static String normalizeBranchName(String name) { + if (name == null || name.length() == 0) { + return name; + } + String result = name.trim(); + return result.replaceAll("\\s+([_:-])*?\\s+", "$1") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll(":", "-") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll("\\s+", "_") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll("_{2,}", "_") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll("-{2,}", "-") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll("[^\\w-]", "") //$NON-NLS-1$ //$NON-NLS-2$ + .replaceAll("^_+", "") //$NON-NLS-1$//$NON-NLS-2$ + .replaceAll("^-+", ""); //$NON-NLS-1$//$NON-NLS-2$ + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java index 245b3ee599..767cb24306 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FormatError.java @@ -43,6 +43,8 @@ package org.eclipse.jgit.patch; +import java.util.Locale; + import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.util.RawParseUtils; @@ -102,7 +104,7 @@ public class FormatError { @Override public String toString() { final StringBuilder r = new StringBuilder(); - r.append(getSeverity().name().toLowerCase()); + r.append(getSeverity().name().toLowerCase(Locale.ROOT)); r.append(": at offset "); //$NON-NLS-1$ r.append(getOffset()); r.append(": "); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java index 319b819a79..36965f4996 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/FooterKey.java @@ -43,6 +43,8 @@ package org.eclipse.jgit.revwalk; +import java.util.Locale; + import org.eclipse.jgit.lib.Constants; /** Case insensitive key for a {@link FooterLine}. */ @@ -68,7 +70,7 @@ public final class FooterKey { */ public FooterKey(final String keyName) { name = keyName; - raw = Constants.encode(keyName.toLowerCase()); + raw = Constants.encode(keyName.toLowerCase(Locale.ROOT)); } /** @return name of this footer line. */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java index d594e97671..3176cb30e1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java @@ -75,6 +75,20 @@ public class PackConfig { public static final boolean DEFAULT_REUSE_OBJECTS = true; /** + * Default value of keep old packs option: {@value} + * @see #setPreserveOldPacks(boolean) + * @since 4.7 + */ + public static final boolean DEFAULT_PRESERVE_OLD_PACKS = false; + + /** + * Default value of prune old packs option: {@value} + * @see #setPrunePreserved(boolean) + * @since 4.7 + */ + public static final boolean DEFAULT_PRUNE_PRESERVED = false; + + /** * Default value of delta compress option: {@value} * * @see #setDeltaCompress(boolean) @@ -204,6 +218,10 @@ public class PackConfig { private boolean reuseObjects = DEFAULT_REUSE_OBJECTS; + private boolean preserveOldPacks = DEFAULT_PRESERVE_OLD_PACKS; + + private boolean prunePreserved = DEFAULT_PRUNE_PRESERVED; + private boolean deltaBaseAsOffset = DEFAULT_DELTA_BASE_AS_OFFSET; private boolean deltaCompress = DEFAULT_DELTA_COMPRESS; @@ -281,6 +299,8 @@ public class PackConfig { this.compressionLevel = cfg.compressionLevel; this.reuseDeltas = cfg.reuseDeltas; this.reuseObjects = cfg.reuseObjects; + this.preserveOldPacks = cfg.preserveOldPacks; + this.prunePreserved = cfg.prunePreserved; this.deltaBaseAsOffset = cfg.deltaBaseAsOffset; this.deltaCompress = cfg.deltaCompress; this.maxDeltaDepth = cfg.maxDeltaDepth; @@ -364,6 +384,61 @@ public class PackConfig { } /** + * Checks whether to preserve old packs in a preserved directory + * + * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} + * + * @return true if repacking will preserve old pack files. + * @since 4.7 + */ + public boolean isPreserveOldPacks() { + return preserveOldPacks; + } + + /** + * Set preserve old packs configuration option for repacking. + * + * If enabled, old pack files are moved into a preserved subdirectory instead + * of being deleted + * + * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} + * + * @param preserveOldPacks + * boolean indicating whether or not preserve old pack files + * @since 4.7 + */ + public void setPreserveOldPacks(boolean preserveOldPacks) { + this.preserveOldPacks = preserveOldPacks; + } + + /** + * Checks whether to remove preserved pack files in a preserved directory + * + * Default setting: {@value #DEFAULT_PRUNE_PRESERVED} + * + * @return true if repacking will remove preserved pack files. + * @since 4.7 + */ + public boolean isPrunePreserved() { + return prunePreserved; + } + + /** + * Set prune preserved configuration option for repacking. + * + * If enabled, preserved pack files are removed from a preserved subdirectory + * + * Default setting: {@value #DEFAULT_PRESERVE_OLD_PACKS} + * + * @param prunePreserved + * boolean indicating whether or not preserve old pack files + * @since 4.7 + */ + public void setPrunePreserved(boolean prunePreserved) { + this.prunePreserved = prunePreserved; + } + + /** * True if writer can use offsets to point to a delta base. * * If true the writer may choose to use an offset to point to a delta base diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java index 5b9e8d9029..a10f3d7117 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.submodule; import java.io.File; import java.io.IOException; import java.text.MessageFormat; +import java.util.Locale; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheIterator; @@ -663,7 +664,8 @@ public class SubmoduleWalk implements AutoCloseable { ConfigConstants.CONFIG_KEY_IGNORE); if (name == null) return null; - return IgnoreSubmoduleMode.valueOf(name.trim().toUpperCase()); + return IgnoreSubmoduleMode + .valueOf(name.trim().toUpperCase(Locale.ROOT)); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java index 81e6904bff..4256fe47db 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java @@ -56,6 +56,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Random; @@ -168,7 +169,8 @@ abstract class HttpAuthMethod { SCHEMA_NAME_SEPARATOR, 2); try { - Type methodType = Type.valueOf(valuePart[0].toUpperCase()); + Type methodType = Type.valueOf( + valuePart[0].toUpperCase(Locale.ROOT)); if ((ignoreTypes != null) && (ignoreTypes.contains(methodType))) { @@ -540,7 +542,7 @@ abstract class HttpAuthMethod { GSSManager gssManager = GSS_MANAGER_FACTORY.newInstance(conn .getURL()); String host = conn.getURL().getHost(); - String peerName = "HTTP@" + host.toLowerCase(); //$NON-NLS-1$ + String peerName = "HTTP@" + host.toLowerCase(Locale.ROOT); //$NON-NLS-1$ try { GSSName gssName = gssManager.createName(peerName, GSSName.NT_HOSTBASED_SERVICE); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java index bacab7e21e..8855f96567 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRC.java @@ -48,6 +48,7 @@ import java.io.FileReader; import java.io.IOException; import java.util.Collection; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; @@ -230,7 +231,7 @@ public class NetRC { matcher.reset(line); while (matcher.find()) { - String command = matcher.group().toLowerCase(); + String command = matcher.group().toLowerCase(Locale.ROOT); if (command.startsWith("#")) { //$NON-NLS-1$ matcher.reset(""); //$NON-NLS-1$ continue; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java index 81c5da3c78..87c9a50038 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ServiceMayNotContinueException.java @@ -45,8 +45,6 @@ package org.eclipse.jgit.transport; import java.io.IOException; -import javax.servlet.http.HttpServletResponse; - import org.eclipse.jgit.internal.JGitText; /** @@ -55,6 +53,7 @@ import org.eclipse.jgit.internal.JGitText; * @since 2.0 */ public class ServiceMayNotContinueException extends IOException { + private static final int FORBIDDEN = 403; private static final long serialVersionUID = 1L; private final int statusCode; @@ -63,7 +62,7 @@ public class ServiceMayNotContinueException extends IOException { /** Initialize with no message. */ public ServiceMayNotContinueException() { // Do not set a message. - statusCode = HttpServletResponse.SC_FORBIDDEN; + statusCode = FORBIDDEN; } /** @@ -73,7 +72,7 @@ public class ServiceMayNotContinueException extends IOException { */ public ServiceMayNotContinueException(String msg) { super(msg); - statusCode = HttpServletResponse.SC_FORBIDDEN; + statusCode = FORBIDDEN; } /** @@ -99,7 +98,7 @@ public class ServiceMayNotContinueException extends IOException { */ public ServiceMayNotContinueException(String msg, Throwable cause) { super(msg, cause); - statusCode = HttpServletResponse.SC_FORBIDDEN; + statusCode = FORBIDDEN; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java index da98e8c9ea..6bdf905e4f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java @@ -56,6 +56,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import org.eclipse.jgit.errors.NoRemoteRepositoryException; @@ -217,11 +218,12 @@ public class TransportGitSsh extends SshTransport implements PackTransport { public Process exec(String command, int timeout) throws TransportException { String ssh = SystemReader.getInstance().getenv("GIT_SSH"); //$NON-NLS-1$ - boolean putty = ssh.toLowerCase().contains("plink"); //$NON-NLS-1$ + boolean putty = ssh.toLowerCase(Locale.ROOT).contains("plink"); //$NON-NLS-1$ List<String> args = new ArrayList<String>(); args.add(ssh); - if (putty && !ssh.toLowerCase().contains("tortoiseplink")) //$NON-NLS-1$ + if (putty + && !ssh.toLowerCase(Locale.ROOT).contains("tortoiseplink")) //$NON-NLS-1$ args.add("-batch"); //$NON-NLS-1$ if (0 < getURI().getPort()) { args.add(putty ? "-P" : "-p"); //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java index 4c3fdd84f2..333e09d463 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java @@ -52,6 +52,7 @@ import java.security.GeneralSecurityException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.KeySpec; import java.text.MessageFormat; +import java.util.Locale; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -192,7 +193,7 @@ abstract class WalkEncryption { // Standard names are not case-sensitive. // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html - String cryptoName = cryptoAlg.toUpperCase(); + String cryptoName = cryptoAlg.toUpperCase(Locale.ROOT); if (!cryptoName.startsWith("PBE")) //$NON-NLS-1$ throw new GeneralSecurityException(JGitText.get().encryptionOnlyPBE); @@ -373,7 +374,7 @@ abstract class WalkEncryption { SecretKey keyBase = factory.generateSecret(keySpec); - String name = cipherAlgo.toUpperCase(); + String name = cipherAlgo.toUpperCase(Locale.ROOT); Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name); Matcher matcherTrans = Pattern.compile(REGEX_TRANS).matcher(name); if (matcherPBE.matches()) { @@ -506,7 +507,7 @@ abstract class WalkEncryption { JGitV1(String algo, String pass) throws GeneralSecurityException { super(wrap(algo, pass)); - String name = cipherAlgo.toUpperCase(); + String name = cipherAlgo.toUpperCase(Locale.ROOT); Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name); if (!matcherPBE.matches()) throw new GeneralSecurityException( diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java index ed5838a20e..c05570b851 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java @@ -7,6 +7,7 @@ package org.eclipse.jgit.util; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.Arrays; @@ -184,11 +185,7 @@ public class Base64 { e += 4; } - try { - return new String(outBuff, 0, e, UTF_8); - } catch (UnsupportedEncodingException uue) { - return new String(outBuff, 0, e); - } + return new String(outBuff, 0, e, StandardCharsets.UTF_8); } /** @@ -304,12 +301,7 @@ public class Base64 { * @return the decoded data */ public static byte[] decode(String s) { - byte[] bytes; - try { - bytes = s.getBytes(UTF_8); - } catch (UnsupportedEncodingException uee) { - bytes = s.getBytes(); - } + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); return decode(bytes, 0, bytes.length); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java index dcd7970cbc..2f570ee51c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -59,7 +59,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -1011,16 +1010,13 @@ public abstract class FS { IOException ioException = null; try { process = processBuilder.start(); - final Callable<Void> errorGobbler = new StreamGobbler( - process.getErrorStream(), errRedirect); - final Callable<Void> outputGobbler = new StreamGobbler( - process.getInputStream(), outRedirect); - executor.submit(errorGobbler); - executor.submit(outputGobbler); + executor.execute( + new StreamGobbler(process.getErrorStream(), errRedirect)); + executor.execute( + new StreamGobbler(process.getInputStream(), outRedirect)); OutputStream outputStream = process.getOutputStream(); if (inRedirect != null) { - new StreamGobbler(inRedirect, outputStream) - .call(); + new StreamGobbler(inRedirect, outputStream).copy(); } try { outputStream.close(); @@ -1336,7 +1332,7 @@ public abstract class FS { * streams. * </p> */ - private static class StreamGobbler implements Callable<Void> { + private static class StreamGobbler implements Runnable { private InputStream in; private OutputStream out; @@ -1346,7 +1342,15 @@ public abstract class FS { this.out = output; } - public Void call() throws IOException { + public void run() { + try { + copy(); + } catch (IOException e) { + // Do nothing on read failure; leave streams open. + } + } + + void copy() throws IOException { boolean writeFailure = false; byte buffer[] = new byte[4096]; int readBytes; @@ -1363,7 +1367,6 @@ public abstract class FS { } } } - return null; } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java index aa101f73f9..c04dfa9610 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -65,6 +65,7 @@ import java.text.Normalizer; import java.text.Normalizer.Form; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.regex.Pattern; import org.eclipse.jgit.internal.JGitText; @@ -542,7 +543,8 @@ public class FileUtils { public static boolean isStaleFileHandle(IOException ioe) { String msg = ioe.getMessage(); return msg != null - && msg.toLowerCase().matches("stale .*file .*handle"); //$NON-NLS-1$ + && msg.toLowerCase(Locale.ROOT) + .matches("stale .*file .*handle"); //$NON-NLS-1$ } /** |