Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgRepository.java @ 493:ba36f66c32b4
Refactor to keep knowledge about repository control files and their location in respect to .hg/ in a single place (facilitate future adoption of shared repositories)
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 18 Oct 2012 18:36:13 +0200 |
parents | 4a670f76e7d1 |
children | d2f6ab541330 |
comparison
equal
deleted
inserted
replaced
492:e4eaa23e3442 | 493:ba36f66c32b4 |
---|---|
97 } | 97 } |
98 | 98 |
99 private final File repoDir; // .hg folder | 99 private final File repoDir; // .hg folder |
100 private final File workingDir; // .hg/../ | 100 private final File workingDir; // .hg/../ |
101 private final String repoLocation; | 101 private final String repoLocation; |
102 private final PathRewrite normalizePath; // normalized slashes but otherwise regular file names | 102 /* |
103 private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled | 103 * normalized slashes but otherwise regular file names |
104 private final PathRewrite repoPathHelper; // access to system files | 104 * the only front-end path rewrite, kept here as rest of the library shall |
105 * not bother with names normalization. | |
106 */ | |
107 private final PathRewrite normalizePath; | |
105 private final SessionContext sessionContext; | 108 private final SessionContext sessionContext; |
106 | 109 |
107 private HgChangelog changelog; | 110 private HgChangelog changelog; |
108 private HgManifest manifest; | 111 private HgManifest manifest; |
109 private HgTags tags; | 112 private HgTags tags; |
129 | 132 |
130 HgRepository(String repositoryPath) { | 133 HgRepository(String repositoryPath) { |
131 repoDir = null; | 134 repoDir = null; |
132 workingDir = null; | 135 workingDir = null; |
133 repoLocation = repositoryPath; | 136 repoLocation = repositoryPath; |
134 dataPathHelper = repoPathHelper = null; | |
135 normalizePath = null; | 137 normalizePath = null; |
136 sessionContext = null; | 138 sessionContext = null; |
137 impl = null; | 139 impl = null; |
138 } | 140 } |
139 | 141 |
151 throw new IllegalArgumentException(repoDir.toString()); | 153 throw new IllegalArgumentException(repoDir.toString()); |
152 } | 154 } |
153 repoLocation = repositoryPath; | 155 repoLocation = repositoryPath; |
154 sessionContext = ctx; | 156 sessionContext = ctx; |
155 impl = new org.tmatesoft.hg.internal.Internals(this, repositoryRoot); | 157 impl = new org.tmatesoft.hg.internal.Internals(this, repositoryRoot); |
156 impl.parseRequires(); | |
157 normalizePath = impl.buildNormalizePathRewrite(); | 158 normalizePath = impl.buildNormalizePathRewrite(); |
158 dataPathHelper = impl.buildDataFilesHelper(); | |
159 repoPathHelper = impl.buildRepositoryFilesHelper(); | |
160 } | 159 } |
161 | 160 |
162 @Override | 161 @Override |
163 public String toString() { | 162 public String toString() { |
164 return getClass().getSimpleName() + "[" + getLocation() + (isInvalid() ? "(BAD)" : "") + "]"; | 163 return getClass().getSimpleName() + "[" + getLocation() + (isInvalid() ? "(BAD)" : "") + "]"; |
183 return impl == null || impl.isInvalid(); | 182 return impl == null || impl.isInvalid(); |
184 } | 183 } |
185 | 184 |
186 public HgChangelog getChangelog() { | 185 public HgChangelog getChangelog() { |
187 if (changelog == null) { | 186 if (changelog == null) { |
188 CharSequence storagePath = repoPathHelper.rewrite("00changelog.i"); | 187 File chlogFile = impl.getFileFromStoreDir("00changelog.i"); |
189 RevlogStream content = resolve(Path.create(storagePath), true); | 188 if (!chlogFile.exists()) { |
189 // fake its existence | |
190 chlogFile = fakeNonExistentFile(chlogFile); | |
191 } | |
192 RevlogStream content = new RevlogStream(impl.getDataAccess(), chlogFile); | |
190 changelog = new HgChangelog(this, content); | 193 changelog = new HgChangelog(this, content); |
191 } | 194 } |
192 return changelog; | 195 return changelog; |
193 } | 196 } |
194 | 197 |
195 public HgManifest getManifest() { | 198 public HgManifest getManifest() { |
196 if (manifest == null) { | 199 if (manifest == null) { |
197 RevlogStream content = resolve(Path.create(repoPathHelper.rewrite("00manifest.i")), true); | 200 File manifestFile = impl.getFileFromStoreDir("00manifest.i"); |
201 if (!manifestFile.exists()) { | |
202 manifestFile = fakeNonExistentFile(manifestFile); | |
203 } | |
204 RevlogStream content = new RevlogStream(impl.getDataAccess(), manifestFile); | |
198 manifest = new HgManifest(this, content, impl.buildFileNameEncodingHelper()); | 205 manifest = new HgManifest(this, content, impl.buildFileNameEncodingHelper()); |
199 } | 206 } |
200 return manifest; | 207 return manifest; |
201 } | 208 } |
202 | 209 |
265 return mergeState; | 272 return mergeState; |
266 } | 273 } |
267 | 274 |
268 public HgDataFile getFileNode(String path) { | 275 public HgDataFile getFileNode(String path) { |
269 CharSequence nPath = normalizePath.rewrite(path); | 276 CharSequence nPath = normalizePath.rewrite(path); |
270 CharSequence storagePath = dataPathHelper.rewrite(nPath); | |
271 RevlogStream content = resolve(Path.create(storagePath), false); | |
272 Path p = Path.create(nPath); | 277 Path p = Path.create(nPath); |
273 if (content == null) { | 278 return getFileNode(p); |
274 return new HgDataFile(this, p); | |
275 } | |
276 return new HgDataFile(this, p, content); | |
277 } | 279 } |
278 | 280 |
279 public HgDataFile getFileNode(Path path) { | 281 public HgDataFile getFileNode(Path path) { |
280 CharSequence storagePath = dataPathHelper.rewrite(path.toString()); | 282 RevlogStream content = resolveStoreFile(path); |
281 RevlogStream content = resolve(Path.create(storagePath), false); | |
282 // XXX no content when no file? or HgDataFile.exists() to detect that? | |
283 if (content == null) { | 283 if (content == null) { |
284 return new HgDataFile(this, path); | 284 return new HgDataFile(this, path); |
285 } | 285 } |
286 return new HgDataFile(this, path, content); | 286 return new HgDataFile(this, path, content); |
287 } | 287 } |
343 return new HgRepoConfig(new ConfigFile(getSessionContext())); // empty config, do not cache, allow to try once again | 343 return new HgRepoConfig(new ConfigFile(getSessionContext())); // empty config, do not cache, allow to try once again |
344 //throw new HgInvalidControlFileException(m, ex, null); | 344 //throw new HgInvalidControlFileException(m, ex, null); |
345 } | 345 } |
346 } | 346 } |
347 return repoConfig; | 347 return repoConfig; |
348 } | |
349 | |
350 // shall be of use only for internal classes | |
351 /*package-local*/ File getRepositoryRoot() { | |
352 return repoDir; | |
353 } | |
354 | |
355 /*package-local, debug*/String getStoragePath(HgDataFile df) { | |
356 // may come handy for debug | |
357 return dataPathHelper.rewrite(df.getPath().toString()).toString(); | |
358 } | 348 } |
359 | 349 |
360 // XXX package-local, unless there are cases when required from outside (guess, working dir/revision walkers may hide dirstate access and no public visibility needed) | 350 // XXX package-local, unless there are cases when required from outside (guess, working dir/revision walkers may hide dirstate access and no public visibility needed) |
361 // XXX consider passing Path pool or factory to produce (shared) Path instead of Strings | 351 // XXX consider passing Path pool or factory to produce (shared) Path instead of Strings |
362 /*package-local*/ final HgDirstate loadDirstate(Path.Source pathFactory) throws HgInvalidControlFileException { | 352 /*package-local*/ final HgDirstate loadDirstate(Path.Source pathFactory) throws HgInvalidControlFileException { |
457 | 447 |
458 @Experimental(reason="WORK IN PROGRESS") | 448 @Experimental(reason="WORK IN PROGRESS") |
459 public HgRepositoryLock getStoreLock() { | 449 public HgRepositoryLock getStoreLock() { |
460 if (storeLock == null) { | 450 if (storeLock == null) { |
461 int timeout = getLockTimeout(); | 451 int timeout = getLockTimeout(); |
462 File fl = impl.getFileFromRepoDir(repoPathHelper.rewrite("lock").toString()); | 452 File fl = impl.getFileFromStoreDir("lock"); |
463 synchronized (this) { | 453 synchronized (this) { |
464 if (storeLock == null) { | 454 if (storeLock == null) { |
465 storeLock = new HgRepositoryLock(fl, timeout); | 455 storeLock = new HgRepositoryLock(fl, timeout); |
466 } | 456 } |
467 } | 457 } |
489 return sessionContext; | 479 return sessionContext; |
490 } | 480 } |
491 | 481 |
492 /** | 482 /** |
493 * Perhaps, should be separate interface, like ContentLookup | 483 * Perhaps, should be separate interface, like ContentLookup |
494 * path - repository storage path (i.e. one usually with .i or .d) | 484 * @param path - normalized file name |
495 */ | 485 * @return <code>null</code> if path doesn't resolve to a existing file |
496 /*package-local*/ RevlogStream resolve(Path path, boolean shallFakeNonExistent) { | 486 */ |
487 /*package-local*/ RevlogStream resolveStoreFile(Path path) { | |
497 final SoftReference<RevlogStream> ref = streamsCache.get(path); | 488 final SoftReference<RevlogStream> ref = streamsCache.get(path); |
498 RevlogStream cached = ref == null ? null : ref.get(); | 489 RevlogStream cached = ref == null ? null : ref.get(); |
499 if (cached != null) { | 490 if (cached != null) { |
500 return cached; | 491 return cached; |
501 } | 492 } |
502 File f = new File(repoDir, path.toString()); | 493 File f = impl.getFileFromDataDir(path); |
503 if (f.exists()) { | 494 if (f.exists()) { |
504 RevlogStream s = new RevlogStream(impl.getDataAccess(), f); | 495 RevlogStream s = new RevlogStream(impl.getDataAccess(), f); |
505 if (impl.shallCacheRevlogs()) { | 496 if (impl.shallCacheRevlogs()) { |
506 streamsCache.put(path, new SoftReference<RevlogStream>(s)); | 497 streamsCache.put(path, new SoftReference<RevlogStream>(s)); |
507 } | 498 } |
508 return s; | 499 return s; |
509 } else { | 500 } |
510 if (shallFakeNonExistent) { | 501 return null; |
511 try { | 502 } |
512 File fake = File.createTempFile(f.getName(), null); | 503 |
513 fake.deleteOnExit(); | 504 private File fakeNonExistentFile(File expected) throws HgInvalidFileException { |
514 return new RevlogStream(impl.getDataAccess(), fake); | 505 try { |
515 } catch (IOException ex) { | 506 File fake = File.createTempFile(expected.getName(), null); |
516 getSessionContext().getLog().dump(getClass(), Info, ex, null); | 507 fake.deleteOnExit(); |
517 } | 508 return fake; |
518 } | 509 } catch (IOException ex) { |
519 } | 510 getSessionContext().getLog().dump(getClass(), Info, ex, null); |
520 return null; // XXX empty stream instead? | 511 throw new HgInvalidFileException(String.format("Failed to fake existence of file %s", expected), ex); |
512 } | |
521 } | 513 } |
522 | 514 |
523 /*package-local*/ List<Filter> getFiltersFromRepoToWorkingDir(Path p) { | 515 /*package-local*/ List<Filter> getFiltersFromRepoToWorkingDir(Path p) { |
524 return instantiateFilters(p, new Filter.Options(Filter.Direction.FromRepo)); | 516 return instantiateFilters(p, new Filter.Options(Filter.Direction.FromRepo)); |
525 } | 517 } |