Mercurial > hg > mercurial
annotate mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java @ 17:21b5b1c5dd74
test connection minor fix
author | Pavel.Sher |
---|---|
date | Wed, 16 Jul 2008 01:37:35 +0400 |
parents | 7aa397165fa0 |
children | d787c696225c |
rev | line source |
---|---|
0 | 1 package jetbrains.buildServer.buildTriggers.vcs.mercurial; |
2 | |
3 import jetbrains.buildServer.CollectChangesByIncludeRule; | |
4 import jetbrains.buildServer.Used; | |
5 import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor; | |
6 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; | |
7 import jetbrains.buildServer.log.Loggers; | |
8 import jetbrains.buildServer.serverSide.InvalidProperty; | |
9 import jetbrains.buildServer.serverSide.PropertiesProcessor; | |
10 import jetbrains.buildServer.serverSide.ServerPaths; | |
11 import jetbrains.buildServer.util.FileUtil; | |
12 import jetbrains.buildServer.vcs.*; | |
13 import jetbrains.buildServer.vcs.patches.PatchBuilder; | |
14 import org.jetbrains.annotations.NotNull; | |
15 import org.jetbrains.annotations.Nullable; | |
16 | |
1 | 17 import java.io.File; |
18 import java.io.FileFilter; | |
19 import java.io.FileInputStream; | |
20 import java.io.IOException; | |
21 import java.util.*; | |
22 | |
0 | 23 public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule { |
24 private ServerPaths myServerPaths; | |
25 | |
26 public MercurialVcsSupport(@NotNull VcsManager vcsManager, @NotNull ServerPaths paths) { | |
27 vcsManager.registerVcsSupport(this); | |
28 myServerPaths = paths; | |
29 } | |
30 | |
31 public List<ModificationData> collectBuildChanges(final VcsRoot root, | |
32 @NotNull final String fromVersion, | |
33 @NotNull final String currentVersion, | |
34 final CheckoutRules checkoutRules) throws VcsException { | |
35 updateWorkingDirectory(root); | |
36 return VcsSupportUtil.collectBuildChanges(root, fromVersion, currentVersion, checkoutRules, this); | |
37 } | |
38 | |
39 public List<ModificationData> collectBuildChanges(final VcsRoot root, | |
40 final String fromVersion, | |
41 final String currentVersion, | |
42 final IncludeRule includeRule) throws VcsException { | |
43 List<ModificationData> result = new ArrayList<ModificationData>(); | |
44 Settings settings = new Settings(myServerPaths, root); | |
45 LogCommand lc = new LogCommand(settings); | |
46 lc.setFromRevId(new ChangeSet(fromVersion).getId()); | |
47 lc.setToRevId(new ChangeSet(currentVersion).getId()); | |
48 List<ChangeSet> changeSets = lc.execute(); | |
49 if (changeSets.isEmpty()) { | |
50 return result; | |
51 } | |
52 | |
53 Iterator<ChangeSet> it = changeSets.iterator(); | |
54 ChangeSet prev = it.next(); // skip first changeset (cause it was already reported) | |
55 StatusCommand st = new StatusCommand(settings); | |
56 while (it.hasNext()) { | |
57 ChangeSet cur = it.next(); | |
58 st.setFromRevId(prev.getId()); | |
59 st.setToRevId(cur.getId()); | |
60 List<ModifiedFile> modifiedFiles = st.execute(); | |
61 List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), includeRule); | |
62 if (files.isEmpty()) continue; | |
63 ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getSummary(), cur.getUser(), root, cur.getFullVersion(), cur.getFullVersion()); | |
64 result.add(md); | |
65 prev = cur; | |
66 } | |
67 | |
68 return result; | |
69 } | |
70 | |
71 private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, final IncludeRule includeRule) { | |
72 List<VcsChange> files = new ArrayList<VcsChange>(); | |
73 for (ModifiedFile mf: modifiedFiles) { | |
12 | 74 String normalizedPath = normalizePath(mf.getPath()); |
75 if (!normalizedPath.startsWith(includeRule.getFrom())) continue; // skip files which do not match include rule | |
0 | 76 |
77 VcsChangeInfo.Type changeType = getChangeType(mf.getStatus()); | |
78 if (changeType == null) { | |
79 Loggers.VCS.warn("Unable to convert status: " + mf.getStatus() + " to VCS change type"); | |
80 changeType = VcsChangeInfo.Type.NOT_CHANGED; | |
81 } | |
12 | 82 files.add(new VcsChange(changeType, mf.getStatus().getName(), normalizedPath, normalizedPath, prevVer, curVer)); |
0 | 83 } |
84 return files; | |
85 } | |
86 | |
87 private @NotNull String normalizePath(@NotNull String repPath) { | |
88 return repPath.replace('\\', '/'); | |
89 } | |
90 | |
91 private VcsChangeInfo.Type getChangeType(final ModifiedFile.Status status) { | |
92 switch (status) { | |
93 case ADDED:return VcsChangeInfo.Type.ADDED; | |
94 case MODIFIED:return VcsChangeInfo.Type.CHANGED; | |
95 case REMOVED:return VcsChangeInfo.Type.REMOVED; | |
96 } | |
97 return null; | |
98 } | |
99 | |
100 @NotNull | |
101 public byte[] getContent(final VcsModification vcsModification, | |
102 final VcsChangeInfo change, | |
103 final VcsChangeInfo.ContentType contentType, | |
104 final VcsRoot vcsRoot) throws VcsException { | |
12 | 105 updateWorkingDirectory(vcsRoot); |
106 String version = contentType == VcsChangeInfo.ContentType.AFTER_CHANGE ? change.getAfterChangeRevisionNumber() : change.getBeforeChangeRevisionNumber(); | |
107 return getContent(change.getRelativeFileName(), vcsRoot, version); | |
0 | 108 } |
109 | |
110 @NotNull | |
12 | 111 public byte[] getContent(final String filePath, final VcsRoot vcsRoot, final String version) throws VcsException { |
112 updateWorkingDirectory(vcsRoot); | |
113 Settings settings = new Settings(myServerPaths, vcsRoot); | |
114 CatCommand cc = new CatCommand(settings); | |
115 ChangeSet cs = new ChangeSet(version); | |
116 cc.setRevId(cs.getId()); | |
117 File parentDir = cc.execute(Collections.singletonList(filePath)); | |
118 File file = new File(parentDir, filePath); | |
119 if (file.isFile()) { | |
120 try { | |
121 return FileUtil.loadFileBytes(file); | |
122 } catch (IOException e) { | |
123 throw new VcsException("Failed to load content of file: " + file.getAbsolutePath(), e); | |
124 } | |
125 } else { | |
126 Loggers.VCS.warn("Unable to obtain content of the file: " + filePath); | |
127 } | |
0 | 128 return new byte[0]; |
129 } | |
130 | |
131 public String getName() { | |
132 return "mercurial"; | |
133 } | |
134 | |
135 @Used("jsp") | |
136 public String getDisplayName() { | |
137 return "Mercurial"; | |
138 } | |
139 | |
140 @Nullable | |
141 public PropertiesProcessor getVcsPropertiesProcessor() { | |
142 return new AbstractVcsPropertiesProcessor() { | |
143 public Collection<InvalidProperty> process(final Map<String, String> properties) { | |
144 List<InvalidProperty> result = new ArrayList<InvalidProperty>(); | |
145 if (isEmpty(properties.get(Constants.HG_COMMAND_PATH_PROP))) { | |
146 result.add(new InvalidProperty(Constants.HG_COMMAND_PATH_PROP, "Path to 'hg' command must be specified")); | |
147 } | |
148 if (isEmpty(properties.get(Constants.REPOSITORY_PROP))) { | |
149 result.add(new InvalidProperty(Constants.REPOSITORY_PROP, "Repository must be specified")); | |
150 } | |
151 return result; | |
152 } | |
153 }; | |
154 } | |
155 | |
156 public String getVcsSettingsJspFilePath() { | |
157 return "mercurialSettings.jsp"; | |
158 } | |
159 | |
160 @NotNull | |
161 public String getCurrentVersion(final VcsRoot root) throws VcsException { | |
162 updateWorkingDirectory(root); | |
163 Settings settings = new Settings(myServerPaths, root); | |
9
7dadebd03515
use tip command instead of log in getCurrentVersion method
Pavel.Sher
parents:
8
diff
changeset
|
164 TipCommand lc = new TipCommand(settings); |
7dadebd03515
use tip command instead of log in getCurrentVersion method
Pavel.Sher
parents:
8
diff
changeset
|
165 ChangeSet changeSet = lc.execute(); |
0 | 166 return changeSet.getFullVersion(); |
167 } | |
168 | |
169 public String describeVcsRoot(final VcsRoot vcsRoot) { | |
170 return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP); | |
171 } | |
172 | |
173 public boolean isTestConnectionSupported() { | |
16
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
174 return true; |
0 | 175 } |
176 | |
177 @Nullable | |
178 public String testConnection(final VcsRoot vcsRoot) throws VcsException { | |
16
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
179 Settings settings = new Settings(myServerPaths, vcsRoot); |
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
180 IdentifyCommand id = new IdentifyCommand(settings); |
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
181 StringBuilder res = new StringBuilder(); |
17 | 182 res.append(quoteIfNeeded(settings.getHgCommandPath())); |
183 res.append(" identify "); | |
184 res.append(quoteIfNeeded(settings.getRepository())); | |
16
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
185 res.append('\n').append(id.execute()); |
7aa397165fa0
identify command added, test connection now uses identify command
Pavel.Sher
parents:
13
diff
changeset
|
186 return res.toString(); |
0 | 187 } |
188 | |
17 | 189 private String quoteIfNeeded(@NotNull String str) { |
190 if (str.indexOf(' ') != -1) { | |
191 return "\"" + str + "\""; | |
192 } | |
193 | |
194 return str; | |
195 } | |
196 | |
0 | 197 @Nullable |
198 public Map<String, String> getDefaultVcsProperties() { | |
199 return null; | |
200 } | |
201 | |
202 public String getVersionDisplayName(final String version, final VcsRoot root) throws VcsException { | |
203 return version; | |
204 } | |
205 | |
206 @NotNull | |
207 public Comparator<String> getVersionComparator() { | |
208 return new Comparator<String>() { | |
209 public int compare(final String o1, final String o2) { | |
210 try { | |
211 return new ChangeSet(o1).getRevNumber() - new ChangeSet(o2).getRevNumber(); | |
212 } catch (Exception e) { | |
213 return 1; | |
214 } | |
215 } | |
216 }; | |
217 } | |
218 | |
219 public void buildPatch(final VcsRoot root, | |
220 @Nullable final String fromVersion, | |
221 @NotNull final String toVersion, | |
222 final PatchBuilder builder, | |
223 final CheckoutRules checkoutRules) throws IOException, VcsException { | |
224 updateWorkingDirectory(root); | |
225 Settings settings = new Settings(myServerPaths, root); | |
226 if (fromVersion == null) { | |
227 buildFullPatch(settings, new ChangeSet(toVersion), builder); | |
228 } else { | |
229 buildIncrementalPatch(settings, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder); | |
230 } | |
231 } | |
232 | |
233 private void buildIncrementalPatch(final Settings settings, @NotNull final ChangeSet fromVer, @NotNull final ChangeSet toVer, final PatchBuilder builder) | |
234 throws VcsException, IOException { | |
235 StatusCommand st = new StatusCommand(settings); | |
236 st.setFromRevId(fromVer.getId()); | |
237 st.setToRevId(toVer.getId()); | |
238 List<ModifiedFile> modifiedFiles = st.execute(); | |
239 List<String> notDeletedFiles = new ArrayList<String>(); | |
240 for (ModifiedFile f: modifiedFiles) { | |
241 if (f.getStatus() != ModifiedFile.Status.REMOVED) { | |
242 notDeletedFiles.add(f.getPath()); | |
243 } | |
244 } | |
245 | |
246 CatCommand cc = new CatCommand(settings); | |
247 cc.setRevId(toVer.getId()); | |
248 File parentDir = cc.execute(notDeletedFiles); | |
249 | |
250 try { | |
251 for (ModifiedFile f: modifiedFiles) { | |
252 final File virtualFile = new File(f.getPath()); | |
253 if (f.getStatus() == ModifiedFile.Status.REMOVED) { | |
254 builder.deleteFile(virtualFile, true); | |
255 } else { | |
256 File realFile = new File(parentDir, f.getPath()); | |
257 FileInputStream is = new FileInputStream(realFile); | |
258 try { | |
11 | 259 builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length()); |
0 | 260 } finally { |
261 is.close(); | |
262 } | |
263 } | |
264 } | |
265 } finally { | |
266 FileUtil.delete(parentDir); | |
267 } | |
268 } | |
269 | |
270 private void buildFullPatch(final Settings settings, @NotNull final ChangeSet toVer, final PatchBuilder builder) | |
271 throws IOException, VcsException { | |
272 CloneCommand cl = new CloneCommand(settings); | |
273 cl.setToId(toVer.getId()); | |
274 File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId()); | |
275 try { | |
276 final File repRoot = new File(tempDir, "rep"); | |
277 cl.setDestDir(repRoot.getAbsolutePath()); | |
278 cl.execute(); | |
279 buildPatchFromDirectory(builder, repRoot, new FileFilter() { | |
280 public boolean accept(final File file) { | |
281 return !(file.isDirectory() && ".hg".equals(file.getName())); | |
282 } | |
283 }); | |
284 } finally { | |
285 FileUtil.delete(tempDir); | |
286 } | |
287 } | |
288 | |
289 private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException { | |
290 buildPatchFromDirectory(repRoot, builder, repRoot, filter); | |
291 } | |
292 | |
293 private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException { | |
294 File[] files = curDir.listFiles(filter); | |
295 if (files != null) { | |
296 for (File realFile: files) { | |
297 String relPath = realFile.getAbsolutePath().substring(repRoot.getAbsolutePath().length()); | |
298 final File virtualFile = new File(relPath); | |
299 if (realFile.isDirectory()) { | |
300 builder.createDirectory(virtualFile); | |
301 buildPatchFromDirectory(realFile, builder, repRoot, filter); | |
302 } else { | |
303 final FileInputStream is = new FileInputStream(realFile); | |
304 try { | |
305 builder.createBinaryFile(virtualFile, null, is, realFile.length()); | |
306 } finally { | |
307 is.close(); | |
308 } | |
309 } | |
310 } | |
311 } | |
312 } | |
313 | |
314 private void updateWorkingDirectory(final VcsRoot root) throws VcsException { | |
315 Settings settings = new Settings(myServerPaths, root); | |
316 String workDir = settings.getWorkingDir(); | |
317 synchronized (root) { | |
318 if (hasRepositoryCopy(new File(workDir))) { | |
319 // update | |
8 | 320 PullCommand pull = new PullCommand(settings); |
321 pull.execute(); | |
0 | 322 } else { |
323 // clone | |
324 CloneCommand cl = new CloneCommand(settings); | |
325 cl.setDestDir(workDir); | |
326 cl.execute(); | |
327 } | |
328 } | |
329 } | |
330 | |
331 private boolean hasRepositoryCopy(final File workDir) { | |
332 return workDir.isDirectory() && new File(workDir, ".hg").isDirectory(); | |
333 } | |
334 | |
335 } |