diff --git a/WORKSPACE b/WORKSPACE index 40fe8b259..9fb3eedef 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -145,13 +145,13 @@ maven_jar( BYTE_BUDDY_VERSION = "1.9.0" maven_jar( - name = "byte_buddy", + name = "bytebuddy", artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, sha1 = "8cb0d5baae526c9df46ae17693bbba302640538b", ) maven_jar( - name = "byte_buddy_agent", + name = "bytebuddy-agent", artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, sha1 = "37b5703b4a6290be3fffc63ae9c6bcaaee0ff856", ) diff --git a/lib/BUILD b/lib/BUILD index 932d7dfa4..89279da8c 100644 --- a/lib/BUILD +++ b/lib/BUILD @@ -189,9 +189,13 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ + "@bytebuddy//jar", + "@bytebuddy-agent//jar", "@hamcrest-core//jar", "@hamcrest-library//jar", "@junit//jar", + "@mockito//jar", + "@objenesis//jar" ], ) @@ -200,8 +204,8 @@ java_library( testonly = 1, visibility = ["//visibility:public"], exports = [ - "@byte_buddy//jar", - "@byte_buddy_agent//jar", + "@bytebuddy//jar", + "@bytebuddy-agent//jar", "@mockito//jar", "@objenesis//jar", ], diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 32fc677fb..3aac85233 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -108,7 +108,6 @@ import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.transport.AbstractAdvertiseRefsHook; import org.eclipse.jgit.transport.AdvertiseRefsHook; import org.eclipse.jgit.transport.CredentialItem; @@ -125,7 +124,6 @@ import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.transport.http.HttpConnectionFactory; import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory; import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.HttpSupport; import org.eclipse.jgit.util.SystemReader; import org.hamcrest.Matchers; @@ -673,8 +671,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { @Test public void testInitialClone_RedirectMax() throws Exception { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = SystemReader.getInstance() + .getUserConfig(); userConfig.setInt("http", null, "maxRedirects", 4); userConfig.save(); initialClone_Redirect(4, 302); @@ -682,8 +680,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { @Test public void testInitialClone_RedirectTooOften() throws Exception { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = SystemReader.getInstance() + .getUserConfig(); userConfig.setInt("http", null, "maxRedirects", 3); userConfig.save(); @@ -721,8 +719,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { @Test public void testInitialClone_RedirectOnPostAllowed() throws Exception { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = SystemReader.getInstance() + .getUserConfig(); userConfig.setString("http", null, "followRedirects", "true"); userConfig.save(); @@ -782,8 +780,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { @Test public void testInitialClone_RedirectForbidden() throws Exception { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = SystemReader.getInstance() + .getUserConfig(); userConfig.setString("http", null, "followRedirects", "false"); userConfig.save(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index 98e1f8240..5c2cd6ac6 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java @@ -128,21 +128,25 @@ public abstract class LocalDiskRepositoryTestCase { if (!tmp.delete() || !tmp.mkdir()) throw new IOException("Cannot create " + tmp); - // measure timer resolution before the test to avoid time critical tests - // are affected by time needed for measurement + mockSystemReader = new MockSystemReader(); + SystemReader.setInstance(mockSystemReader); + + // Measure timer resolution before the test to avoid time critical tests + // are affected by time needed for measurement. + // The MockSystemReader must be configured first since we need to use + // the same one here FS.getFileStoreAttributes(tmp.toPath().getParent()); - mockSystemReader = new MockSystemReader(); - mockSystemReader.userGitConfig = new FileBasedConfig(new File(tmp, - "usergitconfig"), FS.DETECTED); + FileBasedConfig userConfig = new FileBasedConfig( + new File(tmp, "usergitconfig"), FS.DETECTED); // We have to set autoDetach to false for tests, because tests expect to be able // to clean up by recursively removing the repository, and background GC might be // in the middle of writing or deleting files, which would disrupt this. - mockSystemReader.userGitConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, + userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, ConfigConstants.CONFIG_KEY_AUTODETACH, false); - mockSystemReader.userGitConfig.save(); + userConfig.save(); + mockSystemReader.setUserGitConfig(userConfig); ceilTestDirectories(getCeilings()); - SystemReader.setInstance(mockSystemReader); author = new PersonIdent("J. Author", "jauthor@example.com"); committer = new PersonIdent("J. Committer", "jcommitter@example.com"); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index 89f2530a3..13c293228 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -60,6 +60,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; @@ -80,20 +81,56 @@ public class MockSystemReader extends SystemReader { // Do nothing } + @Override + public void save() throws IOException { + // Do nothing + } + @Override public boolean isOutdated() { return false; } + + @Override + public String toString() { + return "MockConfig"; + } } long now = 1250379778668L; // Sat Aug 15 20:12:58 GMT-03:30 2009 final Map values = new HashMap<>(); - FileBasedConfig userGitConfig; + private FileBasedConfig userGitConfig; FileBasedConfig systemGitConfig; + /** + * Set the user-level git config + * + * @param userGitConfig + * set another user-level git config + * @return the old user-level git config + */ + public FileBasedConfig setUserGitConfig(FileBasedConfig userGitConfig) { + FileBasedConfig old = this.userGitConfig; + this.userGitConfig = userGitConfig; + return old; + } + + /** + * Set the system-level git config + * + * @param systemGitConfig + * the new system-level git config + * @return the old system-level config + */ + public FileBasedConfig setSystemGitConfig(FileBasedConfig systemGitConfig) { + FileBasedConfig old = this.systemGitConfig; + this.systemGitConfig = systemGitConfig; + return old; + } + /** * Constructor for MockSystemReader */ @@ -156,6 +193,18 @@ public class MockSystemReader extends SystemReader { return systemGitConfig; } + @Override + public StoredConfig getUserConfig() + throws IOException, ConfigInvalidException { + return userGitConfig; + } + + @Override + public StoredConfig getSystemConfig() + throws IOException, ConfigInvalidException { + return systemGitConfig; + } + /** {@inheritDoc} */ @Override public String getHostname() { @@ -278,4 +327,10 @@ public class MockSystemReader extends SystemReader { e.printStackTrace(); } } + + @Override + public String toString() { + return "MockSystemReader"; + } + } diff --git a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java index ec44da4ca..e55c4c643 100644 --- a/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java +++ b/org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java @@ -74,6 +74,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.http.AppServer; import org.eclipse.jgit.lfs.errors.LfsException; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; @@ -85,6 +86,7 @@ import org.eclipse.jgit.lfs.test.LongObjectIdTestUtils; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; @@ -119,6 +121,7 @@ public abstract class LfsServerTest { @Before public void setup() throws Exception { + SystemReader.setInstance(new MockSystemReader()); tmp = Files.createTempDirectory("jgit_test_"); // measure timer resolution before the test to avoid time critical tests diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java index 028b19b2a..b7b0535ea 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/InstallBuiltinLfsCommand.java @@ -43,14 +43,12 @@ package org.eclipse.jgit.lfs; import java.io.IOException; -import java.text.MessageFormat; +import org.eclipse.jgit.api.errors.InvalidConfigurationException; import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.lfs.internal.LfsText; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.LfsFactory.LfsInstallCommand; import org.eclipse.jgit.util.SystemReader; @@ -70,12 +68,28 @@ public class InstallBuiltinLfsCommand implements LfsInstallCommand { private Repository repository; - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @throws IOException + * if an I/O error occurs while accessing a git config or + * executing {@code git lfs install} in an external process + * @throws InvalidConfigurationException + * if a git configuration is invalid + * @throws InterruptedException + * if the current thread is interrupted while waiting for the + * {@code git lfs install} executed in an external process + */ @Override - public Void call() throws Exception { + public Void call() throws IOException, InvalidConfigurationException, + InterruptedException { StoredConfig cfg = null; if (repository == null) { - cfg = loadUserConfig(); + try { + cfg = SystemReader.getInstance().getUserConfig(); + } catch (ConfigInvalidException e) { + throw new InvalidConfigurationException(e.getMessage(), e); + } } else { cfg = repository.getConfig(); } @@ -116,19 +130,4 @@ public class InstallBuiltinLfsCommand implements LfsInstallCommand { return this; } - private StoredConfig loadUserConfig() throws IOException { - FileBasedConfig c = SystemReader.getInstance().openUserConfig(null, - FS.DETECTED); - try { - c.load(); - } catch (ConfigInvalidException e1) { - throw new IOException(MessageFormat - .format(LfsText.get().userConfigInvalid, c.getFile() - .getAbsolutePath(), e1), - e1); - } - - return c; - } - } diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target index f5eca33ac..5a9714f2e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target index bdbc75a9b..c00aebd4f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target index e98c89e4d..a79aeb016 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12-staging.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index 308f9f9f8..082f5d4b4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index eeae21904..aff5ce6a2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index 4ada70f91..4995bae26 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target index 97c9de369..debd6164a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd index e2f975ebd..db674493b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20190602212107-2019-06.tpd @@ -62,3 +62,4 @@ location "https://download.eclipse.org/tools/orbit/downloads/drops/R201906022121 org.apache.sshd.sftp [2.2.0.v20190425-2127,2.2.0.v20190425-2127] org.apache.sshd.sftp.source [2.2.0.v20190425-2127,2.2.0.v20190425-2127] } + diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java index 0ce645139..1ce86d15e 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java @@ -43,14 +43,14 @@ package org.eclipse.jgit.pgm; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.CLIRepositoryTestCase; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; import org.junit.Before; import org.junit.Test; @@ -65,6 +65,7 @@ public class ConfigTest extends CLIRepositoryTestCase { } } + @SuppressWarnings("boxing") @Test public void testListConfig() throws Exception { boolean isWindows = SystemReader.getInstance().getProperty("os.name") @@ -73,19 +74,31 @@ public class ConfigTest extends CLIRepositoryTestCase { .equals("Mac OS X"); String[] output = execute("git config --list"); - List expect = new ArrayList<>(); - expect.add("gc.autoDetach=false"); - expect.add("core.filemode=" + !isWindows); - expect.add("core.logallrefupdates=true"); - if (isMac) - expect.add("core.precomposeunicode=true"); - expect.add("core.repositoryformatversion=0"); - if (!FS.DETECTED.supportsSymlinks()) - expect.add("core.symlinks=false"); - expect.add(""); // ends with LF (last line empty) - assertEquals("expected default configuration", - Arrays.asList(expect.toArray()).toString(), - Arrays.asList(output).toString()); + + Map options = parseOptions(output); + + assertEquals(!isWindows, Boolean.valueOf(options.get("core.filemode"))); + assertTrue((Boolean.valueOf(options.get("core.logallrefupdates")))); + if (isMac) { + assertTrue( + (Boolean.valueOf(options.get("core.precomposeunicode")))); + } + assertEquals(Integer.valueOf(0), + Integer.valueOf(options.get("core.repositoryformatversion"))); + } + + private Map parseOptions(String[] output) { + Map options = new HashMap<>(); + Arrays.stream(output).forEachOrdered(s -> { + int p = s.indexOf('='); + if (p == -1) { + return; + } + String key = s.substring(0, p); + String value = s.substring(p + 1); + options.put(key, value); + }); + return options; } } diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index fc8c53c18..f90a28030 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD @@ -51,6 +51,7 @@ java_library( deps = [ "//lib:jsch", "//lib:junit", + "//lib:slf4j-simple", "//lib:mockito", "//org.eclipse.jgit:jgit", "//org.eclipse.jgit.junit:junit", diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 53b79b0cb..e36f5e419 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -10,7 +10,7 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.54,0.2.0)", - net.bytebuddy.dynamic.loading;version="[1.7.0,2.0.0)", + net.bytebuddy.dynamic.loading;version="[1.9.0,2.0.0)", org.apache.commons.compress.archivers;version="[1.15.0,2.0)", org.apache.commons.compress.archivers.tar;version="[1.15.0,2.0)", org.apache.commons.compress.archivers.zip;version="[1.15.0,2.0)", @@ -74,10 +74,10 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", org.junit.rules;version="[4.12,5.0.0)", org.junit.runner;version="[4.12,5.0.0)", org.junit.runners;version="[4.12,5.0.0)", - org.mockito;version="[2.13.0,3.0.0)", - org.mockito.invocation;version="[2.13.0,3.0.0)", - org.mockito.junit;version="[2.13.0,3.0.0)", - org.mockito.stubbing;version="[2.13.0,3.0.0)", + org.mockito;version="[2.23.0,3.0.0)", + org.mockito.invocation;version="[2.23.0,3.0.0)", + org.mockito.junit;version="[2.23.0,3.0.0)", + org.mockito.stubbing;version="[2.23.0,3.0.0)", org.objenesis;version="[2.6.0,3.0.0)", org.slf4j;version="[1.7.0,2.0.0)", org.tukaani.xz;version="[1.6.0,2.0)" diff --git a/org.eclipse.jgit.test/tst-rsrc/log4j.properties b/org.eclipse.jgit.test/tst-rsrc/log4j.properties index ee1ac3515..856a731ab 100644 --- a/org.eclipse.jgit.test/tst-rsrc/log4j.properties +++ b/org.eclipse.jgit.test/tst-rsrc/log4j.properties @@ -7,8 +7,8 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -#log4j.appender.fileLogger.bufferedIO = true -#log4j.appender.fileLogger.bufferSize = 4096 +log4j.appender.fileLogger.bufferedIO = true +log4j.appender.fileLogger.bufferSize = 4096 #log4j.logger.org.eclipse.jgit.util.FS = DEBUG #log4j.logger.org.eclipse.jgit.internal.storage.file.FileSnapshot = DEBUG diff --git a/org.eclipse.jgit.test/tst-rsrc/simplelogger.properties b/org.eclipse.jgit.test/tst-rsrc/simplelogger.properties new file mode 100644 index 000000000..011b2f8bb --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/simplelogger.properties @@ -0,0 +1,9 @@ +org.slf4j.simpleLogger.logFile = System.err +org.slf4j.simpleLogger.cacheOutputStream = true +org.slf4j.simpleLogger.defaultLogLevel = info +org.slf4j.simpleLogger.showDateTime = true +org.slf4j.simpleLogger.dateTimeFormat = HH:mm:ss.SSSXXX +org.slf4j.simpleLogger.showThreadName = true + +#org.slf4j.simpleLogger.log.org.eclipse.jgit.util.FS = debug +#org.slf4j.simpleLogger.log.org.eclipse.jgit.internal.storage.file.FileSnapshot = debug diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 74d13883e..2270a6a8b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -68,9 +68,9 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.submodule.SubmoduleStatus; import org.eclipse.jgit.submodule.SubmoduleStatusType; import org.eclipse.jgit.submodule.SubmoduleWalk; @@ -680,8 +680,8 @@ public class CloneCommandTest extends RepositoryTestCase { ConfigConstants.CONFIG_BRANCH_SECTION, "test", ConfigConstants.CONFIG_KEY_REBASE, null)); - FileBasedConfig userConfig = SystemReader.getInstance().openUserConfig( - null, git.getRepository().getFS()); + StoredConfig userConfig = SystemReader.getInstance() + .getUserConfig(); userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE, ConfigConstants.CONFIG_KEY_ALWAYS); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java index 83181eea2..2a2a6ba1b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java @@ -1295,9 +1295,15 @@ public class CommitOnlyTest extends RepositoryTestCase { try { final Repository repo = git.getRepository(); final ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}"); + if (headId == null) { + return ""; + } try (RevWalk rw = new RevWalk(repo)) { final TreeWalk tw = TreeWalk.forPath(repo, path, rw.parseTree(headId)); + if (tw == null) { + return ""; + } return new String(tw.getObjectReader().open(tw.getObjectId(0)) .getBytes(), UTF_8); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java index 6fa35d64b..35f4fcba9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileSnapshotTest.java @@ -62,6 +62,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.concurrent.TimeUnit; +import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS.FileStoreAttributes; import org.eclipse.jgit.util.FileUtils; @@ -84,6 +85,7 @@ public class FileSnapshotTest { @Before public void setUp() throws Exception { + SystemReader.setInstance(new MockSystemReader()); trash = Files.createTempDirectory("tmp_"); // measure timer resolution before the test to avoid time critical tests // are affected by time needed for measurement diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/LocalDiskRefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/LocalDiskRefTreeDatabaseTest.java index d5a07e02f..cafec04f7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/LocalDiskRefTreeDatabaseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/LocalDiskRefTreeDatabaseTest.java @@ -80,6 +80,7 @@ public class LocalDiskRefTreeDatabaseTest extends LocalDiskRepositoryTestCase { @Override @Before public void setUp() throws Exception { + super.setUp(); FileRepository init = createWorkRepository(); FileBasedConfig cfg = init.getConfig(); cfg.setInt("core", null, "repositoryformatversion", 1); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java index 43648206f..5100d258d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java @@ -56,9 +56,11 @@ import java.nio.file.StandardOpenOption; import java.util.StringTokenizer; import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -90,6 +92,7 @@ public class FileBasedConfigTest { @Before public void setUp() throws Exception { + SystemReader.setInstance(new MockSystemReader()); trash = Files.createTempDirectory("tmp_"); FS.getFileStoreAttributes(trash.getParent()); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java index 99d435100..89a2fc44c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java @@ -67,6 +67,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.errors.CommandFailedException; +import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.RepositoryCache; import org.junit.After; @@ -79,6 +80,7 @@ public class FSTest { @Before public void setUp() throws Exception { + SystemReader.setInstance(new MockSystemReader()); trash = File.createTempFile("tmp_", ""); trash.delete(); assertTrue("mkdir " + trash, trash.mkdir()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java new file mode 100644 index 000000000..87349a25a --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FS_POSIXTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2019, Vishal Devgire + * 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.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.jgit.junit.MockSystemReader; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FS_POSIXTest { + private SystemReader originalSystemReaderInstance; + + private FileBasedConfig systemConfig; + + private FileBasedConfig userConfig; + + private Path tmp; + + @Before + public void setUp() throws Exception { + tmp = Files.createTempDirectory("jgit_test_"); + MockSystemReader mockSystemReader = new MockSystemReader(); + SystemReader.setInstance(mockSystemReader); + + // Measure timer resolution before the test to avoid time critical tests + // are affected by time needed for measurement. + // The MockSystemReader must be configured first since we need to use + // the same one here + FS.getFileStoreAttributes(tmp.getParent()); + systemConfig = new FileBasedConfig( + new File(tmp.toFile(), "systemgitconfig"), FS.DETECTED); + userConfig = new FileBasedConfig(systemConfig, + new File(tmp.toFile(), "usergitconfig"), FS.DETECTED); + // We have to set autoDetach to false for tests, because tests expect to + // be able to clean up by recursively removing the repository, and + // background GC might be in the middle of writing or deleting files, + // which would disrupt this. + userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTODETACH, false); + userConfig.save(); + mockSystemReader.setSystemGitConfig(systemConfig); + mockSystemReader.setUserGitConfig(userConfig); + + originalSystemReaderInstance = SystemReader.getInstance(); + SystemReader.setInstance(mockSystemReader); + } + + @After + public void tearDown() throws IOException { + SystemReader.setInstance(originalSystemReaderInstance); + FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE | FileUtils.RETRY); + } + + @Test + public void supportsAtomicCreateNewFile_shouldReturnSupportedAsDefault() { + assertTrue(new FS_POSIX().supportsAtomicCreateNewFile()); + } + + @Test + public void supportsAtomicCreateNewFile_shouldReturnTrueIfFlagIsSetInUserConfig() { + setAtomicCreateCreationFlag(userConfig, "true"); + assertTrue(new FS_POSIX().supportsAtomicCreateNewFile()); + } + + @Test + public void supportsAtomicCreateNewFile_shouldReturnTrueIfFlagIsSetInSystemConfig() { + setAtomicCreateCreationFlag(systemConfig, "true"); + assertTrue(new FS_POSIX().supportsAtomicCreateNewFile()); + } + + @Test + public void supportsAtomicCreateNewFile_shouldReturnFalseIfFlagUnsetInUserConfig() { + setAtomicCreateCreationFlag(userConfig, "false"); + assertFalse(new FS_POSIX().supportsAtomicCreateNewFile()); + } + + @Test + public void supportsAtomicCreateNewFile_shouldReturnFalseIfFlagUnsetInSystemConfig() { + setAtomicCreateCreationFlag(systemConfig, "false"); + assertFalse(new FS_POSIX().supportsAtomicCreateNewFile()); + } + + private void setAtomicCreateCreationFlag(FileBasedConfig config, + String value) { + config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION, value); + } +} diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index 3a5dd11f5..17054cd88 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -49,14 +49,6 @@ - - - - - - - - @@ -158,4 +150,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 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 e26163e24..0d8f83ed6 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -17,6 +17,7 @@ applyingCommit=Applying {0} archiveFormatAlreadyAbsent=Archive format already absent: {0} archiveFormatAlreadyRegistered=Archive format already registered with different implementation: {0} argumentIsNotAValidCommentString=Invalid comment: {0} +assumeAtomicCreateNewFile=Reading option "core.supportsAtomicFileCreation" failed, fallback to default assuming atomic file creation is supported atLeastOnePathIsRequired=At least one path is required. atLeastOnePatternIsRequired=At least one pattern is required. atLeastTwoFiltersNeeded=At least two filters needed. @@ -311,6 +312,7 @@ expectedPktLineWithService=expected pkt-line with ''# service=-'', got ''{0}'' expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1} expectedReportForRefNotReceived={0}: expected report for ref {1} not received failedAtomicFileCreation=Atomic file creation failed, number of hard links to file {0} was not 2 but {1} +failedCreateLockFile=Creating lock file {} failed failedToDetermineFilterDefinition=An exception occurred while determining filter definitions failedUpdatingRefs=failed updating refs failureDueToOneOfTheFollowing=Failure due to one of the following: @@ -446,6 +448,7 @@ localRefIsMissingObjects=Local ref {0} is missing object(s). localRepository=local repository lockCountMustBeGreaterOrEqual1=lockCount must be >= 1 lockError=lock error: {0} +lockFailedRetry=locking {0} failed after {1} retries lockOnNotClosed=Lock on {0} not closed. lockOnNotHeld=Lock on {0} not held. malformedpersonIdentString=Malformed PersonIdent string (no < was found): {0} @@ -580,6 +583,7 @@ pushNotPermitted=push not permitted pushOptionsNotSupported=Push options not supported; received {0} rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry readConfigFailed=Reading config file ''{0}'' failed +readFileStoreAttributesFailed=Reading FileStore attributes from user config failed readerIsRequired=Reader is required readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0} readLastModifiedFailed=Reading lastModified of {0} failed @@ -638,6 +642,7 @@ s3ActionDeletion=Deletion s3ActionReading=Reading s3ActionWriting=Writing searchForReachableBranches=Finding reachable branches +saveFileStoreAttributesFailed=Saving measured FileStore attributes to user config failed searchForReuse=Finding sources searchForSizes=Getting sizes secondsAgo={0} seconds ago @@ -797,7 +802,7 @@ uriNotConfigured=Submodule URI not configured uriNotFound={0} not found uriNotFoundWithMessage={0} not found: {1} URINotSupported=URI not supported: {0} -userConfigFileInvalid=User config file {0} invalid {1} +userConfigInvalid=Git config in the user's home directory {0} is invalid {1} validatingGitModules=Validating .gitmodules files walkFailure=Walk failure. wantNoSpaceWithCapabilities=No space between oid and first capability in first want line 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 320036c52..48f6778f0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -78,6 +78,7 @@ public class JGitText extends TranslationBundle { /***/ public String archiveFormatAlreadyAbsent; /***/ public String archiveFormatAlreadyRegistered; /***/ public String argumentIsNotAValidCommentString; + /***/ public String assumeAtomicCreateNewFile; /***/ public String atLeastOnePathIsRequired; /***/ public String atLeastOnePatternIsRequired; /***/ public String atLeastTwoFiltersNeeded; @@ -372,6 +373,7 @@ public class JGitText extends TranslationBundle { /***/ public String expectedReceivedContentType; /***/ public String expectedReportForRefNotReceived; /***/ public String failedAtomicFileCreation; + /***/ public String failedCreateLockFile; /***/ public String failedToDetermineFilterDefinition; /***/ public String failedUpdatingRefs; /***/ public String failureDueToOneOfTheFollowing; @@ -507,6 +509,7 @@ public class JGitText extends TranslationBundle { /***/ public String localRepository; /***/ public String lockCountMustBeGreaterOrEqual1; /***/ public String lockError; + /***/ public String lockFailedRetry; /***/ public String lockOnNotClosed; /***/ public String lockOnNotHeld; /***/ public String malformedpersonIdentString; @@ -641,6 +644,7 @@ public class JGitText extends TranslationBundle { /***/ public String pushOptionsNotSupported; /***/ public String rawLogMessageDoesNotParseAsLogEntry; /***/ public String readConfigFailed; + /***/ public String readFileStoreAttributesFailed; /***/ public String readerIsRequired; /***/ public String readingObjectsFromLocalRepositoryFailed; /***/ public String readLastModifiedFailed; @@ -698,6 +702,7 @@ public class JGitText extends TranslationBundle { /***/ public String s3ActionDeletion; /***/ public String s3ActionReading; /***/ public String s3ActionWriting; + /***/ public String saveFileStoreAttributesFailed; /***/ public String searchForReachableBranches; /***/ public String searchForReuse; /***/ public String searchForSizes; @@ -857,7 +862,7 @@ public class JGitText extends TranslationBundle { /***/ public String uriNotFound; /***/ public String uriNotFoundWithMessage; /***/ public String URINotSupported; - /***/ public String userConfigFileInvalid; + /***/ public String userConfigInvalid; /***/ public String validatingGitModules; /***/ public String walkFailure; /***/ public String wantNoSpaceWithCapabilities; 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 90772970a..4f5f8a613 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 @@ -79,15 +79,17 @@ import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.storage.pack.PackConfig; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.SystemReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Represents a Git repository. A repository holds all objects and refs used for @@ -114,10 +116,10 @@ import org.eclipse.jgit.util.SystemReader; * This implementation only handles a subtly undocumented subset of git features. */ public class FileRepository extends Repository { + private static final Logger LOG = LoggerFactory + .getLogger(FileRepository.class); private static final String UNNAMED = "Unnamed repository; edit this file to name it for gitweb."; //$NON-NLS-1$ - private final FileBasedConfig systemConfig; - private final FileBasedConfig userConfig; private final FileBasedConfig repoConfig; private final RefDatabase refs; private final ObjectDirectory objectDatabase; @@ -176,32 +178,16 @@ public class FileRepository extends Repository { */ public FileRepository(BaseRepositoryBuilder options) throws IOException { super(options); - - if (StringUtils.isEmptyOrNull(SystemReader.getInstance().getenv( - Constants.GIT_CONFIG_NOSYSTEM_KEY))) - systemConfig = SystemReader.getInstance().openSystemConfig(null, - getFS()); - else - systemConfig = new FileBasedConfig(null, FS.DETECTED) { - @Override - public void load() { - // empty, do not load - } - - @Override - public boolean isOutdated() { - // regular class would bomb here - return false; - } - }; - userConfig = SystemReader.getInstance().openUserConfig(systemConfig, - getFS()); + StoredConfig userConfig = null; + try { + userConfig = SystemReader.getInstance().getUserConfig(); + } catch (ConfigInvalidException e) { + LOG.error(e.getMessage(), e); + throw new IOException(e.getMessage(), e); + } repoConfig = new FileBasedConfig(userConfig, getFS().resolve( getDirectory(), Constants.CONFIG), getFS()); - - loadSystemConfig(); - loadUserConfig(); loadRepoConfig(); repoConfig.addChangeListener(this::fireEvent); @@ -240,28 +226,6 @@ public class FileRepository extends Repository { } } - private void loadSystemConfig() throws IOException { - try { - systemConfig.load(); - } catch (ConfigInvalidException e) { - throw new IOException(MessageFormat.format(JGitText - .get().systemConfigFileInvalid, systemConfig.getFile() - .getAbsolutePath(), - e), e); - } - } - - private void loadUserConfig() throws IOException { - try { - userConfig.load(); - } catch (ConfigInvalidException e) { - throw new IOException(MessageFormat.format(JGitText - .get().userConfigFileInvalid, userConfig.getFile() - .getAbsolutePath(), - e), e); - } - } - private void loadRepoConfig() throws IOException { try { repoConfig.load(); @@ -402,26 +366,13 @@ public class FileRepository extends Repository { /** {@inheritDoc} */ @Override public FileBasedConfig getConfig() { - if (systemConfig.isOutdated()) { - try { - loadSystemConfig(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - if (userConfig.isOutdated()) { - try { - loadUserConfig(); - } catch (IOException e) { - throw new RuntimeException(e); + try { + SystemReader.getInstance().getUserConfig(); + if (repoConfig.isOutdated()) { + loadRepoConfig(); } - } - if (repoConfig.isOutdated()) { - try { - loadRepoConfig(); - } catch (IOException e) { - throw new RuntimeException(e); - } + } catch (IOException | ConfigInvalidException e) { + throw new RuntimeException(e); } return repoConfig; } 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 fa8732d14..6af41256d 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 @@ -161,7 +161,12 @@ public class LockFile { */ public boolean lock() throws IOException { FileUtils.mkdirs(lck.getParentFile(), true); - token = FS.DETECTED.createNewFileAtomic(lck); + try { + token = FS.DETECTED.createNewFileAtomic(lck); + } catch (IOException e) { + LOG.error(JGitText.get().failedCreateLockFile, lck, e); + throw e; + } if (token.isCreated()) { haveLck = true; try { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java index 9df593375..74c712c46 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java @@ -135,6 +135,9 @@ public class ObjectIdOwnerMap */ @SuppressWarnings("unchecked") public V get(AnyObjectId toFind) { + if (toFind == null) { + return null; + } int h = toFind.w1; V obj = directory[h & mask][h >>> SEGMENT_SHIFT]; for (; obj != null; obj = (V) obj.next) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java index c0fcd4161..ebbb3a484 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RebaseTodoFile.java @@ -137,11 +137,13 @@ public class RebaseTodoFile { if (skip != -1) { // try to parse the line as non-comment line = parseLine(buf, skip, lineEnd); - // successfully parsed as non-comment line - // mark this line as a comment explicitly - line.setAction(Action.COMMENT); - // use the read line as comment string - line.setComment(commentString); + if (line != null) { + // successfully parsed as non-comment line + // mark this line as a comment explicitly + line.setAction(Action.COMMENT); + // use the read line as comment string + line.setComment(commentString); + } } } catch (Exception e) { // parsing as non-comment line failed diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java index 10b00b77a..5bb8153a5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java @@ -148,38 +148,14 @@ public class FileBasedConfig extends StoredConfig { */ @Override public void load() throws IOException, ConfigInvalidException { - load(true); - } - - /** - * Load the configuration as a Git text style configuration file. - *

- * If the file does not exist, this configuration is cleared, and thus - * behaves the same as though the file exists, but is empty. - * - * @param useFileSnapshotWithConfig - * if {@code true} use the FileSnapshot with config, otherwise - * use it without config - * @throws IOException - * if IO failed - * @throws ConfigInvalidException - * if config is invalid - * @since 5.1.9 - */ - public void load(boolean useFileSnapshotWithConfig) - throws IOException, ConfigInvalidException { final int maxRetries = 5; int retryDelayMillis = 20; int retries = 0; while (true) { final FileSnapshot oldSnapshot = snapshot; final FileSnapshot newSnapshot; - if (useFileSnapshotWithConfig) { - newSnapshot = FileSnapshot.save(getFile()); - } else { - // don't use config in this snapshot to avoid endless recursion - newSnapshot = FileSnapshot.saveNoConfig(getFile()); - } + // don't use config in this snapshot to avoid endless recursion + newSnapshot = FileSnapshot.saveNoConfig(getFile()); try { final byte[] in = IO.readFully(getFile()); final ObjectId newHash = hash(in); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java index 36ff2836a..be7111d90 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpConfig.java @@ -53,8 +53,7 @@ import java.util.function.Supplier; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.storage.file.FileBasedConfig; -import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.SystemReader; import org.slf4j.Logger; @@ -274,14 +273,12 @@ public class HttpConfig { * to get the configuration values for */ public HttpConfig(URIish uri) { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = null; try { - userConfig.load(); + userConfig = SystemReader.getInstance().getUserConfig(); } catch (IOException | ConfigInvalidException e) { // Log it and then work with default values. - LOG.error(MessageFormat.format(JGitText.get().userConfigFileInvalid, - userConfig.getFile().getAbsolutePath(), e)); + LOG.error(e.getMessage(), e); init(new Config(), uri); return; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java index c523cbf05..3029327c5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -122,11 +122,9 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.lib.SymbolicRef; -import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.transport.HttpAuthMethod.Type; import org.eclipse.jgit.transport.HttpConfig.HttpRedirectMode; import org.eclipse.jgit.transport.http.HttpConnection; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.HttpSupport; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; @@ -794,15 +792,13 @@ public class TransportHttp extends HttpTransport implements WalkTransport, } private void updateSslVerifyUser(boolean value) { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig = null; try { - userConfig.load(); + userConfig = SystemReader.getInstance().getUserConfig(); updateSslVerify(userConfig, value); } catch (IOException | ConfigInvalidException e) { // Log it, but otherwise ignore here. - LOG.error(MessageFormat.format(JGitText.get().userConfigFileInvalid, - userConfig.getFile().getAbsolutePath(), e)); + LOG.error(e.getMessage(), e); } } 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 421bf8149..90305013f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -100,7 +100,7 @@ import org.eclipse.jgit.internal.storage.file.FileSnapshot; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; import org.eclipse.jgit.treewalk.FileTreeIterator.FileModeStrategy; import org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry; @@ -510,18 +510,12 @@ public abstract class FS { private static Optional readFromConfig( FileStore s) { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig; try { - userConfig.load(false); - } catch (IOException e) { - LOG.error(MessageFormat.format(JGitText.get().readConfigFailed, - userConfig.getFile().getAbsolutePath()), e); - } catch (ConfigInvalidException e) { - LOG.error(MessageFormat.format( - JGitText.get().repositoryConfigFileInvalid, - userConfig.getFile().getAbsolutePath(), - e.getMessage())); + userConfig = SystemReader.getInstance().getUserConfig(); + } catch (IOException | ConfigInvalidException e) { + LOG.error(JGitText.get().readFileStoreAttributesFailed, e); + return Optional.empty(); } String key = getConfigKey(s); Duration resolution = Duration.ofNanos(userConfig.getTimeUnit( @@ -544,8 +538,13 @@ public abstract class FS { private static void saveToConfig(FileStore s, FileStoreAttributes c) { - FileBasedConfig userConfig = SystemReader.getInstance() - .openUserConfig(null, FS.DETECTED); + StoredConfig userConfig; + try { + userConfig = SystemReader.getInstance().getUserConfig(); + } catch (IOException | ConfigInvalidException e) { + LOG.error(JGitText.get().saveFileStoreAttributesFailed, e); + return; + } long resolution = c.getFsTimestampResolution().toNanos(); TimeUnit resolutionUnit = getUnit(resolution); long resolutionValue = resolutionUnit.convert(resolution, @@ -562,7 +561,7 @@ public abstract class FS { String key = getConfigKey(s); while (!succeeded && retries < max_retries) { try { - userConfig.load(false); + userConfig.load(); userConfig.setString( ConfigConstants.CONFIG_FILESYSTEM_SECTION, key, ConfigConstants.CONFIG_KEY_TIMESTAMP_RESOLUTION, @@ -580,22 +579,30 @@ public abstract class FS { } catch (LockFailedException e) { // race with another thread, wait a bit and try again try { - LOG.warn(MessageFormat.format(JGitText.get().cannotLock, - userConfig.getFile().getAbsolutePath())); retries++; - Thread.sleep(20); + if (retries < max_retries) { + Thread.sleep(100); + LOG.debug("locking {} failed, retries {}/{}", //$NON-NLS-1$ + userConfig, Integer.valueOf(retries), + Integer.valueOf(max_retries)); + } else { + LOG.warn(MessageFormat.format( + JGitText.get().lockFailedRetry, userConfig, + Integer.valueOf(retries))); + } } catch (InterruptedException e1) { - Thread.interrupted(); + Thread.currentThread().interrupt(); + break; } } catch (IOException e) { LOG.error(MessageFormat.format( - JGitText.get().cannotSaveConfig, - userConfig.getFile().getAbsolutePath()), e); + JGitText.get().cannotSaveConfig, userConfig), e); + break; } catch (ConfigInvalidException e) { LOG.error(MessageFormat.format( JGitText.get().repositoryConfigFileInvalid, - userConfig.getFile().getAbsolutePath(), - e.getMessage())); + userConfig, e.getMessage())); + break; } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java index 6ec50c24e..a485389a9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java @@ -42,15 +42,20 @@ */ package org.eclipse.jgit.util; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.charset.Charset; +import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileStore; import java.nio.file.FileSystemException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermission; @@ -69,10 +74,9 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.errors.CommandFailedException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.lib.StoredConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +93,7 @@ public class FS_POSIX extends FS { private static final Map CAN_HARD_LINK = new ConcurrentHashMap<>(); - private volatile AtomicFileCreation supportsAtomicCreateNewFile = AtomicFileCreation.UNDEFINED; + private volatile AtomicFileCreation supportsAtomicFileCreation = AtomicFileCreation.UNDEFINED; private enum AtomicFileCreation { SUPPORTED, NOT_SUPPORTED, UNDEFINED @@ -114,37 +118,6 @@ public class FS_POSIX extends FS { } } - private void determineAtomicFileCreationSupport() { - // @TODO: enhance SystemReader to support this without copying code - AtomicFileCreation ret = getAtomicFileCreationSupportOption( - SystemReader.getInstance().openUserConfig(null, this)); - if (ret == AtomicFileCreation.UNDEFINED - && StringUtils.isEmptyOrNull(SystemReader.getInstance() - .getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) { - ret = getAtomicFileCreationSupportOption( - SystemReader.getInstance().openSystemConfig(null, this)); - } - supportsAtomicCreateNewFile = ret; - } - - private AtomicFileCreation getAtomicFileCreationSupportOption( - FileBasedConfig config) { - try { - config.load(); - String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION, - null, - ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION); - if (value == null) { - return AtomicFileCreation.UNDEFINED; - } - return StringUtils.toBoolean(value) - ? AtomicFileCreation.SUPPORTED - : AtomicFileCreation.NOT_SUPPORTED; - } catch (IOException | ConfigInvalidException e) { - return AtomicFileCreation.SUPPORTED; - } - } - /** {@inheritDoc} */ @Override public FS newInstance() { @@ -359,10 +332,24 @@ public class FS_POSIX extends FS { /** {@inheritDoc} */ @Override public boolean supportsAtomicCreateNewFile() { - if (supportsAtomicCreateNewFile == AtomicFileCreation.UNDEFINED) { - determineAtomicFileCreationSupport(); + if (supportsAtomicFileCreation == AtomicFileCreation.UNDEFINED) { + try { + StoredConfig config = SystemReader.getInstance().getUserConfig(); + String value = config.getString(CONFIG_CORE_SECTION, null, + CONFIG_KEY_SUPPORTSATOMICFILECREATION); + if (value != null) { + supportsAtomicFileCreation = StringUtils.toBoolean(value) + ? AtomicFileCreation.SUPPORTED + : AtomicFileCreation.NOT_SUPPORTED; + } else { + supportsAtomicFileCreation = AtomicFileCreation.SUPPORTED; + } + } catch (IOException | ConfigInvalidException e) { + LOG.warn(JGitText.get().assumeAtomicCreateNewFile, e); + supportsAtomicFileCreation = AtomicFileCreation.SUPPORTED; + } } - return supportsAtomicCreateNewFile == AtomicFileCreation.SUPPORTED; + return supportsAtomicFileCreation == AtomicFileCreation.SUPPORTED; } @Override @@ -438,7 +425,7 @@ public class FS_POSIX extends FS { * An implementation of the File#createNewFile() semantics which can create * a unique file atomically also on NFS. If the config option * {@code core.supportsAtomicCreateNewFile = true} (which is the default) - * then simply File#createNewFile() is called. + * then simply Files#createFile() is called. * * But if {@code core.supportsAtomicCreateNewFile = false} then after * successful creation of the lock file a hard link to that lock file is @@ -459,14 +446,17 @@ public class FS_POSIX extends FS { */ @Override public LockToken createNewFileAtomic(File file) throws IOException { - if (!file.createNewFile()) { + Path path; + try { + path = file.toPath(); + Files.createFile(path); + } catch (FileAlreadyExistsException | InvalidPathException e) { return token(false, null); } if (supportsAtomicCreateNewFile()) { return token(true, null); } Path link = null; - Path path = file.toPath(); FileStore store = null; try { store = Files.getFileStore(path); 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 4a773b05b..4d791e470 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -56,6 +56,7 @@ import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; @@ -697,9 +698,14 @@ public class FileUtils { try { return Files.getLastModifiedTime(path, LinkOption.NOFOLLOW_LINKS) .toInstant(); + } catch (NoSuchFileException e) { + LOG.debug( + "Cannot read lastModifiedInstant since path {} does not exist", //$NON-NLS-1$ + path); + return Instant.EPOCH; } catch (IOException e) { LOG.error(MessageFormat - .format(JGitText.get().readLastModifiedFailed, path)); + .format(JGitText.get().readLastModifiedFailed, path), e); return Instant.ofEpochMilli(path.toFile().lastModified()); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java index d04f087d5..8431196cb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -47,6 +47,7 @@ package org.eclipse.jgit.util; import java.io.File; +import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.AccessController; @@ -56,12 +57,17 @@ import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; +import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectChecker; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.util.time.MonotonicClock; import org.eclipse.jgit.util.time.MonotonicSystemClock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Interface to read values from the system. @@ -72,6 +78,10 @@ import org.eclipse.jgit.util.time.MonotonicSystemClock; *

*/ public abstract class SystemReader { + + private final static Logger LOG = LoggerFactory + .getLogger(SystemReader.class); + private static final SystemReader DEFAULT; private static Boolean isMacOS; @@ -87,6 +97,10 @@ public abstract class SystemReader { private static class Default extends SystemReader { private volatile String hostname; + private volatile FileBasedConfig systemConfig; + + private volatile FileBasedConfig userConfig; + @Override public String getenv(String variable) { return System.getenv(variable); @@ -99,28 +113,69 @@ public abstract class SystemReader { @Override public FileBasedConfig openSystemConfig(Config parent, FS fs) { - File configFile = fs.getGitSystemConfig(); - if (configFile == null) { - return new FileBasedConfig(parent, null, fs) { - @Override - public void load() { - // empty, do not load - } - - @Override - public boolean isOutdated() { - // regular class would bomb here - return false; - } - }; + if (systemConfig == null) { + systemConfig = createSystemConfig(parent, fs); } - return new FileBasedConfig(parent, configFile, fs); + return systemConfig; + } + + protected FileBasedConfig createSystemConfig(Config parent, FS fs) { + if (StringUtils.isEmptyOrNull(getenv(Constants.GIT_CONFIG_NOSYSTEM_KEY))) { + File configFile = fs.getGitSystemConfig(); + if (configFile != null) { + return new FileBasedConfig(parent, configFile, fs); + } + } + return new FileBasedConfig(null, fs) { + @Override + public void load() { + // empty, do not load + } + + @Override + public boolean isOutdated() { + // regular class would bomb here + return false; + } + }; } @Override public FileBasedConfig openUserConfig(Config parent, FS fs) { - final File home = fs.userHome(); - return new FileBasedConfig(parent, new File(home, ".gitconfig"), fs); //$NON-NLS-1$ + if (userConfig == null) { + File home = fs.userHome(); + userConfig = new FileBasedConfig(parent, + new File(home, ".gitconfig"), fs); //$NON-NLS-1$ + } + return userConfig; + } + + @Override + public StoredConfig getSystemConfig() + throws IOException, ConfigInvalidException { + if (systemConfig == null) { + systemConfig = createSystemConfig(null, FS.DETECTED); + } + if (systemConfig.isOutdated()) { + LOG.debug("loading system config {}", systemConfig); //$NON-NLS-1$ + systemConfig.load(); + } + return systemConfig; + } + + @Override + public StoredConfig getUserConfig() + throws IOException, ConfigInvalidException { + if (userConfig == null) { + userConfig = openUserConfig(getSystemConfig(), FS.DETECTED); + } else { + getSystemConfig(); + } + if (userConfig.isOutdated()) { + LOG.debug("loading user config {}", userConfig); //$NON-NLS-1$ + userConfig.load(); + } + return userConfig; } @Override @@ -149,19 +204,19 @@ public abstract class SystemReader { } } - private static SystemReader INSTANCE = DEFAULT; + private static volatile SystemReader INSTANCE = DEFAULT; /** - * Get time since epoch, with up to millisecond resolution. + * Get the current SystemReader instance * - * @return time since epoch, with up to millisecond resolution. + * @return the current SystemReader instance. */ public static SystemReader getInstance() { return INSTANCE; } /** - * Set the new instance to use when accessing properties. + * Set a new SystemReader instance to use when accessing properties. * * @param newReader * the new instance to use when accessing properties, or null for @@ -225,7 +280,10 @@ public abstract class SystemReader { public abstract String getProperty(String key); /** - * Open the git configuration found in the user home + * Open the git configuration found in the user home. Use + * {@link #getUserConfig()} to get the current git configuration in the user + * home since it manages automatic reloading when the gitconfig file was + * modified and avoids unnecessary reloads. * * @param parent * a config with values not found directly in the returned config @@ -237,7 +295,10 @@ public abstract class SystemReader { public abstract FileBasedConfig openUserConfig(Config parent, FS fs); /** - * Open the gitconfig configuration found in the system-wide "etc" directory + * Open the gitconfig configuration found in the system-wide "etc" + * directory. Use {@link #getSystemConfig()} to get the current system-wide + * git configuration since it manages automatic reloading when the gitconfig + * file was modified and avoids unnecessary reloads. * * @param parent * a config with values not found directly in the returned @@ -250,6 +311,38 @@ public abstract class SystemReader { */ public abstract FileBasedConfig openSystemConfig(Config parent, FS fs); + /** + * Get the git configuration found in the user home. The configuration will + * be reloaded automatically if the configuration file was modified. Also + * reloads the system config if the system config file was modified. If the + * configuration file wasn't modified returns the cached configuration. + * + * @return the git configuration found in the user home + * @throws ConfigInvalidException + * if configuration is invalid + * @throws IOException + * if something went wrong when reading files + * @since 5.1.9 + */ + public abstract StoredConfig getUserConfig() + throws IOException, ConfigInvalidException; + + /** + * Get the gitconfig configuration found in the system-wide "etc" directory. + * The configuration will be reloaded automatically if the configuration + * file was modified otherwise returns the cached system level config. + * + * @return the gitconfig configuration found in the system-wide "etc" + * directory + * @throws ConfigInvalidException + * if configuration is invalid + * @throws IOException + * if something went wrong when reading files + * @since 5.1.9 + */ + public abstract StoredConfig getSystemConfig() + throws IOException, ConfigInvalidException; + /** * Get the current system time * diff --git a/pom.xml b/pom.xml index 8da9a88b5..0deeb7f6c 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 1.7.2 1.2.15 3.1.1 - 1.3.0 + 1.4.0 2.8.2 1.61 3.1.12.2