1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.aragost.javahg;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.nio.charset.CharsetDecoder;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.concurrent.ExecutionException;
34
35 import com.aragost.javahg.RepositoryConfiguration.CachePolicy;
36 import com.aragost.javahg.commands.HeadsCommand;
37 import com.aragost.javahg.commands.LogCommand;
38 import com.aragost.javahg.internals.GenericCommand;
39 import com.aragost.javahg.internals.GenericLogCommand;
40 import com.aragost.javahg.internals.HgInputStream;
41 import com.aragost.javahg.internals.RuntimeIOException;
42 import com.aragost.javahg.internals.ServerPool;
43 import com.aragost.javahg.internals.Utils;
44 import com.google.common.cache.CacheBuilder;
45 import com.google.common.cache.CacheLoader;
46 import com.google.common.cache.CacheStats;
47 import com.google.common.cache.LoadingCache;
48 import com.google.common.collect.Maps;
49
50
51
52
53 public abstract class Repository {
54
55 private final LoadingCache<String, Changeset> changesetCache;
56
57 protected Repository(CachePolicy cachePolicy) {
58 this.changesetCache = createCache(cachePolicy);
59 }
60
61
62
63
64
65
66
67
68 public static BaseRepository open(RepositoryConfiguration conf, File mercurialRepository) {
69 return new BaseRepository(conf, mercurialRepository, false, null);
70 }
71
72
73
74
75
76
77
78
79
80 public static BaseRepository create(RepositoryConfiguration conf, File directory) {
81 return new BaseRepository(conf, directory, true, null);
82 }
83
84
85
86
87
88
89
90
91
92
93 public static BaseRepository clone(RepositoryConfiguration conf, File directory, String otherRepoUrl) {
94 return new BaseRepository(conf, directory, false, otherRepoUrl);
95 }
96
97
98
99
100
101
102
103
104
105 public static BaseRepository open(File mercurialRepository) {
106 return new BaseRepository(RepositoryConfiguration.DEFAULT, mercurialRepository, false, null);
107 }
108
109
110
111
112
113
114
115
116
117 public static BaseRepository create(File directory) {
118 return new BaseRepository(RepositoryConfiguration.DEFAULT, directory, true, null);
119 }
120
121
122
123
124
125
126
127
128
129
130
131 public static BaseRepository clone(File directory, String otherRepoUrl) {
132 return new BaseRepository(RepositoryConfiguration.DEFAULT, directory, false, otherRepoUrl);
133 }
134
135
136
137
138
139
140
141
142 @Deprecated
143 public final Changeset changeSet(String node) {
144 return changeset(node);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public final Changeset changeset(String node) {
160 if (node.equals(Changeset.NULL_ID)) {
161 return null;
162 } else {
163 try {
164 return basicChangeset(node);
165 } catch (ExecutionException e) {
166 throw Utils.asRuntime(e);
167 }
168 }
169 }
170
171
172
173
174
175
176
177
178 protected Changeset basicChangeset(String node) throws ExecutionException {
179 return this.changesetCache.get(node);
180 }
181
182
183
184
185 public abstract ServerPool getServerPool();
186
187
188
189
190 public abstract CharsetDecoder newDecoder();
191
192
193
194
195
196 public void close() {
197 getServerPool().decrementRefCount();
198 }
199
200
201
202
203 public abstract File getDirectory();
204
205 public abstract BaseRepository getBaseRepository();
206
207 @Override
208 public String toString() {
209 return "repo@" + getDirectory();
210 }
211
212
213
214
215
216
217
218 public void addToCommandLine(List<String> commandLine) {
219 String sshBin = getBaseRepository().getConfiguration().getSshBin();
220 if (sshBin != null) {
221 commandLine.add("--config");
222 commandLine.add("ui.ssh=" + sshBin);
223 }
224 }
225
226
227
228
229 public HgVersion getHgVersion() {
230 return getServerPool().getHgVersion(this);
231 }
232
233
234
235
236
237
238 public WorkingCopy workingCopy() {
239 return new WorkingCopy(this);
240 }
241
242
243
244
245
246 public List<Changeset> heads() {
247 return HeadsCommand.on(this).execute();
248 }
249
250
251
252
253
254
255
256 @Deprecated
257 public Map<Changeset, Phase> readPhases(String... revs) {
258 return phases(revs);
259 }
260
261
262
263
264
265
266
267 public Map<Changeset, Phase> phases(String... revs) {
268 GenericLogCommand cmd = new GenericLogCommand(this).template("{node} {phase}\\0");
269 cmd.rev(revs);
270 HgInputStream stream = cmd.stream();
271 Map<Changeset, Phase> result = Maps.newHashMap();
272 try {
273 while (!stream.isEof()) {
274
275
276
277
278 String node = stream.textUpTo(' ');
279
280 while ("removing".equals(node) && stream.find('\n')) {
281 node = stream.textUpTo(' ');
282 }
283
284 String phaseName = stream.textUpTo('\0');
285 Phase phase = Phase.fromText(phaseName);
286 result.put(changeset(node), phase);
287 }
288 } catch (IOException e) {
289 throw new RuntimeIOException(e);
290 } finally {
291 try {
292 stream.consumeAll();
293 } catch (IOException e) {
294 throw new RuntimeIOException(e);
295 }
296 }
297
298 return result;
299 }
300
301
302
303
304
305 public Changeset tip() {
306 List<Changeset> changesets = LogCommand.on(this).rev("tip").execute();
307 return Utils.single(changesets);
308 }
309
310
311
312
313
314
315
316
317
318
319 public File relativeFile(File file) {
320 if (file.isAbsolute()) {
321 String filePath = Utils.resolveSymlinks(file).getPath();
322 String repoPath = getDirectory().getPath() + File.separator;
323 if (filePath.startsWith(repoPath)) {
324 return new File(filePath.substring(repoPath.length()));
325 } else {
326 throw new IllegalArgumentException("" + file + " is not under root of repository");
327 }
328 } else {
329 return file;
330 }
331 }
332
333
334
335
336
337
338
339
340 public File file(String name) {
341 return new File(getDirectory(), name);
342 }
343
344 public void lock() {
345 GenericCommand lock = new GenericCommand(this, "javahg-lock");
346 lock.execute();
347 }
348
349 public void unlock() {
350 GenericCommand unlock = new GenericCommand(this, "javahg-unlock");
351 unlock.execute();
352 }
353
354 private LoadingCache<String, Changeset> createCache(CachePolicy cachePolicy) {
355 CacheLoader<String, Changeset> cacheLoader = new CacheLoader<String, Changeset>() {
356 @Override
357 public Changeset load(String key) throws Exception {
358 return new Changeset(Repository.this, key);
359 }
360 };
361 CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
362 switch (cachePolicy) {
363 case STRONG:
364 break;
365 case SOFT:
366 cacheBuilder.softValues();
367 break;
368 case WEAK:
369 cacheBuilder.weakValues();
370 break;
371 case NONE:
372
373 cacheBuilder.maximumSize(0);
374 break;
375 }
376 return cacheBuilder.build(cacheLoader);
377 }
378
379 protected LoadingCache<String, Changeset> getChangesetCache() {
380 return changesetCache;
381 }
382
383 protected Changeset getChangesetIfInCache(String node) {
384 return this.changesetCache.getIfPresent(node);
385 }
386
387 public CacheStats getCacheStats() {
388 return this.changesetCache.stats();
389 }
390
391 }