view mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ext/impl/SparseCheckoutProvider.java @ 1027:10dc26b32c35

Update code according to new Java
author nikolai.kulakov@DESKTOP-Q4QCGIH
date Wed, 05 Aug 2020 13:19:53 +0300
parents 7bf4d943d5bb
children
line wrap: on
line source
/*
 * Copyright 2000-2018 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.impl;

import com.intellij.openapi.util.text.StringUtil;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandResult;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.ext.*;
import jetbrains.buildServer.log.Loggers;
import jetbrains.buildServer.util.FileUtil;
import jetbrains.buildServer.vcs.CheckoutRules;
import jetbrains.buildServer.vcs.FileRule;
import jetbrains.buildServer.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class SparseCheckoutProvider implements MercurialExtensionProvider {

  private static final HgVersion MIN_SPARSE_CHECKOUT_VERSION = new HgVersion(3, 0, 0);

  public SparseCheckoutProvider(@NotNull MercurialExtensionManager extentionManager) {
    extentionManager.registerExtentionFactory(this);
  }

  @Nullable
  public MercurialExtension getExtentionForCheckout(@NotNull CheckoutInfo info) {
    if (sparseIsAvailable(info)) {
      return new SparseCheckout(info.getCheckoutRules());
    } else {
      return new UndoSparseCheckout();
    }
  }


  private boolean sparseIsAvailable(@NotNull CheckoutInfo info) {
    if (info.getCheckoutRules().getExcludeRules().isEmpty())
      return false;
    try {
      HgVersion version = info.getTempDirRepo().version().call();
      if (!version.isEqualsOrGreaterThan(MIN_SPARSE_CHECKOUT_VERSION)) {
        Loggers.VCS.info("The sparse checkout is not supported in the mercurial version " + version.toString());
        return false;
      }
      CommandResult result = info.getTempDirRepo().runCommand("help", "extensions");
      boolean enabledExtensions = false;
      for (String line : StringUtil.splitByLines(result.getRawStdout())) {
        if (line.trim().equals("enabled extensions:")) {
          enabledExtensions = true;
          continue;
        }
        if (line.trim().equals("disabled extensions:")) {
          return false;
        }
        if (enabledExtensions) {
          List<String> words = StringUtil.getWordsIn(line.trim());
          if (words.isEmpty())
            continue;
          if (words.get(0).equals("sparse")) {
            Loggers.VCS.info("Sparse extension is enabled");
            return true;
          }
        }
      }
      return true;
    } catch (VcsException e) {
      //log
      return false;
    }
  }


  private static class SparseCheckout implements BeforeWorkingDirUpdateExtension {
    private final CheckoutRules myRules;
    private SparseCheckout(@NotNull CheckoutRules rules) {
      myRules = rules;
    }

    public void call(@NotNull HgRepo repo, @NotNull String revision) throws VcsException {
      String currentConfig = readSparseContent(repo.getWorkingDir());
      String newConfig = getSparseContentFromRules();
      if (currentConfig.equals(newConfig))
        return;
      writeSparseConfig(repo.getWorkingDir(), newConfig);
      repo.runCommand("sparse", "--refresh");
    }

    private void writeSparseConfig(@NotNull File workingDir, @NotNull String sparseContent) throws VcsException {
      try {
        FileUtil.writeToFile(getSparseConfig(workingDir), sparseContent.getBytes(StandardCharsets.UTF_8), false);
      } catch (IOException e) {
        Loggers.VCS.warn("Error while writing .hg/sparse, will not do a sparse checkout", e);
      }
    }

    @NotNull
    private String getSparseContentFromRules() {
      StringBuilder sparse = new StringBuilder();
      sparse.append("[exclude]\n");
      for (FileRule<?> rule : myRules.getExcludeRules()) {
        sparse.append(rule.getFrom()).append("\n");
      }
      return sparse.toString();
    }

    @NotNull
    private String readSparseContent(@NotNull File workingDir) {
      File sparseConfig = getSparseConfig(workingDir);
      if (!sparseConfig.exists())
        return "";
      try {
        return FileUtil.readText(sparseConfig);
      } catch (IOException e) {
        Loggers.VCS.warn("Error while reading .hg/sparse, assume it was empty", e);
        return "";
      }
    }
  }


  private static class UndoSparseCheckout implements BeforeWorkingDirUpdateExtension {
    public void call(@NotNull HgRepo repo, @NotNull String revision) throws VcsException {
      File workingDir = repo.getWorkingDir();
      File sparseConfig = getSparseConfig(workingDir);
      if (sparseConfig.exists()) {
        Loggers.VCS.info("Remove sparse extension config and reset working directory state");
        FileUtil.delete(sparseConfig);
        FileUtil.delete(new File(new File(workingDir, ".hg"), "dirstate"));
      }
    }
  }


  private static File getSparseConfig(@NotNull File workingDir) {
    return new File(new File(workingDir, ".hg"), "sparse");
  }
}