Mercurial > hg > mercurial
view mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java @ 16:7aa397165fa0
identify command added, test connection now uses identify command
author | Pavel.Sher |
---|---|
date | Wed, 16 Jul 2008 01:26:07 +0400 |
parents | 26505742bae5 |
children | 21b5b1c5dd74 |
line wrap: on
line source
package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.CollectChangesByIncludeRule; import jetbrains.buildServer.Used; import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; import jetbrains.buildServer.log.Loggers; import jetbrains.buildServer.serverSide.InvalidProperty; import jetbrains.buildServer.serverSide.PropertiesProcessor; import jetbrains.buildServer.serverSide.ServerPaths; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.*; import jetbrains.buildServer.vcs.patches.PatchBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.util.*; public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule { private ServerPaths myServerPaths; public MercurialVcsSupport(@NotNull VcsManager vcsManager, @NotNull ServerPaths paths) { vcsManager.registerVcsSupport(this); myServerPaths = paths; } public List<ModificationData> collectBuildChanges(final VcsRoot root, @NotNull final String fromVersion, @NotNull final String currentVersion, final CheckoutRules checkoutRules) throws VcsException { updateWorkingDirectory(root); return VcsSupportUtil.collectBuildChanges(root, fromVersion, currentVersion, checkoutRules, this); } public List<ModificationData> collectBuildChanges(final VcsRoot root, final String fromVersion, final String currentVersion, final IncludeRule includeRule) throws VcsException { List<ModificationData> result = new ArrayList<ModificationData>(); Settings settings = new Settings(myServerPaths, root); LogCommand lc = new LogCommand(settings); lc.setFromRevId(new ChangeSet(fromVersion).getId()); lc.setToRevId(new ChangeSet(currentVersion).getId()); List<ChangeSet> changeSets = lc.execute(); if (changeSets.isEmpty()) { return result; } Iterator<ChangeSet> it = changeSets.iterator(); ChangeSet prev = it.next(); // skip first changeset (cause it was already reported) StatusCommand st = new StatusCommand(settings); while (it.hasNext()) { ChangeSet cur = it.next(); st.setFromRevId(prev.getId()); st.setToRevId(cur.getId()); List<ModifiedFile> modifiedFiles = st.execute(); List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), includeRule); if (files.isEmpty()) continue; ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getSummary(), cur.getUser(), root, cur.getFullVersion(), cur.getFullVersion()); result.add(md); prev = cur; } return result; } private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, final IncludeRule includeRule) { List<VcsChange> files = new ArrayList<VcsChange>(); for (ModifiedFile mf: modifiedFiles) { String normalizedPath = normalizePath(mf.getPath()); if (!normalizedPath.startsWith(includeRule.getFrom())) continue; // skip files which do not match include rule VcsChangeInfo.Type changeType = getChangeType(mf.getStatus()); if (changeType == null) { Loggers.VCS.warn("Unable to convert status: " + mf.getStatus() + " to VCS change type"); changeType = VcsChangeInfo.Type.NOT_CHANGED; } files.add(new VcsChange(changeType, mf.getStatus().getName(), normalizedPath, normalizedPath, prevVer, curVer)); } return files; } private @NotNull String normalizePath(@NotNull String repPath) { return repPath.replace('\\', '/'); } private VcsChangeInfo.Type getChangeType(final ModifiedFile.Status status) { switch (status) { case ADDED:return VcsChangeInfo.Type.ADDED; case MODIFIED:return VcsChangeInfo.Type.CHANGED; case REMOVED:return VcsChangeInfo.Type.REMOVED; } return null; } @NotNull public byte[] getContent(final VcsModification vcsModification, final VcsChangeInfo change, final VcsChangeInfo.ContentType contentType, final VcsRoot vcsRoot) throws VcsException { updateWorkingDirectory(vcsRoot); String version = contentType == VcsChangeInfo.ContentType.AFTER_CHANGE ? change.getAfterChangeRevisionNumber() : change.getBeforeChangeRevisionNumber(); return getContent(change.getRelativeFileName(), vcsRoot, version); } @NotNull public byte[] getContent(final String filePath, final VcsRoot vcsRoot, final String version) throws VcsException { updateWorkingDirectory(vcsRoot); Settings settings = new Settings(myServerPaths, vcsRoot); CatCommand cc = new CatCommand(settings); ChangeSet cs = new ChangeSet(version); cc.setRevId(cs.getId()); File parentDir = cc.execute(Collections.singletonList(filePath)); File file = new File(parentDir, filePath); if (file.isFile()) { try { return FileUtil.loadFileBytes(file); } catch (IOException e) { throw new VcsException("Failed to load content of file: " + file.getAbsolutePath(), e); } } else { Loggers.VCS.warn("Unable to obtain content of the file: " + filePath); } return new byte[0]; } public String getName() { return "mercurial"; } @Used("jsp") public String getDisplayName() { return "Mercurial"; } @Nullable public PropertiesProcessor getVcsPropertiesProcessor() { return new AbstractVcsPropertiesProcessor() { public Collection<InvalidProperty> process(final Map<String, String> properties) { 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")); } return result; } }; } public String getVcsSettingsJspFilePath() { return "mercurialSettings.jsp"; } @NotNull public String getCurrentVersion(final VcsRoot root) throws VcsException { updateWorkingDirectory(root); Settings settings = new Settings(myServerPaths, root); TipCommand lc = new TipCommand(settings); ChangeSet changeSet = lc.execute(); return changeSet.getFullVersion(); } public String describeVcsRoot(final VcsRoot vcsRoot) { return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP); } public boolean isTestConnectionSupported() { return true; } @Nullable public String testConnection(final VcsRoot vcsRoot) throws VcsException { Settings settings = new Settings(myServerPaths, vcsRoot); IdentifyCommand id = new IdentifyCommand(settings); StringBuilder res = new StringBuilder(); res.append("hg identify " + settings.getRepository()); res.append('\n').append(id.execute()); return res.toString(); } @Nullable public Map<String, String> getDefaultVcsProperties() { return null; } public String getVersionDisplayName(final String version, final VcsRoot root) throws VcsException { return version; } @NotNull public Comparator<String> getVersionComparator() { return new Comparator<String>() { public int compare(final String o1, final String o2) { try { return new ChangeSet(o1).getRevNumber() - new ChangeSet(o2).getRevNumber(); } catch (Exception e) { return 1; } } }; } public void buildPatch(final VcsRoot root, @Nullable final String fromVersion, @NotNull final String toVersion, final PatchBuilder builder, final CheckoutRules checkoutRules) throws IOException, VcsException { updateWorkingDirectory(root); Settings settings = new Settings(myServerPaths, root); if (fromVersion == null) { buildFullPatch(settings, new ChangeSet(toVersion), builder); } else { buildIncrementalPatch(settings, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder); } } private void buildIncrementalPatch(final Settings settings, @NotNull final ChangeSet fromVer, @NotNull final ChangeSet toVer, final PatchBuilder builder) throws VcsException, IOException { StatusCommand st = new StatusCommand(settings); st.setFromRevId(fromVer.getId()); st.setToRevId(toVer.getId()); List<ModifiedFile> modifiedFiles = st.execute(); List<String> notDeletedFiles = new ArrayList<String>(); for (ModifiedFile f: modifiedFiles) { if (f.getStatus() != ModifiedFile.Status.REMOVED) { notDeletedFiles.add(f.getPath()); } } CatCommand cc = new CatCommand(settings); cc.setRevId(toVer.getId()); File parentDir = cc.execute(notDeletedFiles); try { for (ModifiedFile f: modifiedFiles) { final File virtualFile = new File(f.getPath()); if (f.getStatus() == ModifiedFile.Status.REMOVED) { builder.deleteFile(virtualFile, true); } else { File realFile = new File(parentDir, f.getPath()); FileInputStream is = new FileInputStream(realFile); try { builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length()); } finally { is.close(); } } } } finally { FileUtil.delete(parentDir); } } private void buildFullPatch(final Settings settings, @NotNull final ChangeSet toVer, final PatchBuilder builder) throws IOException, VcsException { CloneCommand cl = new CloneCommand(settings); cl.setToId(toVer.getId()); File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId()); try { final File repRoot = new File(tempDir, "rep"); cl.setDestDir(repRoot.getAbsolutePath()); cl.execute(); buildPatchFromDirectory(builder, repRoot, new FileFilter() { public boolean accept(final File file) { return !(file.isDirectory() && ".hg".equals(file.getName())); } }); } finally { FileUtil.delete(tempDir); } } private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException { buildPatchFromDirectory(repRoot, builder, repRoot, filter); } private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, 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()); final File virtualFile = new File(relPath); if (realFile.isDirectory()) { builder.createDirectory(virtualFile); buildPatchFromDirectory(realFile, builder, repRoot, filter); } else { final FileInputStream is = new FileInputStream(realFile); try { builder.createBinaryFile(virtualFile, null, is, realFile.length()); } finally { is.close(); } } } } } private void updateWorkingDirectory(final VcsRoot root) throws VcsException { Settings settings = new Settings(myServerPaths, root); String workDir = settings.getWorkingDir(); synchronized (root) { if (hasRepositoryCopy(new File(workDir))) { // update PullCommand pull = new PullCommand(settings); pull.execute(); } else { // clone CloneCommand cl = new CloneCommand(settings); cl.setDestDir(workDir); cl.execute(); } } } private boolean hasRepositoryCopy(final File workDir) { return workDir.isDirectory() && new File(workDir, ".hg").isDirectory(); } }