changeset 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 e4eaa23e3442
children 2743641f2f12
files src/org/tmatesoft/hg/core/HgChangeset.java src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java src/org/tmatesoft/hg/internal/Internals.java src/org/tmatesoft/hg/internal/PhasesHelper.java src/org/tmatesoft/hg/internal/RepoInitializer.java src/org/tmatesoft/hg/internal/RequiresFile.java src/org/tmatesoft/hg/repo/HgInternals.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java src/org/tmatesoft/hg/repo/ext/MqManager.java test/org/tmatesoft/hg/test/TestPhases.java
diffstat 11 files changed, 172 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgChangeset.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/core/HgChangeset.java	Thu Oct 18 18:36:13 2012 +0200
@@ -24,6 +24,7 @@
 import org.tmatesoft.hg.internal.PhasesHelper;
 import org.tmatesoft.hg.repo.HgChangelog;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
+import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgPhase;
 import org.tmatesoft.hg.repo.HgInvalidStateException;
 import org.tmatesoft.hg.repo.HgRepository;
@@ -264,7 +265,7 @@
 			synchronized (shared) {
 				// ensure field is initialized only once 
 				if (shared.phaseHelper == null) {
-					shared.phaseHelper = new PhasesHelper(getRepo(), shared.parentHelper);
+					shared.phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(getRepo()), shared.parentHelper);
 				}
 			}
 		}
--- a/src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java	Thu Oct 18 18:36:13 2012 +0200
@@ -52,7 +52,7 @@
 	
 	public static HgUpdateConfigCommand forRepository(HgRepository hgRepo) {
 		// XXX HgRepository to implement SessionContext.Provider (with getContext())?
-		return new HgUpdateConfigCommand(hgRepo.getSessionContext(), new File(HgInternals.getRepositoryDir(hgRepo), "hgrc"));
+		return new HgUpdateConfigCommand(hgRepo.getSessionContext(), HgInternals.getImplementationRepo(hgRepo).getFileFromRepoDir("hgrc"));
 	}
 	
 	public static HgUpdateConfigCommand forUser(SessionContext ctx) {
--- a/src/org/tmatesoft/hg/internal/Internals.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/Internals.java	Thu Oct 18 18:36:13 2012 +0200
@@ -16,7 +16,6 @@
  */
 package org.tmatesoft.hg.internal;
 
-import static org.tmatesoft.hg.internal.RequiresFile.*;
 import static org.tmatesoft.hg.util.LogFacility.Severity.Error;
 
 import java.io.File;
@@ -31,7 +30,8 @@
 import java.util.StringTokenizer;
 
 import org.tmatesoft.hg.core.SessionContext;
-import org.tmatesoft.hg.repo.HgInvalidControlFileException;
+import org.tmatesoft.hg.repo.HgDataFile;
+import org.tmatesoft.hg.repo.HgRuntimeException;
 import org.tmatesoft.hg.repo.HgRepoConfig.ExtensionsSection;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.util.PathRewrite;
@@ -73,30 +73,67 @@
 	 */
 	public static final String CFG_PROPERTY_FS_FILENAME_ENCODING = "hg.fs.filename.encoding";
 	
-	private int requiresFlags = 0;
 	private List<Filter.Factory> filterFactories;
 	private final HgRepository repo;
 	private final File repoDir;
 	private final boolean isCaseSensitiveFileSystem;
 	private final boolean shallCacheRevlogsInRepo;
 	private final DataAccessProvider dataAccess;
+	
+	@SuppressWarnings("unused")
+	private final int requiresFlags;
 
-	public Internals(HgRepository hgRepo, File hgDir) {
+	private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled  
+	private final PathRewrite repoPathHelper; // access to system files (under .hg/store if requires has 'store' flag)
+
+	public Internals(HgRepository hgRepo, File hgDir) throws HgRuntimeException {
 		repo = hgRepo;
 		repoDir = hgDir;
 		isCaseSensitiveFileSystem = !runningOnWindows();
 		SessionContext ctx = repo.getSessionContext();
 		shallCacheRevlogsInRepo = new PropertyMarshal(ctx).getBoolean(CFG_PROPERTY_REVLOG_STREAM_CACHE, true);
 		dataAccess = new DataAccessProvider(ctx);
+		RepoInitializer repoInit = new RepoInitializer().initRequiresFromFile(repoDir);
+		requiresFlags = repoInit.getRequires();
+		dataPathHelper = repoInit.buildDataFilesHelper(getContext());
+		repoPathHelper = repoInit.buildStoreFilesHelper();
 	}
 	
 	public boolean isInvalid() {
 		return !repoDir.exists() || !repoDir.isDirectory();
 	}
 	
+	/**
+	 * Access files under ".hg/".
+	 * File not necessarily exists, this method is merely a factory for Files at specific, configuration-dependent location. 
+	 * 
+	 * @param name shall be normalized path
+	 */
 	public File getFileFromRepoDir(String name) {
 		return new File(repoDir, name);
 	}
+
+	/**
+	 * Access files under ".hg/store/" or ".hg/" depending on use of 'store' in requires.
+	 * File not necessarily exists, this method is merely a factory for Files at specific, configuration-dependent location.
+	 *  
+	 * @param name shall be normalized path
+	 */
+	public File getFileFromStoreDir(String name) {
+		CharSequence location = repoPathHelper.rewrite(name);
+		return new File(repoDir, location.toString());
+	}
+	
+	/**
+	 * Access files under ".hg/store/data", ".hg/store/dh/" or ".hg/data" according to settings in requires file.
+	 * File not necessarily exists, this method is merely a factory for Files at specific, configuration-dependent location.
+	 * 
+	 * @param name shall be normalized path, without .i or .d suffixes
+	 */
+	public File getFileFromDataDir(CharSequence path) {
+		CharSequence storagePath = dataPathHelper.rewrite(path);
+		return new File(repoDir, storagePath.toString());
+	}
 	
 	public SessionContext getContext() {
 		return repo.getSessionContext();
@@ -110,19 +147,6 @@
 		return dataAccess;
 	}
 
-	public void parseRequires() throws HgInvalidControlFileException {
-		File requiresFile =getFileFromRepoDir("requires");
-		try {
-			new RequiresFile().parse(this, requiresFile);
-		} catch (IOException ex) {
-			throw new HgInvalidControlFileException("Parse failed", ex, requiresFile);
-		}
-	}
-
-	public/*for tests, otherwise pkg*/ void setStorageConfig(int version, int flags) {
-		requiresFlags = flags;
-	}
-	
 	public PathRewrite buildNormalizePathRewrite() {
 		if (runningOnWindows()) {
 			return new WinToNixPathRewrite();
@@ -131,23 +155,6 @@
 		}
 	}
 
-	// XXX perhaps, should keep both fields right here, not in the HgRepository
-	public PathRewrite buildDataFilesHelper() {
-		return new RepoInitializer().setRequires(requiresFlags).buildDataFilesHelper(getContext());
-	}
-
-	public PathRewrite buildRepositoryFilesHelper() {
-		if ((requiresFlags & STORE) != 0) {
-			return new PathRewrite() {
-				public CharSequence rewrite(CharSequence path) {
-					return "store/" + path;
-				}
-			};
-		} else {
-			return new PathRewrite.Empty();
-		}
-	}
-
 	public List<Filter.Factory> getFilters() {
 		if (filterFactories == null) {
 			filterFactories = new ArrayList<Filter.Factory>();
@@ -192,6 +199,15 @@
 		}
 		return cs;
 	}
+	
+	/**
+	 * Access to mangled name of a file in repository storage, may come handy for debug.
+	 * @return mangled path of the repository file
+	 */
+	public CharSequence getStoragePath(HgDataFile df) {
+		return dataPathHelper.rewrite(df.getPath().toString());
+	}
+
 
 	public static boolean runningOnWindows() {
 		return System.getProperty("os.name").indexOf("Windows") != -1;
--- a/src/org/tmatesoft/hg/internal/PhasesHelper.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/PhasesHelper.java	Thu Oct 18 18:36:13 2012 +0200
@@ -33,7 +33,6 @@
 import org.tmatesoft.hg.core.HgChangeset;
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.repo.HgChangelog;
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
 import org.tmatesoft.hg.repo.HgParentChildMap;
 import org.tmatesoft.hg.repo.HgPhase;
@@ -50,24 +49,24 @@
  */
 public final class PhasesHelper {
 
-	private final HgRepository repo;
+	private final Internals repo;
 	private final HgParentChildMap<HgChangelog> parentHelper;
 	private Boolean repoSupporsPhases;
 	private List<Nodeid> draftPhaseRoots;
 	private List<Nodeid> secretPhaseRoots;
 	private RevisionDescendants[][] phaseDescendants = new RevisionDescendants[HgPhase.values().length][];
 
-	public PhasesHelper(HgRepository hgRepo) {
-		this(hgRepo, null);
+	public PhasesHelper(Internals internalRepo) {
+		this(internalRepo, null);
 	}
 
-	public PhasesHelper(HgRepository hgRepo, HgParentChildMap<HgChangelog> pw) {
-		repo = hgRepo;
+	public PhasesHelper(Internals internalRepo, HgParentChildMap<HgChangelog> pw) {
+		repo = internalRepo;
 		parentHelper = pw;
 	}
 	
 	public HgRepository getRepo() {
-		return repo;
+		return repo.getRepo();
 	}
 
 	public boolean isCapableOfPhases() throws HgInvalidControlFileException {
@@ -90,7 +89,7 @@
 		}
 		// csetRev is only used when parentHelper is available
 		if (parentHelper != null && (csetRev == null || csetRev.isNull())) {
-			csetRev = repo.getChangelog().getRevision(csetRevIndex);
+			csetRev = getRepo().getChangelog().getRevision(csetRevIndex);
 		}
 					
 		for (HgPhase phase : new HgPhase[] {HgPhase.Secret, HgPhase.Draft }) {
@@ -121,8 +120,7 @@
 	}
 
 	private Boolean readRoots() throws HgInvalidControlFileException {
-		// FIXME shall access phaseroots through HgRepository#repoPathHelper
-		File phaseroots = new File(HgInternals.getRepositoryDir(repo), "store/phaseroots");
+		File phaseroots = repo.getFileFromStoreDir("phaseroots");
 		BufferedReader br = null;
 		try {
 			if (!phaseroots.exists()) {
@@ -137,13 +135,13 @@
 					continue;
 				}
 				if (lc.length != 2) {
-					repo.getSessionContext().getLog().dump(getClass(), Warn, "Bad line in phaseroots:%s", line);
+					repo.getContext().getLog().dump(getClass(), Warn, "Bad line in phaseroots:%s", line);
 					continue;
 				}
 				int phaseIndex = Integer.parseInt(lc[0]);
 				Nodeid rootRev = Nodeid.fromAscii(lc[1]);
-				if (!repo.getChangelog().isKnown(rootRev)) {
-					repo.getSessionContext().getLog().dump(getClass(), Warn, "Phase(%d) root node %s doesn't exist in the repository, ignored.", phaseIndex, rootRev);
+				if (!getRepo().getChangelog().isKnown(rootRev)) {
+					repo.getContext().getLog().dump(getClass(), Warn, "Phase(%d) root node %s doesn't exist in the repository, ignored.", phaseIndex, rootRev);
 					continue;
 				}
 				HgPhase phase = HgPhase.parse(phaseIndex);
@@ -162,7 +160,7 @@
 				try {
 					br.close();
 				} catch (IOException ex) {
-					repo.getSessionContext().getLog().dump(getClass(), Info, ex, null);
+					repo.getContext().getLog().dump(getClass(), Info, ex, null);
 					// ignore the exception otherwise 
 				}
 			}
@@ -191,7 +189,7 @@
 		int[] roots = toIndexes(getPhaseRoots(phase));
 		RevisionDescendants[] rv = new RevisionDescendants[roots.length];
 		for (int i = 0; i < roots.length; i++) {
-			rv[i] = new RevisionDescendants(repo, roots[i]);
+			rv[i] = new RevisionDescendants(getRepo(), roots[i]);
 			rv[i].build();
 		}
 		return rv;
@@ -200,7 +198,7 @@
 	private int[] toIndexes(List<Nodeid> roots) throws HgInvalidControlFileException {
 		int[] rv = new int[roots.size()];
 		for (int i = 0; i < rv.length; i++) {
-			rv[i] = repo.getChangelog().getRevisionIndex(roots.get(i));
+			rv[i] = getRepo().getChangelog().getRevisionIndex(roots.get(i));
 		}
 		return rv;
 	}
--- a/src/org/tmatesoft/hg/internal/RepoInitializer.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/RepoInitializer.java	Thu Oct 18 18:36:13 2012 +0200
@@ -24,6 +24,7 @@
 import java.nio.charset.Charset;
 
 import org.tmatesoft.hg.core.SessionContext;
+import org.tmatesoft.hg.repo.HgInvalidControlFileException;
 import org.tmatesoft.hg.util.PathRewrite;
 
 /**
@@ -39,6 +40,16 @@
 	public RepoInitializer() {
 	}
 	
+	public RepoInitializer initRequiresFromFile(File repoDir) throws HgInvalidControlFileException {
+		File requiresFile = new File(repoDir, "requires"); // not #getFileFromRepoDir() just in case it gets modified later 
+		try {
+			int flags = new RequiresFile().parse(requiresFile);
+			return setRequires(flags);
+		} catch (IOException ex) {
+			throw new HgInvalidControlFileException("Parse failed", ex, requiresFile);
+		}
+	}
+	
 	public RepoInitializer setRequires(int flags) {
 		requiresFlags = flags;
 		return this;
@@ -48,9 +59,9 @@
 		return requiresFlags;
 	}
 
-	public void initEmptyRepository(File hgDir) throws IOException {
-		hgDir.mkdir();
-		FileOutputStream requiresFile = new FileOutputStream(new File(hgDir, "requires"));
+	public void initEmptyRepository(File repoDir) throws IOException {
+		repoDir.mkdirs();
+		FileOutputStream requiresFile = new FileOutputStream(new File(repoDir, "requires"));
 		StringBuilder sb = new StringBuilder(40);
 		sb.append("revlogv1\n");
 		if ((requiresFlags & STORE) != 0) {
@@ -64,7 +75,7 @@
 		}
 		requiresFile.write(sb.toString().getBytes());
 		requiresFile.close();
-		new File(hgDir, "store").mkdir(); // with that, hg verify says ok.
+		new File(repoDir, "store").mkdir(); // with that, hg verify says ok.
 	}
 
 	public PathRewrite buildDataFilesHelper(SessionContext ctx) {
@@ -72,4 +83,16 @@
 		// StoragePathHelper needs fine-grained control over char encoding, hence doesn't use EncodingHelper
 		return new StoragePathHelper((requiresFlags & STORE) != 0, (requiresFlags & FNCACHE) != 0, (requiresFlags & DOTENCODE) != 0, cs);
 	}
+
+	public PathRewrite buildStoreFilesHelper() {
+		if ((requiresFlags & STORE) != 0) {
+			return new PathRewrite() {
+				public CharSequence rewrite(CharSequence path) {
+					return "store/" + path;
+				}
+			};
+		} else {
+			return new PathRewrite.Empty();
+		}
+	}
 }
--- a/src/org/tmatesoft/hg/internal/RequiresFile.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/RequiresFile.java	Thu Oct 18 18:36:13 2012 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 TMate Software Ltd
+ * Copyright (c) 2011-2012 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,36 +28,43 @@
  * @author TMate Software Ltd.
  */
 public class RequiresFile {
-	public static final int STORE = 1;
-	public static final int FNCACHE = 2;
-	public static final int DOTENCODE = 4;
+	public static final int STORE 		= 1 << 0;
+	public static final int FNCACHE		= 1 << 1;
+	public static final int DOTENCODE	= 1 << 2;
+	public static final int REVLOGV0	= 1 << 31;
+	public static final int REVLOGV1	= 1 << 30;
 	
 	public RequiresFile() {
 	}
 
-	public void parse(Internals repoImpl, File requiresFile) throws IOException {
+	/**
+	 * Settings from requires file as bits
+	 */
+	public int parse(File requiresFile) throws IOException {
 		if (!requiresFile.exists()) {
-			return;
+			// TODO check what's going on in Mercurial if no requires exist
+			return 0;
 		}
 		BufferedReader br = null;
 		try {
-			boolean revlogv1 = false;
-			boolean store = false;
-			boolean fncache = false;
-			boolean dotencode = false;
 			br = new BufferedReader(new InputStreamReader(new FileInputStream(requiresFile)));
 			String line;
+			int flags = 0;
 			while ((line = br.readLine()) != null) {
-				revlogv1 |= "revlogv1".equals(line);
-				store |= "store".equals(line);
-				fncache |= "fncache".equals(line);
-				dotencode |= "dotencode".equals(line);
+				if ("revlogv1".equals(line)) {
+					flags |= REVLOGV1;
+				} else if ("store".equals(line)) {
+					flags |= STORE;
+				} else if ("fncache".equals(line)) {
+					flags |= FNCACHE;
+				} else if ("dotencode".equals(line)) {
+					flags |= DOTENCODE;
+				}
 			}
-			int flags = 0;
-			flags += store ? STORE : 0;
-			flags += fncache ? FNCACHE : 0;
-			flags += dotencode ? DOTENCODE : 0;
-			repoImpl.setStorageConfig(revlogv1 ? 1 : 0, flags);
+			if ((flags & REVLOGV1) == 0) {
+				flags |= REVLOGV0; // TODO check if there's no special flag for V0 indeed
+			}
+			return flags;
 		} finally {
 			if (br != null) {
 				br.close();
--- a/src/org/tmatesoft/hg/repo/HgInternals.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgInternals.java	Thu Oct 18 18:36:13 2012 +0200
@@ -88,11 +88,11 @@
 	public HgSubrepoLocation newSubrepo(Path loc, String src, Kind kind, Nodeid rev) {
 		return new HgSubrepoLocation(repo, loc, src, kind, rev);
 	}
+	
+	public static Internals getImplementationRepo(HgRepository hgRepo) {
+		return hgRepo.getImplHelper();
+	}
 
-	public static File getRepositoryDir(HgRepository hgRepo) {
-		return hgRepo.getRepositoryRoot();
-	}
-	
 	/**
 	 * @param source where to read definitions from
 	 * @param globPathRewrite <code>null</code> to use default, or pass an instance to override defaults
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Oct 18 18:36:13 2012 +0200
@@ -99,9 +99,12 @@
 	private final File repoDir; // .hg folder
 	private final File workingDir; // .hg/../
 	private final String repoLocation;
-	private final PathRewrite normalizePath; // normalized slashes but otherwise regular file names
-	private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled  
-	private final PathRewrite repoPathHelper; // access to system files
+	/*
+	 * normalized slashes but otherwise regular file names
+	 * the only front-end path rewrite, kept here as rest of the library shall
+	 * not bother with names normalization.
+	 */
+	private final PathRewrite normalizePath;
 	private final SessionContext sessionContext;
 
 	private HgChangelog changelog;
@@ -131,7 +134,6 @@
 		repoDir = null;
 		workingDir = null;
 		repoLocation = repositoryPath;
-		dataPathHelper = repoPathHelper = null;
 		normalizePath = null;
 		sessionContext = null;
 		impl = null;
@@ -153,10 +155,7 @@
 		repoLocation = repositoryPath;
 		sessionContext = ctx;
 		impl = new org.tmatesoft.hg.internal.Internals(this, repositoryRoot);
-		impl.parseRequires();
 		normalizePath = impl.buildNormalizePathRewrite(); 
-		dataPathHelper = impl.buildDataFilesHelper();
-		repoPathHelper = impl.buildRepositoryFilesHelper();
 	}
 
 	@Override
@@ -185,8 +184,12 @@
 	
 	public HgChangelog getChangelog() {
 		if (changelog == null) {
-			CharSequence storagePath = repoPathHelper.rewrite("00changelog.i");
-			RevlogStream content = resolve(Path.create(storagePath), true);
+			File chlogFile = impl.getFileFromStoreDir("00changelog.i");
+			if (!chlogFile.exists()) {
+				// fake its existence
+				chlogFile = fakeNonExistentFile(chlogFile);
+			}
+			RevlogStream content = new RevlogStream(impl.getDataAccess(), chlogFile);
 			changelog = new HgChangelog(this, content);
 		}
 		return changelog;
@@ -194,7 +197,11 @@
 	
 	public HgManifest getManifest() {
 		if (manifest == null) {
-			RevlogStream content = resolve(Path.create(repoPathHelper.rewrite("00manifest.i")), true);
+			File manifestFile = impl.getFileFromStoreDir("00manifest.i");
+			if (!manifestFile.exists()) {
+				manifestFile = fakeNonExistentFile(manifestFile);
+			}
+			RevlogStream content = new RevlogStream(impl.getDataAccess(), manifestFile);
 			manifest = new HgManifest(this, content, impl.buildFileNameEncodingHelper());
 		}
 		return manifest;
@@ -267,19 +274,12 @@
 	
 	public HgDataFile getFileNode(String path) {
 		CharSequence nPath = normalizePath.rewrite(path);
-		CharSequence storagePath = dataPathHelper.rewrite(nPath);
-		RevlogStream content = resolve(Path.create(storagePath), false);
 		Path p = Path.create(nPath);
-		if (content == null) {
-			return new HgDataFile(this, p);
-		}
-		return new HgDataFile(this, p, content);
+		return getFileNode(p);
 	}
 
 	public HgDataFile getFileNode(Path path) {
-		CharSequence storagePath = dataPathHelper.rewrite(path.toString());
-		RevlogStream content = resolve(Path.create(storagePath), false);
-		// XXX no content when no file? or HgDataFile.exists() to detect that?
+		RevlogStream content = resolveStoreFile(path);
 		if (content == null) {
 			return new HgDataFile(this, path);
 		}
@@ -347,16 +347,6 @@
 		return repoConfig;
 	}
 
-	// shall be of use only for internal classes 
-	/*package-local*/ File getRepositoryRoot() {
-		return repoDir;
-	}
-	
-	/*package-local, debug*/String getStoragePath(HgDataFile df) {
-		// may come handy for debug
-		return dataPathHelper.rewrite(df.getPath().toString()).toString();
-	}
-
 	// 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)
 	// XXX consider passing Path pool or factory to produce (shared) Path instead of Strings
 	/*package-local*/ final HgDirstate loadDirstate(Path.Source pathFactory) throws HgInvalidControlFileException {
@@ -459,7 +449,7 @@
 	public HgRepositoryLock getStoreLock() {
 		if (storeLock == null) {
 			int timeout = getLockTimeout();
-			File fl = impl.getFileFromRepoDir(repoPathHelper.rewrite("lock").toString());
+			File fl = impl.getFileFromStoreDir("lock");
 			synchronized (this) {
 				if (storeLock == null) {
 					storeLock = new HgRepositoryLock(fl, timeout);
@@ -491,33 +481,35 @@
 
 	/**
 	 * Perhaps, should be separate interface, like ContentLookup
-	 * path - repository storage path (i.e. one usually with .i or .d)
+	 * @param path - normalized file name
+	 * @return <code>null</code> if path doesn't resolve to a existing file
 	 */
-	/*package-local*/ RevlogStream resolve(Path path, boolean shallFakeNonExistent) {
+	/*package-local*/ RevlogStream resolveStoreFile(Path path) {
 		final SoftReference<RevlogStream> ref = streamsCache.get(path);
 		RevlogStream cached = ref == null ? null : ref.get();
 		if (cached != null) {
 			return cached;
 		}
-		File f = new File(repoDir, path.toString());
+		File f = impl.getFileFromDataDir(path);
 		if (f.exists()) {
 			RevlogStream s = new RevlogStream(impl.getDataAccess(), f);
 			if (impl.shallCacheRevlogs()) {
 				streamsCache.put(path, new SoftReference<RevlogStream>(s));
 			}
 			return s;
-		} else {
-			if (shallFakeNonExistent) {
-				try {
-					File fake = File.createTempFile(f.getName(), null);
-					fake.deleteOnExit();
-					return new RevlogStream(impl.getDataAccess(), fake);
-				} catch (IOException ex) {
-					getSessionContext().getLog().dump(getClass(), Info, ex, null);
-				}
-			}
 		}
-		return null; // XXX empty stream instead?
+		return null;
+	}
+	
+	private File fakeNonExistentFile(File expected) throws HgInvalidFileException {
+		try {
+			File fake = File.createTempFile(expected.getName(), null);
+			fake.deleteOnExit();
+			return fake;
+		} catch (IOException ex) {
+			getSessionContext().getLog().dump(getClass(), Info, ex, null);
+			throw new HgInvalidFileException(String.format("Failed to fake existence of file %s", expected), ex);
+		}
 	}
 	
 	/*package-local*/ List<Filter> getFiltersFromRepoToWorkingDir(Path p) {
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Thu Oct 18 18:36:13 2012 +0200
@@ -350,7 +350,9 @@
 					} else {
 						HgDataFile df = repo.getFileNode(fname);
 						if (!df.exists()) {
-							String msg = String.format("File %s known as normal in dirstate (%d, %d), doesn't exist at %s", fname, r.modificationTime(), r.size(), repo.getStoragePath(df));
+							// TODO pass Internals right into HgWCSC cons
+							Internals implRepo = HgInternals.getImplementationRepo(repo);
+							String msg = String.format("File %s known as normal in dirstate (%d, %d), doesn't exist at %s", fname, r.modificationTime(), r.size(), implRepo.getStoragePath(df));
 							throw new HgInvalidFileException(msg, null).setFileName(fname);
 						}
 						Nodeid rev = getDirstateParentManifest().nodeid(fname);
--- a/src/org/tmatesoft/hg/repo/ext/MqManager.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/ext/MqManager.java	Thu Oct 18 18:36:13 2012 +0200
@@ -28,6 +28,7 @@
 import java.util.Map;
 
 import org.tmatesoft.hg.core.Nodeid;
+import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.LineReader;
 import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
@@ -63,16 +64,16 @@
 	public void refresh() throws HgInvalidControlFileException {
 		applied = allKnown = Collections.emptyList();
 		queueNames = Collections.emptyList();
-		File repoDir = HgInternals.getRepositoryDir(repo);
+		Internals repoImpl = HgInternals.getImplementationRepo(repo);
 		final LogFacility log = repo.getSessionContext().getLog();
 		try {
-			File queues = new File(repoDir, "patches.queues");
+			File queues = repoImpl.getFileFromRepoDir("patches.queues");
 			if (queues.isFile()) {
 				LineReader lr = new LineReader(queues, log).trimLines(true).skipEmpty(true);
 				lr.read(new LineReader.SimpleLineCollector(), queueNames = new LinkedList<String>());
 			}
 			final String queueLocation; // path under .hg to patch queue information (status, series and diff files)
-			File activeQueueFile = new File(repoDir, "patches.queue");
+			File activeQueueFile = repoImpl.getFileFromRepoDir("patches.queue");
 			// file is there only if it's not default queue ('patches') that is active
 			if (activeQueueFile.isFile()) {
 				ArrayList<String> contents = new ArrayList<String>();
@@ -99,8 +100,8 @@
 					return Path.create(sb);
 				}
 			};
-			final File fileStatus = new File(repoDir, queueLocation + "status");
-			final File fileSeries = new File(repoDir, queueLocation + "series");
+			final File fileStatus = repoImpl.getFileFromRepoDir(queueLocation + "status");
+			final File fileSeries = repoImpl.getFileFromRepoDir(queueLocation + "series");
 			if (fileStatus.isFile()) {
 				new LineReader(fileStatus, log).read(new LineReader.LineConsumer<List<PatchRecord>>() {
 	
--- a/test/org/tmatesoft/hg/test/TestPhases.java	Thu Oct 18 16:27:32 2012 +0200
+++ b/test/org/tmatesoft/hg/test/TestPhases.java	Thu Oct 18 18:36:13 2012 +0200
@@ -25,6 +25,7 @@
 import org.junit.Test;
 import org.tmatesoft.hg.internal.PhasesHelper;
 import org.tmatesoft.hg.repo.HgChangelog;
+import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgLookup;
 import org.tmatesoft.hg.repo.HgParentChildMap;
 import org.tmatesoft.hg.repo.HgPhase;
@@ -45,7 +46,7 @@
 		HgRepository repo = Configuration.get().find("test-phases");
 		HgPhase[] expected = readPhases(repo);
 		final long start = System.nanoTime();
-		PhasesHelper ph = new PhasesHelper(repo, null);
+		PhasesHelper ph = new PhasesHelper(HgInternals.getImplementationRepo(repo), null);
 		initAndCheck(ph, expected);
 		final long end = System.nanoTime();
 		// μ == \u03bc
@@ -60,7 +61,7 @@
 		HgParentChildMap<HgChangelog> pw = new HgParentChildMap<HgChangelog>(repo.getChangelog());
 		pw.init();
 		final long start2 = System.nanoTime();
-		PhasesHelper ph = new PhasesHelper(repo, pw);
+		PhasesHelper ph = new PhasesHelper(HgInternals.getImplementationRepo(repo), pw);
 		initAndCheck(ph, expected);
 		final long end = System.nanoTime();
 		System.out.printf("With ParentWalker(simulates log command for whole repo): %,d μs (pw init: %,d ns)\n", (end - start1)/1000, start2 - start1);