Merge branch 'stable-5.5'
* stable-5.5: BaseReceivePack: Fix the format Prepend hostname to subsection used to store file timestamp resolution Store filesystem timestamp resolution in extra jgit config SystemReader: extract updating config and its parents if outdated Change-Id: Iecfddce8081303af29badcdcd3d72a0da50c964f Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
commit
826317942f
|
@ -125,8 +125,9 @@ public abstract class LocalDiskRepositoryTestCase {
|
|||
public void setUp() throws Exception {
|
||||
tmp = File.createTempFile("jgit_test_", "_tmp");
|
||||
CleanupThread.deleteOnShutdown(tmp);
|
||||
if (!tmp.delete() || !tmp.mkdir())
|
||||
if (!tmp.delete() || !tmp.mkdir()) {
|
||||
throw new IOException("Cannot create " + tmp);
|
||||
}
|
||||
|
||||
mockSystemReader = new MockSystemReader();
|
||||
SystemReader.setInstance(mockSystemReader);
|
||||
|
@ -137,7 +138,11 @@ public void setUp() throws Exception {
|
|||
// the same one here
|
||||
FS.getFileStoreAttributes(tmp.toPath().getParent());
|
||||
|
||||
FileBasedConfig userConfig = new FileBasedConfig(
|
||||
FileBasedConfig jgitConfig = new FileBasedConfig(
|
||||
new File(tmp, "jgitconfig"), FS.DETECTED);
|
||||
FileBasedConfig systemConfig = new FileBasedConfig(jgitConfig,
|
||||
new File(tmp, "systemgitconfig"), FS.DETECTED);
|
||||
FileBasedConfig userConfig = new FileBasedConfig(systemConfig,
|
||||
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
|
||||
|
@ -145,7 +150,10 @@ public void setUp() throws Exception {
|
|||
userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION,
|
||||
null, ConfigConstants.CONFIG_KEY_AUTODETACH, false);
|
||||
userConfig.save();
|
||||
mockSystemReader.setJGitConfig(jgitConfig);
|
||||
mockSystemReader.setSystemGitConfig(systemConfig);
|
||||
mockSystemReader.setUserGitConfig(userConfig);
|
||||
|
||||
ceilTestDirectories(getCeilings());
|
||||
|
||||
author = new PersonIdent("J. Author", "jauthor@example.com");
|
||||
|
|
|
@ -103,6 +103,8 @@ public String toString() {
|
|||
|
||||
private FileBasedConfig userGitConfig;
|
||||
|
||||
private FileBasedConfig jgitConfig;
|
||||
|
||||
FileBasedConfig systemGitConfig;
|
||||
|
||||
/**
|
||||
|
@ -118,6 +120,16 @@ public FileBasedConfig setUserGitConfig(FileBasedConfig userGitConfig) {
|
|||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the jgit config stored at $XDG_CONFIG_HOME/jgit/config
|
||||
*
|
||||
* @param jgitConfig
|
||||
* set the jgit configuration
|
||||
*/
|
||||
public void setJGitConfig(FileBasedConfig jgitConfig) {
|
||||
this.jgitConfig = jgitConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the system-level git config
|
||||
*
|
||||
|
@ -142,6 +154,7 @@ public MockSystemReader() {
|
|||
init(Constants.GIT_COMMITTER_EMAIL_KEY);
|
||||
setProperty(Constants.OS_USER_DIR, ".");
|
||||
userGitConfig = new MockConfig(null, null);
|
||||
jgitConfig = new MockConfig(null, null);
|
||||
systemGitConfig = new MockConfig(null, null);
|
||||
setCurrentPlatform();
|
||||
}
|
||||
|
@ -199,6 +212,11 @@ public StoredConfig getUserConfig()
|
|||
return userGitConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileBasedConfig getJGitConfig() {
|
||||
return jgitConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredConfig getSystemConfig()
|
||||
throws IOException, ConfigInvalidException {
|
||||
|
@ -333,4 +351,9 @@ public String toString() {
|
|||
return "MockSystemReader";
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileBasedConfig openJGitConfig(Config parent, FS fs) {
|
||||
return jgitConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
import org.junit.Test;
|
||||
|
||||
public class FS_POSIXTest {
|
||||
private SystemReader originalSystemReaderInstance;
|
||||
private FileBasedConfig jgitConfig;
|
||||
|
||||
private FileBasedConfig systemConfig;
|
||||
|
||||
|
@ -70,6 +70,7 @@ public class FS_POSIXTest {
|
|||
@Before
|
||||
public void setUp() throws Exception {
|
||||
tmp = Files.createTempDirectory("jgit_test_");
|
||||
|
||||
MockSystemReader mockSystemReader = new MockSystemReader();
|
||||
SystemReader.setInstance(mockSystemReader);
|
||||
|
||||
|
@ -78,7 +79,10 @@ public void setUp() throws Exception {
|
|||
// The MockSystemReader must be configured first since we need to use
|
||||
// the same one here
|
||||
FS.getFileStoreAttributes(tmp.getParent());
|
||||
systemConfig = new FileBasedConfig(
|
||||
|
||||
jgitConfig = new FileBasedConfig(new File(tmp.toFile(), "jgitconfig"),
|
||||
FS.DETECTED);
|
||||
systemConfig = new FileBasedConfig(jgitConfig,
|
||||
new File(tmp.toFile(), "systemgitconfig"), FS.DETECTED);
|
||||
userConfig = new FileBasedConfig(systemConfig,
|
||||
new File(tmp.toFile(), "usergitconfig"), FS.DETECTED);
|
||||
|
@ -89,16 +93,14 @@ public void setUp() throws Exception {
|
|||
userConfig.setBoolean(ConfigConstants.CONFIG_GC_SECTION, null,
|
||||
ConfigConstants.CONFIG_KEY_AUTODETACH, false);
|
||||
userConfig.save();
|
||||
mockSystemReader.setJGitConfig(jgitConfig);
|
||||
mockSystemReader.setSystemGitConfig(systemConfig);
|
||||
mockSystemReader.setUserGitConfig(userConfig);
|
||||
|
||||
originalSystemReaderInstance = SystemReader.getInstance();
|
||||
SystemReader.setInstance(mockSystemReader);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws IOException {
|
||||
SystemReader.setInstance(originalSystemReaderInstance);
|
||||
SystemReader.setInstance(null);
|
||||
FileUtils.delete(tmp.toFile(), FileUtils.RECURSIVE | FileUtils.RETRY);
|
||||
}
|
||||
|
||||
|
|
|
@ -201,8 +201,10 @@ countingObjects=Counting objects
|
|||
corruptPack=Pack file {0} is corrupt, removing it from pack list
|
||||
createBranchFailedUnknownReason=Create branch failed for unknown reason
|
||||
createBranchUnexpectedResult=Create branch returned unexpected result {0}
|
||||
createJGitConfigFailed=Creating JGit config directory {} failed
|
||||
createNewFileFailed=Could not create new file {0}
|
||||
createRequiresZeroOldId=Create requires old ID to be zero
|
||||
createXDGConfigHomeFailed=Creating XDG_CONFIG_HOME directory {} failed
|
||||
credentialPassword=Password
|
||||
credentialPassphrase=Passphrase
|
||||
credentialUsername=Username
|
||||
|
|
|
@ -262,8 +262,10 @@ public static JGitText get() {
|
|||
/***/ public String countingObjects;
|
||||
/***/ public String createBranchFailedUnknownReason;
|
||||
/***/ public String createBranchUnexpectedResult;
|
||||
/***/ public String createJGitConfigFailed;
|
||||
/***/ public String createNewFileFailed;
|
||||
/***/ public String createRequiresZeroOldId;
|
||||
/***/ public String createXDGConfigHomeFailed;
|
||||
/***/ public String credentialPassword;
|
||||
/***/ public String credentialPassphrase;
|
||||
/***/ public String credentialUsername;
|
||||
|
|
|
@ -128,10 +128,22 @@ public Config(Config defaultConfig) {
|
|||
state = new AtomicReference<>(newState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this config's base config.
|
||||
*
|
||||
* @return the base configuration of this config.
|
||||
*
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public Config getBaseConfig() {
|
||||
return baseConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given string is the "missing" value.
|
||||
*
|
||||
* @param value string to be checked.
|
||||
* @param value
|
||||
* string to be checked.
|
||||
* @return true if the given string is the "missing" value.
|
||||
* @since 5.4
|
||||
*/
|
||||
|
|
|
@ -342,6 +342,15 @@ public final class Constants {
|
|||
*/
|
||||
public static final String GIT_CONFIG_NOSYSTEM_KEY = "GIT_CONFIG_NOSYSTEM";
|
||||
|
||||
/**
|
||||
* The key of the XDG_CONFIG_HOME directory defined in the XDG base
|
||||
* directory specification, see
|
||||
* {@link "https://wiki.archlinux.org/index.php/XDG_Base_Directory"}
|
||||
*
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static final String XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
|
||||
|
||||
/**
|
||||
* The environment variable that limits how close to the root of the file
|
||||
* systems JGit will traverse when looking for a repository root.
|
||||
|
|
|
@ -1361,7 +1361,7 @@ private void parseShallow(String idStr) throws PackProtocolException {
|
|||
}
|
||||
|
||||
static ReceiveCommand parseCommand(String line) throws PackProtocolException {
|
||||
if (line == null || line.length() < 83) {
|
||||
if (line == null || line.length() < 83) {
|
||||
throw new PackProtocolException(
|
||||
JGitText.get().errorInvalidProtocolWantedOldNewRef);
|
||||
}
|
||||
|
|
|
@ -246,8 +246,9 @@ private static void setBackground(boolean async) {
|
|||
background.set(async);
|
||||
}
|
||||
|
||||
private static final String javaVersionPrefix = System
|
||||
.getProperty("java.vendor") + '|' //$NON-NLS-1$
|
||||
private static final String javaVersionPrefix = SystemReader
|
||||
.getInstance().getHostname() + '|'
|
||||
+ System.getProperty("java.vendor") + '|' //$NON-NLS-1$
|
||||
+ System.getProperty("java.version") + '|'; //$NON-NLS-1$
|
||||
|
||||
private static final Duration FALLBACK_MIN_RACY_INTERVAL = Duration
|
||||
|
@ -547,9 +548,9 @@ private static Optional<FileStoreAttributes> readFromConfig(
|
|||
|
||||
private static void saveToConfig(FileStore s,
|
||||
FileStoreAttributes c) {
|
||||
StoredConfig userConfig;
|
||||
StoredConfig jgitConfig;
|
||||
try {
|
||||
userConfig = SystemReader.getInstance().getUserConfig();
|
||||
jgitConfig = SystemReader.getInstance().getJGitConfig();
|
||||
} catch (IOException | ConfigInvalidException e) {
|
||||
LOG.error(JGitText.get().saveFileStoreAttributesFailed, e);
|
||||
return;
|
||||
|
@ -570,20 +571,19 @@ private static void saveToConfig(FileStore s,
|
|||
String key = getConfigKey(s);
|
||||
while (!succeeded && retries < max_retries) {
|
||||
try {
|
||||
userConfig.load();
|
||||
userConfig.setString(
|
||||
jgitConfig.setString(
|
||||
ConfigConstants.CONFIG_FILESYSTEM_SECTION, key,
|
||||
ConfigConstants.CONFIG_KEY_TIMESTAMP_RESOLUTION,
|
||||
String.format("%d %s", //$NON-NLS-1$
|
||||
Long.valueOf(resolutionValue),
|
||||
resolutionUnit.name().toLowerCase()));
|
||||
userConfig.setString(
|
||||
jgitConfig.setString(
|
||||
ConfigConstants.CONFIG_FILESYSTEM_SECTION, key,
|
||||
ConfigConstants.CONFIG_KEY_MIN_RACY_THRESHOLD,
|
||||
String.format("%d %s", //$NON-NLS-1$
|
||||
Long.valueOf(minRacyThresholdValue),
|
||||
minRacyThresholdUnit.name().toLowerCase()));
|
||||
userConfig.save();
|
||||
jgitConfig.save();
|
||||
succeeded = true;
|
||||
} catch (LockFailedException e) {
|
||||
// race with another thread, wait a bit and try again
|
||||
|
@ -592,11 +592,11 @@ private static void saveToConfig(FileStore s,
|
|||
if (retries < max_retries) {
|
||||
Thread.sleep(100);
|
||||
LOG.debug("locking {} failed, retries {}/{}", //$NON-NLS-1$
|
||||
userConfig, Integer.valueOf(retries),
|
||||
jgitConfig, Integer.valueOf(retries),
|
||||
Integer.valueOf(max_retries));
|
||||
} else {
|
||||
LOG.warn(MessageFormat.format(
|
||||
JGitText.get().lockFailedRetry, userConfig,
|
||||
JGitText.get().lockFailedRetry, jgitConfig,
|
||||
Integer.valueOf(retries)));
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
|
@ -605,12 +605,7 @@ private static void saveToConfig(FileStore s,
|
|||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error(MessageFormat.format(
|
||||
JGitText.get().cannotSaveConfig, userConfig), e);
|
||||
break;
|
||||
} catch (ConfigInvalidException e) {
|
||||
LOG.error(MessageFormat.format(
|
||||
JGitText.get().repositoryConfigFileInvalid,
|
||||
userConfig, e.getMessage()));
|
||||
JGitText.get().cannotSaveConfig, jgitConfig), e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.text.DateFormat;
|
||||
|
@ -60,6 +64,7 @@
|
|||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.errors.CorruptObjectException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectChecker;
|
||||
|
@ -137,6 +142,42 @@ public FileBasedConfig openUserConfig(Config parent, FS fs) {
|
|||
fs);
|
||||
}
|
||||
|
||||
private Path getXDGConfigHome(FS fs) {
|
||||
String configHomePath = getenv(Constants.XDG_CONFIG_HOME);
|
||||
if (StringUtils.isEmptyOrNull(configHomePath)) {
|
||||
configHomePath = new File(fs.userHome(), ".config") //$NON-NLS-1$
|
||||
.getAbsolutePath();
|
||||
}
|
||||
try {
|
||||
Path xdgHomePath = Paths.get(configHomePath);
|
||||
Files.createDirectories(xdgHomePath);
|
||||
return xdgHomePath;
|
||||
} catch (IOException | InvalidPathException e) {
|
||||
LOG.error(JGitText.get().createXDGConfigHomeFailed,
|
||||
configHomePath, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileBasedConfig openJGitConfig(Config parent, FS fs) {
|
||||
Path xdgPath = getXDGConfigHome(fs);
|
||||
if (xdgPath != null) {
|
||||
Path configPath = null;
|
||||
try {
|
||||
configPath = xdgPath.resolve("jgit"); //$NON-NLS-1$
|
||||
Files.createDirectories(configPath);
|
||||
configPath = configPath.resolve(Constants.CONFIG);
|
||||
return new FileBasedConfig(parent, configPath.toFile(), fs);
|
||||
} catch (IOException e) {
|
||||
LOG.error(JGitText.get().createJGitConfigFailed, configPath,
|
||||
e);
|
||||
}
|
||||
}
|
||||
return new FileBasedConfig(parent,
|
||||
new File(fs.userHome(), ".jgitconfig"), fs); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostname() {
|
||||
if (hostname == null) {
|
||||
|
@ -198,6 +239,8 @@ public static void setInstance(SystemReader newReader) {
|
|||
|
||||
private AtomicReference<FileBasedConfig> userConfig = new AtomicReference<>();
|
||||
|
||||
private AtomicReference<FileBasedConfig> jgitConfig = new AtomicReference<>();
|
||||
|
||||
private void init() {
|
||||
// Creating ObjectChecker must be deferred. Unit tests change
|
||||
// behavior of is{Windows,MacOS} in constructor of subclass.
|
||||
|
@ -274,6 +317,22 @@ protected final void setPlatformChecker() {
|
|||
*/
|
||||
public abstract FileBasedConfig openSystemConfig(Config parent, FS fs);
|
||||
|
||||
/**
|
||||
* Open the jgit configuration located at $XDG_CONFIG_HOME/jgit/config. Use
|
||||
* {@link #getJGitConfig()} to get the current jgit configuration in the
|
||||
* user home since it manages automatic reloading when the jgit config file
|
||||
* was modified and avoids unnecessary reloads.
|
||||
*
|
||||
* @param parent
|
||||
* a config with values not found directly in the returned config
|
||||
* @param fs
|
||||
* the file system abstraction which will be necessary to perform
|
||||
* certain file system operations.
|
||||
* @return the jgit configuration located at $XDG_CONFIG_HOME/jgit/config
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public abstract FileBasedConfig openJGitConfig(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
|
||||
|
@ -288,20 +347,41 @@ protected final void setPlatformChecker() {
|
|||
* @since 5.1.9
|
||||
*/
|
||||
public StoredConfig getUserConfig()
|
||||
throws IOException, ConfigInvalidException {
|
||||
throws ConfigInvalidException, IOException {
|
||||
FileBasedConfig c = userConfig.get();
|
||||
if (c == null) {
|
||||
userConfig.compareAndSet(null,
|
||||
openUserConfig(getSystemConfig(), FS.DETECTED));
|
||||
c = userConfig.get();
|
||||
} else {
|
||||
// Ensure the parent is up to date
|
||||
getSystemConfig();
|
||||
}
|
||||
if (c.isOutdated()) {
|
||||
LOG.debug("loading user config {}", userConfig); //$NON-NLS-1$
|
||||
c.load();
|
||||
// on the very first call this will check a second time if the system
|
||||
// config is outdated
|
||||
updateAll(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the jgit configuration located at $XDG_CONFIG_HOME/jgit/config. The
|
||||
* configuration will be reloaded automatically if the configuration file
|
||||
* was modified. If the configuration file wasn't modified returns the
|
||||
* cached configuration.
|
||||
*
|
||||
* @return the jgit configuration located at $XDG_CONFIG_HOME/jgit/config
|
||||
* @throws ConfigInvalidException
|
||||
* if configuration is invalid
|
||||
* @throws IOException
|
||||
* if something went wrong when reading files
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public StoredConfig getJGitConfig()
|
||||
throws ConfigInvalidException, IOException {
|
||||
FileBasedConfig c = jgitConfig.get();
|
||||
if (c == null) {
|
||||
jgitConfig.compareAndSet(null,
|
||||
openJGitConfig(null, FS.DETECTED));
|
||||
c = jgitConfig.get();
|
||||
}
|
||||
updateAll(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -319,20 +399,45 @@ public StoredConfig getUserConfig()
|
|||
* @since 5.1.9
|
||||
*/
|
||||
public StoredConfig getSystemConfig()
|
||||
throws IOException, ConfigInvalidException {
|
||||
throws ConfigInvalidException, IOException {
|
||||
FileBasedConfig c = systemConfig.get();
|
||||
if (c == null) {
|
||||
systemConfig.compareAndSet(null,
|
||||
openSystemConfig(null, FS.DETECTED));
|
||||
openSystemConfig(getJGitConfig(), FS.DETECTED));
|
||||
c = systemConfig.get();
|
||||
}
|
||||
if (c.isOutdated()) {
|
||||
LOG.debug("loading system config {}", systemConfig); //$NON-NLS-1$
|
||||
c.load();
|
||||
}
|
||||
updateAll(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update config and its parents if they seem modified
|
||||
*
|
||||
* @param config
|
||||
* configuration to reload if outdated
|
||||
* @throws ConfigInvalidException
|
||||
* if configuration is invalid
|
||||
* @throws IOException
|
||||
* if something went wrong when reading files
|
||||
*/
|
||||
private void updateAll(Config config)
|
||||
throws ConfigInvalidException, IOException {
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
updateAll(config.getBaseConfig());
|
||||
if (config instanceof FileBasedConfig) {
|
||||
FileBasedConfig cfg = (FileBasedConfig) config;
|
||||
if (!cfg.getFile().exists()) {
|
||||
return;
|
||||
}
|
||||
if (cfg.isOutdated()) {
|
||||
LOG.debug("loading config {}", cfg); //$NON-NLS-1$
|
||||
cfg.load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current system time
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue