in git-server/src/main/java/jetbrains/buildServer/buildTriggers/vcs/git/FetchCommandImpl.java [88:213]
private void fetchInSeparateProcess(@NotNull Repository repository,
@NotNull URIish uri,
@NotNull FetchSettings settings) throws VcsException {
if (mySshKnownHostsManager.isKnownHostsEnabled(ServerSshKnownHostsContext.INSTANCE)) {
try {
ServerURI serverURI = ServerURIParser.createServerURI(uri.toString());
if ("ssh".equals(serverURI.getScheme())) {
mySshKnownHostsManager.updateKnownHosts(ServerSshKnownHostsContext.INSTANCE, uri.getHost(), uri.getPort());
}
} catch (Exception e) {
LOG.warnAndDebugDetails("Failed to update known hosts for " + uri, e);
}
}
final Collection<RefSpec> specs = settings.getRefSpecs();
final String debugInfo = getDebugInfo(repository, uri, specs);
final ProcessXmxProvider xmxProvider = new ProcessXmxProvider(new RepositoryXmxStorage(repository, "fetch"), myConfig, "fetch", debugInfo);
Integer xmx = xmxProvider.getNextXmx();
int attempt = 0;
while (xmx != null) {
attempt++;
File gitPropertiesFile = null;
File teamcityPrivateKey = null;
GitProcessStuckMonitor processStuckMonitor = null;
try {
File gcDump = getDumpFile(repository, "gc");
gitPropertiesFile = myFetcherProperties.getPropertiesFile();
teamcityPrivateKey = getTeamCityPrivateKey(settings.getAuthSettings());
final GeneralCommandLine cl = createFetcherCommandLine(repository, uri, xmx);
final String commandLineString = cl.getCommandLineString();
final GitProcessExecutor processExecutor = new GitProcessExecutor(cl);
processStuckMonitor = new GitProcessStuckMonitor(gcDump, xmx.longValue(), commandLineString) {
@Override
protected void stuckDetected() {
processExecutor.interrupt();
}
};
processStuckMonitor.start();
final GitProcessExecutor.GitExecResult gitResult = processExecutor.runProcess(
getFetchProcessInputBytes(getAuthSettings(settings, teamcityPrivateKey), repository.getDirectory(), uri, specs, getDumpFile(repository, null), gcDump, gitPropertiesFile),
myConfig.getFetchTimeoutSeconds(),
settings.createStdoutBuffer(),
new ByteArrayOutputStream(),
new GitProcessExecutor.ProcessExecutorAdapter() {
@Override
public void processStarted() {
if (LOG.isDebugEnabled()) LOG.debug("git fetch process for " + debugInfo + " started in separate process with command line: " + commandLineString);
settings.getProgress().reportProgress("git fetch " + uri);
}
@Override
public void processFinished() {
if (LOG.isDebugEnabled()) LOG.debug("git fetch process for " + debugInfo + " finished");
settings.getProgress().reportProgress("git fetch " + uri + " finished");
}
@Override
public void processFailed(@NotNull final ExecutionException e) {
if (LOG.isDebugEnabled()) LOG.debug("git fetch process for " + debugInfo + " failed");
settings.getProgress().reportProgress("git fetch " + uri + " failed");
}
});
final ExecResult result = gitResult.getExecResult();
VcsException commandError = CommandLineUtil.getCommandLineError("git fetch",
" (repository dir: <TeamCity data dir>/system/caches/git/" +
repository.getDirectory().getName() + ")",
result, true, true);
if (commandError != null) {
commandError.setRecoverable(isRecoverable(commandError));
/* if the process had not enough memory or we killed it because gc */
if (gitResult.isOutOfMemoryError() || gitResult.isInterrupted()) {
final Integer nextXmx = xmxProvider.getNextXmx();
if (nextXmx != null) {
xmx = nextXmx;
clean(repository);
continue;
}
commandError = new VcsException("There is not enough memory for git fetch (last attempted -Xmx" + xmx + "M). Please contact your system administrator", commandError);
} else if (attempt == 1 && settings.getAuthSettings().doesTokenNeedRefresh()) {
LOG.debug("git fetch process failed due to suspected token expiration for \"" + uri + "\" in directory \"" + repository.getDirectory() + "\", took " +
TimePrinter.createMillisecondsFormatter().formatTime(gitResult.getDuration()) + ". Retrying with token refresh.");
continue;
}
LOG.info("git fetch process failed for \"" + uri + "\" in directory \"" + repository.getDirectory() + "\", took " +
TimePrinter.createMillisecondsFormatter().formatTime(gitResult.getDuration()));
if (gitResult.isTimeout()) {
logTimeout(debugInfo, getDumpFile(repository, null));
}
clean(repository);
throw commandError;
}
LOG.info("git fetch process finished for: " + uri + " in directory: " + repository.getDirectory() + ", took " + gitResult.getDuration() + "ms");
if (result.getStderr().length() > 0) {
LOG.warn("Error output produced by git fetch:\n" + result.getStderr());
}
LOG.debug("git fetch process output:\n" + result.getStdout());
break;
} finally {
if (teamcityPrivateKey != null) {
FileUtil.delete(teamcityPrivateKey);
}
if (gitPropertiesFile != null) {
FileUtil.delete(gitPropertiesFile);
}
if (processStuckMonitor != null) {
processStuckMonitor.finish();
}
}
}
}