Mercurial > hg > mercurial
changeset 338:d31d7c81b637 Eluru-6.5.x
Support subrepositories while building clean patch.
Use 'hg clone' instead of 'hg archive' if repository contains
subrepositories.
line wrap: on
line diff
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Thu Dec 01 14:47:47 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Fri Dec 02 15:12:49 2011 +0300 @@ -84,9 +84,9 @@ } /** - * Since mercurial 1.7 on Windows the only file inside '<mercurial_install_dir>/bin' is 'hg.cmd' - * which run hg.exe placed in the parent dir. GeneralCommandLine will not find hg.cmd, in the - * case when $PATH contains <mercurial_install_dir>/bin and doesn't contain <mercurial_install_dir> + * Since mercurial 1.7 on Windows the only file inside '<mercurial_install_dir>/bin' is 'hg.cmd' + * which run hg.exe placed in the parent dir. GeneralCommandLine will not find hg.cmd, in the + * case when $PATH contains <mercurial_install_dir>/bin and doesn't contain <mercurial_install_dir> * and hg executable is set to 'hg'. To fix it - run hg using windows shell which expand * hg to hg.cmd correctly. */ @@ -112,6 +112,10 @@ return CommandUtil.runCommand(cli, getPrivateData()); } + protected ExecResult runCommand(@NotNull GeneralCommandLine cli, boolean logErrorsInDebug) throws VcsException { + return CommandUtil.runCommand(cli, CommandUtil.DEFAULT_COMMAND_TIMEOUT_SEC, getPrivateData(), logErrorsInDebug); + } + protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException { return CommandUtil.runCommand(cli, executionTimeout, getPrivateData()); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Thu Dec 01 14:47:47 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Dec 02 15:12:49 2011 +0300 @@ -29,6 +29,7 @@ public class CatCommand extends BaseCommand { private String myRevId; private final static int MAX_CMD_LEN = 900; + private boolean myLogErrorsInDebug = false; public CatCommand(@NotNull Settings settings, @NotNull File workingDir) { super(settings, workingDir); @@ -38,6 +39,10 @@ myRevId = revId; } + public void setLogErrorsInDebug(boolean doLogErrorsInDebug) { + myLogErrorsInDebug = doLogErrorsInDebug; + } + public File execute(List<String> relPaths) throws VcsException { File tempDir; try { @@ -63,7 +68,7 @@ cmdSize += path.length(); } while (cmdSize < MAX_CMD_LEN && !paths.isEmpty()); - runCommand(cli); + runCommand(cli, myLogErrorsInDebug); } return tempDir;
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Thu Dec 01 14:47:47 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Fri Dec 02 15:12:49 2011 +0300 @@ -31,23 +31,25 @@ public static final int DEFAULT_COMMAND_TIMEOUT_SEC = 3600; public static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res) throws VcsException { - if (res.getExitCode() != 0 || res.getException() != null) { - commandFailed(cmdName, res); - } - if (res.getStderr().length() > 0) { - Loggers.VCS.warn("Error output produced by: " + cmdName); - Loggers.VCS.warn(res.getStderr()); + checkCommandFailed(cmdName, res, false); + } + + private static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res, boolean logErrorsInDebug) throws VcsException { + if (logErrorsInDebug) { + if (res.getExitCode() != 0 || res.getException() != null) + Loggers.VCS.debug(createCommandLogMessage(cmdName, res)); + } else { + if (res.getExitCode() != 0 || res.getException() != null) + commandFailed(cmdName, res); + if (res.getStderr().length() > 0) { + Loggers.VCS.warn("Error output produced by: " + cmdName); + Loggers.VCS.warn(res.getStderr()); + } } } public static void commandFailed(final String cmdName, final ExecResult res) throws VcsException { - String stderr = res.getStderr(); - String stdout = res.getStdout(); - String exceptionMessage = getExceptionMessage(res); - final String message = "'" + cmdName + "' command failed.\n" + - (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") + - (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") + - (exceptionMessage != null ? "exception: " + exceptionMessage : ""); + final String message = createCommandLogMessage(cmdName, res); Loggers.VCS.warn(message); if (hasImportantException(res)) { Loggers.VCS.error("Error during executing '" + cmdName + "'", res.getException()); @@ -55,6 +57,16 @@ throw new VcsException(message); } + private static String createCommandLogMessage(final String cmdName, final ExecResult res) { + String stderr = res.getStderr(); + String stdout = res.getStdout(); + String exceptionMessage = getExceptionMessage(res); + return "'" + cmdName + "' command failed.\n" + + (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") + + (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") + + (exceptionMessage != null ? "exception: " + exceptionMessage : ""); + } + @Nullable private static String getExceptionMessage(ExecResult result) { Throwable exception = result.getException(); @@ -86,6 +98,10 @@ } public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData) throws VcsException { + return runCommand(cli, executionTimeout, privateData, false); + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData, boolean logErrorsInDebug) throws VcsException { final String cmdStr = removePrivateData(cli.getCommandLineString(), privateData); Loggers.VCS.debug("Run command: " + cmdStr); final long start = System.currentTimeMillis(); @@ -103,7 +119,7 @@ removePrivateData(privateData, res); - CommandUtil.checkCommandFailed(cmdStr, res); + CommandUtil.checkCommandFailed(cmdStr, res, logErrorsInDebug); Loggers.VCS.debug("Command " + cmdStr + " output:\n" + res.getStdout()); return res; }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Thu Dec 01 14:47:47 2011 +0300 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Fri Dec 02 15:12:49 2011 +0300 @@ -33,6 +33,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.util.*; @@ -41,6 +42,8 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces; + /** * Mercurial VCS plugin for TeamCity works as follows: * <ul> @@ -61,6 +64,8 @@ private MirrorManager myMirrorManager; private final ServerPluginConfig myConfig; private File myLogTemplate; + private final FileFilter myIgnoreDotHgFilter = new IgnoreDotHgFilter(); + private final FileFilter myAcceptAllFilter = new AcceptAllFilter(); public MercurialVcsSupport(@NotNull final VcsManager vcsManager, @NotNull final ServerPaths paths, @@ -189,6 +194,35 @@ return new byte[0]; } + /** + * Returns file's content or empty string if it doesn't exist. + * @param path path of the file of interest + * @param settings root settings + * @param cset repository cset (should be present in the repository) + * @return see above + */ + @NotNull + private String getFileContent(@NotNull final String path, @NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { + File dir = getWorkingDir(settings); + CatCommand cat = new CatCommand(settings, dir); + cat.setRevId(cset.getId()); + cat.setLogErrorsInDebug(true); + File parentDir = null; + try { + parentDir = cat.execute(Collections.singletonList(path)); + File f = new File(parentDir, path); + if (f.isFile()) + return FileUtil.readText(f); + else + return ""; + } catch (Exception e) { + return ""; + } finally { + if (parentDir != null) + deleteTmpDir(parentDir); + } + } + @NotNull public String getName() { return Constants.VCS_NAME; @@ -207,7 +241,7 @@ List<InvalidProperty> result = new ArrayList<InvalidProperty>(); if (isEmpty(properties.get(Constants.HG_COMMAND_PATH_PROP))) { result.add(new InvalidProperty(Constants.HG_COMMAND_PATH_PROP, "Path to 'hg' command must be specified")); - } + } if (isEmpty(properties.get(Constants.REPOSITORY_PROP))) { result.add(new InvalidProperty(Constants.REPOSITORY_PROP, "Repository must be specified")); } @@ -354,22 +388,44 @@ File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId()); try { File mirrorDir = getWorkingDir(settings); - ArchiveCommand archive = new ArchiveCommand(settings, mirrorDir); - archive.setDestDir(tempDir); - archive.setToId(toVer.getId()); - archive.execute(); - buildPatchFromDirectory(builder, tempDir, checkoutRules); + if (hasSubrepositories(settings, toVer)) { + Loggers.VCS.debug("Repository '" + settings.getRepository() + "' has submodules at revision " + toVer.getId() + ", use 'hg clone' to build clean patch"); + CloneCommand cl = new CloneCommand(settings, tempDir); + cl.setRepository(mirrorDir.getAbsolutePath()); + cl.setToId(toVer.getId()); + cl.setUpdateWorkingDir(false); + cl.setUsePullProtocol(myConfig.isUsePullProtocol()); + cl.execute(); + + UpdateCommand up = new UpdateCommand(settings, tempDir); + up.setToId(toVer.getId()); + up.execute(); + + buildPatchFromDirectory(builder, tempDir, checkoutRules, myIgnoreDotHgFilter); + } else { + Loggers.VCS.debug("Repository '" + settings.getRepository() + "' doesn't have submodules at revision " + toVer.getId() + ", use 'hg archive' to build clean patch"); + ArchiveCommand archive = new ArchiveCommand(settings, mirrorDir); + archive.setDestDir(tempDir); + archive.setToId(toVer.getId()); + archive.execute(); + buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter); + } } finally { FileUtil.delete(tempDir); } } - private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules) throws IOException { - buildPatchFromDirectory(repRoot, builder, repRoot, checkoutRules); + private boolean hasSubrepositories(@NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { + String hgsub = getFileContent(".hgsub", settings, cset); + return !isEmptyOrSpaces(hgsub); } - private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules) throws IOException { - File[] files = curDir.listFiles(); + private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { + buildPatchFromDirectory(repRoot, builder, repRoot, checkoutRules, filter); + } + + private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { + File[] files = curDir.listFiles(filter); if (files != null) { for (File realFile: files) { String relPath = realFile.getAbsolutePath().substring(repRoot.getAbsolutePath().length()); @@ -378,7 +434,7 @@ final File virtualFile = new File(mappedPath); if (realFile.isDirectory()) { builder.createDirectory(virtualFile); - buildPatchFromDirectory(realFile, builder, repRoot, checkoutRules); + buildPatchFromDirectory(realFile, builder, repRoot, checkoutRules, filter); } else { final FileInputStream is = new FileInputStream(realFile); try { @@ -389,7 +445,7 @@ } } else { if (realFile.isDirectory()) { - buildPatchFromDirectory(realFile, builder, repRoot, checkoutRules); + buildPatchFromDirectory(realFile, builder, repRoot, checkoutRules, filter); } } } @@ -754,4 +810,17 @@ public MirrorManager getMirrorManager() { return myMirrorManager; } + + + private static class IgnoreDotHgFilter implements FileFilter { + public boolean accept(final File file) { + return !(file.isDirectory() && ".hg".equals(file.getName())); + } + } + + private static class AcceptAllFilter implements FileFilter { + public boolean accept(File pathname) { + return true; + } + } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Thu Dec 01 14:47:47 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Fri Dec 02 15:12:49 2011 +0300 @@ -40,6 +40,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import static com.intellij.openapi.util.io.FileUtil.copyDir; +import static com.intellij.openapi.util.io.FileUtil.moveDirWithContent; + @Test public class MercurialVcsSupportTest extends BaseMercurialTestCase { private MercurialVcsSupport myVcs; @@ -131,7 +134,7 @@ builder.close(); return output; } - + @Test public void test_build_patch() throws IOException, VcsException { setName("cleanPatch1"); @@ -185,6 +188,20 @@ checkPatchResult(output.toByteArray()); } + public void test_clean_patch_with_subrepositories() throws Exception { + File r1 = new File(myServerPaths.getCachesDir() + File.separator + "mercurial", "r1"); + File r3 = new File(myServerPaths.getCachesDir() + File.separator + "mercurial", "r3"); + copyDir(new File("mercurial-tests/testData/subrepos/r1"), r1); + copyDir(new File("mercurial-tests/testData/subrepos/r3"), r3); + moveDirWithContent(new File(r1, "hg"), new File(r1, ".hg")); + moveDirWithContent(new File(r3, "hg"), new File(r3, ".hg")); + + VcsRootImpl root = createVcsRoot(r1.getAbsolutePath()); + + setName("clean_patch_with_subrepositories"); + checkPatchResult(buildPatch(root, null, "3:d350e7209906", CheckoutRules.DEFAULT).toByteArray()); + } + public void test_get_content() throws IOException, VcsException { VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); @@ -496,4 +513,4 @@ }; } } - +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/clean_patch_with_subrepositories/after/.hgsub Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +r2 = ../r3 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/clean_patch_with_subrepositories/after/.hgsubstate Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +9e4a2fef1a1c04623a0d89edb4f3ba290cf2666e r2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/clean_patch_with_subrepositories/after/a Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/clean_patch_with_subrepositories/after/r2/c Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/clean_patch_with_subrepositories/before/a Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/README Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,11 @@ +r1 history: +3:d350e7209906 Add different subrepository in the same path <- subrepository r2 = ../r3 (9e4a2fef1a1c) +2:4d7b3db8779f Remove subrepository <- subrepository removed +1:34017377d9c3 Add subrepository <- subrepository r2 = ../r2 (916933c1dd8e) +0:e4eced2b7381 Initial commit + +r2 history: +0:916933c1dd8e Initial commit + +r3 history: +0:9e4a2fef1a1c Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/branchheads.cache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,2 @@ +4d7b3db8779f75e0ca452fdd9a057a5c69665aa3 2 +4d7b3db8779f75e0ca452fdd9a057a5c69665aa3 default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/last-message.txt Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +Add different subrepository in the same path \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/requires Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/store/fncache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,3 @@ +data/a.i +data/.hgsub.i +data/.hgsubstate.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/tags.cache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,2 @@ +1 34017377d9c3d7bbcf665f845cce1e41c30bf4e9 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/undo.branch Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/undo.desc Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,2 @@ +3 +commit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/last-message.txt Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/requires Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/store/fncache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +data/b.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/undo.branch Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/last-message.txt Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/requires Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/store/fncache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,1 @@ +data/c.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/tags.cache Fri Dec 02 15:12:49 2011 +0300 @@ -0,0 +1,2 @@ +0 9e4a2fef1a1c04623a0d89edb4f3ba290cf2666e +