private void fetchInSeparateProcess()

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();
        }
      }
    }
  }