changeset 490:b3c16d1aede0

Refactoring: move HgRepository's implementation aspects to Internals (which is now its imlementation counterpart and primary repository class to be used by other parts of the library)
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 16 Aug 2012 17:08:34 +0200
parents 9c0138cda59a
children 4a670f76e7d1
files TODO cmdline/org/tmatesoft/hg/console/Main.java src/org/tmatesoft/hg/core/HgCloneCommand.java src/org/tmatesoft/hg/core/HgLogCommand.java src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java src/org/tmatesoft/hg/core/SessionContext.java src/org/tmatesoft/hg/internal/Internals.java src/org/tmatesoft/hg/internal/KeywordFilter.java src/org/tmatesoft/hg/internal/NewlineFilter.java src/org/tmatesoft/hg/internal/PhasesHelper.java src/org/tmatesoft/hg/internal/RepoInitializer.java src/org/tmatesoft/hg/repo/HgBookmarks.java src/org/tmatesoft/hg/repo/HgBranches.java src/org/tmatesoft/hg/repo/HgDataFile.java src/org/tmatesoft/hg/repo/HgDirstate.java src/org/tmatesoft/hg/repo/HgInternals.java src/org/tmatesoft/hg/repo/HgManifest.java src/org/tmatesoft/hg/repo/HgMergeState.java src/org/tmatesoft/hg/repo/HgRemoteRepository.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/repo/HgTags.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java src/org/tmatesoft/hg/repo/Revlog.java src/org/tmatesoft/hg/repo/ext/MqManager.java test/org/tmatesoft/hg/test/TestFileFlags.java test/org/tmatesoft/hg/test/TestIncoming.java test/org/tmatesoft/hg/test/TestStorePath.java
diffstat 27 files changed, 275 insertions(+), 183 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Mon Aug 13 19:24:29 2012 +0200
+++ b/TODO	Thu Aug 16 17:08:34 2012 +0200
@@ -1,3 +1,4 @@
+
 Read-only support, version 1.0
 ==============================
 Committed:
--- a/cmdline/org/tmatesoft/hg/console/Main.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/cmdline/org/tmatesoft/hg/console/Main.java	Thu Aug 16 17:08:34 2012 +0200
@@ -154,7 +154,7 @@
 
 	// TODO as test
 	private void readConfigFile() throws Exception {
-		ConfigFile configFile = new ConfigFile(HgInternals.getContext(hgRepo));
+		ConfigFile configFile = new ConfigFile(hgRepo.getSessionContext());
 		configFile.addLocation(new File(System.getProperty("user.home"), "test-cfg/aaa/config1"));
 		for (String s : configFile.getSectionNames()) {
 			System.out.printf("[%s]\n", s);
--- a/src/org/tmatesoft/hg/core/HgCloneCommand.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java	Thu Aug 16 17:08:34 2012 +0200
@@ -30,11 +30,10 @@
 import java.util.TreeMap;
 import java.util.zip.DeflaterOutputStream;
 
-import org.tmatesoft.hg.internal.BasicSessionContext;
 import org.tmatesoft.hg.internal.ByteArrayDataAccess;
 import org.tmatesoft.hg.internal.DataAccess;
 import org.tmatesoft.hg.internal.DigestHelper;
-import org.tmatesoft.hg.internal.Internals;
+import org.tmatesoft.hg.internal.RepoInitializer;
 import org.tmatesoft.hg.repo.HgBundle;
 import org.tmatesoft.hg.repo.HgBundle.GroupElement;
 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
@@ -108,7 +107,7 @@
 		// pull all changes from the very beginning
 		// XXX consult getContext() if by any chance has a bundle ready, if not, then read and register 
 		HgBundle completeChanges = srcRepo.getChanges(Collections.singletonList(NULL));
-		WriteDownMate mate = new WriteDownMate(destination);
+		WriteDownMate mate = new WriteDownMate(srcRepo.getSessionContext(), destination);
 		try {
 			// instantiate new repo in the destdir
 			mate.initEmptyRepository();
@@ -143,17 +142,17 @@
 		private final ArrayList<Nodeid> revisionSequence = new ArrayList<Nodeid>(); // last visited nodes first
 
 		private final LinkedList<String> fncacheFiles = new LinkedList<String>();
-		private Internals implHelper;
+		private RepoInitializer repoInit;
 
-		public WriteDownMate(File destDir) {
+		public WriteDownMate(SessionContext ctx, File destDir) {
 			hgDir = new File(destDir, ".hg");
-			implHelper = new Internals(new BasicSessionContext(null));
-			implHelper.setStorageConfig(1, STORE | FNCACHE | DOTENCODE);
-			storagePathHelper = implHelper.buildDataFilesHelper();
+			repoInit = new RepoInitializer();
+			repoInit.setRequires(STORE | FNCACHE | DOTENCODE);
+			storagePathHelper = repoInit.buildDataFilesHelper(ctx);
 		}
 
 		public void initEmptyRepository() throws IOException {
-			implHelper.initEmptyRepository(hgDir);
+			repoInit.initEmptyRepository(hgDir);
 		}
 
 		public void complete() throws IOException {
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/core/HgLogCommand.java	Thu Aug 16 17:08:34 2012 +0200
@@ -35,7 +35,6 @@
 import org.tmatesoft.hg.repo.HgChangelog;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.repo.HgDataFile;
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
 import org.tmatesoft.hg.repo.HgInvalidRevisionException;
 import org.tmatesoft.hg.repo.HgInvalidStateException;
@@ -547,7 +546,7 @@
 						}
 					}
 					if (!sanity) {
-						HgInternals.getContext(repo).getLog().dump(getClass(), Error, "Index of revision %d:%s doesn't match any of requested", cs.getRevisionIndex(), cs.getNodeid().shortNotation());
+						repo.getSessionContext().getLog().dump(getClass(), Error, "Index of revision %d:%s doesn't match any of requested", cs.getRevisionIndex(), cs.getNodeid().shortNotation());
 					}
 					assert sanity;
 				}
--- a/src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/core/HgUpdateConfigCommand.java	Thu Aug 16 17:08:34 2012 +0200
@@ -51,8 +51,8 @@
 	}
 	
 	public static HgUpdateConfigCommand forRepository(HgRepository hgRepo) {
-		// XXX HgRepository to implement SessionContextProvider (with getContext())?
-		return new HgUpdateConfigCommand(HgInternals.getContext(hgRepo), new File(HgInternals.getRepositoryDir(hgRepo), "hgrc"));
+		// XXX HgRepository to implement SessionContext.Provider (with getContext())?
+		return new HgUpdateConfigCommand(hgRepo.getSessionContext(), new File(HgInternals.getRepositoryDir(hgRepo), "hgrc"));
 	}
 	
 	public static HgUpdateConfigCommand forUser(SessionContext ctx) {
--- a/src/org/tmatesoft/hg/core/SessionContext.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/core/SessionContext.java	Thu Aug 16 17:08:34 2012 +0200
@@ -45,4 +45,11 @@
 	public abstract Object getConfigurationProperty(String name, Object defaultValue);
 	// perhaps, later may add Configuration object, with PropertyMarshal's helpers
 	// e.g. when there's standalone Caches and WritableSessionProperties objects
+
+	/**
+	 * Providers of the context may implement
+	 */
+	public interface Source {
+		SessionContext getSessionContext();
+	}
 }
--- a/src/org/tmatesoft/hg/internal/Internals.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/Internals.java	Thu Aug 16 17:08:34 2012 +0200
@@ -20,7 +20,6 @@
 import static org.tmatesoft.hg.util.LogFacility.Severity.Error;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -32,7 +31,6 @@
 import java.util.StringTokenizer;
 
 import org.tmatesoft.hg.core.SessionContext;
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidControlFileException;
 import org.tmatesoft.hg.repo.HgRepoConfig.ExtensionsSection;
 import org.tmatesoft.hg.repo.HgRepository;
@@ -77,17 +75,43 @@
 	
 	private int requiresFlags = 0;
 	private List<Filter.Factory> filterFactories;
-	private final SessionContext sessionContext;
+	private final HgRepository repo;
+	private final File repoDir;
 	private final boolean isCaseSensitiveFileSystem;
 	private final boolean shallCacheRevlogsInRepo;
+	private final DataAccessProvider dataAccess;
 
-	public Internals(SessionContext ctx) {
-		sessionContext = ctx;
+	public Internals(HgRepository hgRepo, File hgDir) {
+		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);
 	}
 	
-	public void parseRequires(HgRepository hgRepo, File requiresFile) throws HgInvalidControlFileException {
+	public boolean isInvalid() {
+		return !repoDir.exists() || !repoDir.isDirectory();
+	}
+	
+	public File getFileFromRepoDir(String name) {
+		return new File(repoDir, name);
+	}
+	
+	public SessionContext getContext() {
+		return repo.getSessionContext();
+	}
+	
+	public HgRepository getRepo() {
+		return repo;
+	}
+	
+	public DataAccessProvider getDataAccess() {
+		return dataAccess;
+	}
+
+	public void parseRequires() throws HgInvalidControlFileException {
+		File requiresFile =getFileFromRepoDir("requires");
 		try {
 			new RequiresFile().parse(this, requiresFile);
 		} catch (IOException ex) {
@@ -109,10 +133,7 @@
 
 	// XXX perhaps, should keep both fields right here, not in the HgRepository
 	public PathRewrite buildDataFilesHelper() {
-		// Note, tests in TestStorePath depend on the encoding not being cached
-		Charset cs = getFileEncoding();
-		// 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);
+		return new RepoInitializer().setRequires(requiresFlags).buildDataFilesHelper(getContext());
 	}
 
 	public PathRewrite buildRepositoryFilesHelper() {
@@ -127,53 +148,35 @@
 		}
 	}
 
-	public List<Filter.Factory> getFilters(HgRepository hgRepo) {
+	public List<Filter.Factory> getFilters() {
 		if (filterFactories == null) {
 			filterFactories = new ArrayList<Filter.Factory>();
-			ExtensionsSection cfg = hgRepo.getConfiguration().getExtensions();
+			ExtensionsSection cfg = repo.getConfiguration().getExtensions();
 			if (cfg.isEnabled("eol")) {
 				NewlineFilter.Factory ff = new NewlineFilter.Factory();
-				ff.initialize(hgRepo);
+				ff.initialize(repo);
 				filterFactories.add(ff);
 			}
 			if (cfg.isEnabled("keyword")) {
 				KeywordFilter.Factory ff = new KeywordFilter.Factory();
-				ff.initialize(hgRepo);
+				ff.initialize(repo);
 				filterFactories.add(ff);
 			}
 		}
 		return filterFactories;
 	}
 	
-	public void initEmptyRepository(File hgDir) throws IOException {
-		hgDir.mkdir();
-		FileOutputStream requiresFile = new FileOutputStream(new File(hgDir, "requires"));
-		StringBuilder sb = new StringBuilder(40);
-		sb.append("revlogv1\n");
-		if ((requiresFlags & STORE) != 0) {
-			sb.append("store\n");
-		}
-		if ((requiresFlags & FNCACHE) != 0) {
-			sb.append("fncache\n");
-		}
-		if ((requiresFlags & DOTENCODE) != 0) {
-			sb.append("dotencode\n");
-		}
-		requiresFile.write(sb.toString().getBytes());
-		requiresFile.close();
-		new File(hgDir, "store").mkdir(); // with that, hg verify says ok.
-	}
-	
 	public boolean isCaseSensitiveFileSystem() {
 		return isCaseSensitiveFileSystem;
 	}
 	
 	public EncodingHelper buildFileNameEncodingHelper() {
-		return new EncodingHelper(getFileEncoding(), sessionContext);
+		SessionContext ctx = repo.getSessionContext();
+		return new EncodingHelper(getFileEncoding(ctx), ctx);
 	}
 	
-	private Charset getFileEncoding() {
-		Object altEncoding = sessionContext.getConfigurationProperty(CFG_PROPERTY_FS_FILENAME_ENCODING, null);
+	/*package-local*/ static Charset getFileEncoding(SessionContext ctx) {
+		Object altEncoding = ctx.getConfigurationProperty(CFG_PROPERTY_FS_FILENAME_ENCODING, null);
 		Charset cs;
 		if (altEncoding == null) {
 			cs = Charset.defaultCharset();
@@ -183,7 +186,7 @@
 			} catch (IllegalArgumentException ex) {
 				// both IllegalCharsetNameException and UnsupportedCharsetException are subclasses of IAE, too
 				// not severe enough to throw an exception, imo. Just record the fact it's bad ad we ignore it 
-				sessionContext.getLog().dump(Internals.class, Error, ex, String.format("Bad configuration value for filename encoding %s", altEncoding));
+				ctx.getLog().dump(Internals.class, Error, ex, String.format("Bad configuration value for filename encoding %s", altEncoding));
 				cs = Charset.defaultCharset();
 			}
 		}
@@ -245,9 +248,8 @@
 	/**
 	 * @see http://www.selenic.com/mercurial/hgrc.5.html
 	 */
-	public ConfigFile readConfiguration(HgRepository hgRepo, File repoRoot) throws IOException {
-		// XXX Internals now have sessionContext field, is there real need to extract one from the repo?
-		SessionContext sessionCtx = HgInternals.getContext(hgRepo);
+	public ConfigFile readConfiguration() throws IOException {
+		SessionContext sessionCtx = repo.getSessionContext();
 		ConfigFile configFile = new ConfigFile(sessionCtx);
 		File hgInstallRoot = findHgInstallRoot(sessionCtx); // may be null
 		//
@@ -288,7 +290,7 @@
 		}
 		// last one, overrides anything else
 		// <repo>/.hg/hgrc
-		configFile.addLocation(new File(repoRoot, "hgrc"));
+		configFile.addLocation(getFileFromRepoDir("hgrc"));
 		return configFile;
 	}
 	
--- a/src/org/tmatesoft/hg/internal/KeywordFilter.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/KeywordFilter.java	Thu Aug 16 17:08:34 2012 +0200
@@ -25,7 +25,6 @@
 
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgRuntimeException;
 import org.tmatesoft.hg.util.Pair;
@@ -265,7 +264,7 @@
 			int csetRev = repo.getFileNode(path).getChangesetRevisionIndex(HgRepository.TIP);
 			return repo.getChangelog().getRevision(csetRev).shortNotation();
 		} catch (HgRuntimeException ex) {
-			HgInternals.getContext(repo).getLog().dump(getClass(), Error, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
 			return Nodeid.NULL.shortNotation(); // XXX perhaps, might return anything better? Not sure how hg approaches this. 
 		}
 	}
@@ -274,7 +273,7 @@
 		try {
 			return getChangeset().user();
 		} catch (HgRuntimeException ex) {
-			HgInternals.getContext(repo).getLog().dump(getClass(), Error, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
 			return "";
 		}
 	}
@@ -284,7 +283,7 @@
 		try {
 			d = getChangeset().date();
 		} catch (HgRuntimeException ex) {
-			HgInternals.getContext(repo).getLog().dump(getClass(), Error, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
 			d = new Date(0l);
 		}
 		return String.format("%tY/%<tm/%<td %<tH:%<tM:%<tS", d);
--- a/src/org/tmatesoft/hg/internal/NewlineFilter.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/NewlineFilter.java	Thu Aug 16 17:08:34 2012 +0200
@@ -28,7 +28,6 @@
 import java.util.ArrayList;
 import java.util.Map;
 
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidFileException;
 import org.tmatesoft.hg.repo.HgInvalidStateException;
 import org.tmatesoft.hg.repo.HgRepository;
@@ -312,11 +311,11 @@
 //				return;
 //			}
 			// XXX perhaps, add HgDataFile.hasWorkingCopy and workingCopyContent()?
-			ConfigFile hgeol = new ConfigFile(HgInternals.getContext(hgRepo));
+			ConfigFile hgeol = new ConfigFile(hgRepo.getSessionContext());
 			try {
 				hgeol.addLocation(cfgFile);
 			} catch (HgInvalidFileException ex) {
-				HgInternals.getContext(hgRepo).getLog().dump(getClass(), Warn, ex, null);
+				hgRepo.getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 			}
 			nativeRepoFormat = hgeol.getSection("repository").get("native");
 			if (nativeRepoFormat == null) {
@@ -339,7 +338,7 @@
 				} else if ("BIN".equals(e.getValue())) {
 					binPatterns.add(e.getKey());
 				} else {
-					HgInternals.getContext(hgRepo).getLog().dump(getClass(), Warn, "Can't recognize .hgeol entry: %s for %s", e.getValue(), e.getKey());
+					hgRepo.getSessionContext().getLog().dump(getClass(), Warn, "Can't recognize .hgeol entry: %s for %s", e.getValue(), e.getKey());
 				}
 			}
 			if (!crlfPatterns.isEmpty()) {
--- a/src/org/tmatesoft/hg/internal/PhasesHelper.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/internal/PhasesHelper.java	Thu Aug 16 17:08:34 2012 +0200
@@ -40,7 +40,10 @@
 import org.tmatesoft.hg.repo.HgRepository;
 
 /**
- * Support to deal with phases feature fo Mercurial (as of Mercutial version 2.1)
+ * Support to deal with Mercurial phases feature (as of Mercurial version 2.1)
+ * 
+ * @see http://mercurial.selenic.com/wiki/Phases
+ * @see http://mercurial.selenic.com/wiki/PhasesDevel
  * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
@@ -134,13 +137,13 @@
 					continue;
 				}
 				if (lc.length != 2) {
-					HgInternals.getContext(repo).getLog().dump(getClass(), Warn, "Bad line in phaseroots:%s", line);
+					repo.getSessionContext().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)) {
-					HgInternals.getContext(repo).getLog().dump(getClass(), Warn, "Phase(%d) root node %s doesn't exist in the repository, ignored.", phaseIndex, rootRev);
+					repo.getSessionContext().getLog().dump(getClass(), Warn, "Phase(%d) root node %s doesn't exist in the repository, ignored.", phaseIndex, rootRev);
 					continue;
 				}
 				HgPhase phase = HgPhase.parse(phaseIndex);
@@ -159,7 +162,7 @@
 				try {
 					br.close();
 				} catch (IOException ex) {
-					HgInternals.getContext(repo).getLog().dump(getClass(), Info, ex, null);
+					repo.getSessionContext().getLog().dump(getClass(), Info, ex, null);
 					// ignore the exception otherwise 
 				}
 			}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/internal/RepoInitializer.java	Thu Aug 16 17:08:34 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 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
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For information on how to redistribute this software under
+ * the terms of a license other than GNU General Public License
+ * contact TMate Software at support@hg4j.com
+ */
+package org.tmatesoft.hg.internal;
+
+import static org.tmatesoft.hg.internal.RequiresFile.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.tmatesoft.hg.core.SessionContext;
+import org.tmatesoft.hg.util.PathRewrite;
+
+/**
+ * Responsible of `requires` processing both on repo read and repo write
+ * XXX needs better name, perhaps
+ * 
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class RepoInitializer {
+	private int requiresFlags;
+	
+	public RepoInitializer() {
+	}
+	
+	public RepoInitializer setRequires(int flags) {
+		requiresFlags = flags;
+		return this;
+	}
+	
+	public int getRequires() {
+		return requiresFlags;
+	}
+
+	public void initEmptyRepository(File hgDir) throws IOException {
+		hgDir.mkdir();
+		FileOutputStream requiresFile = new FileOutputStream(new File(hgDir, "requires"));
+		StringBuilder sb = new StringBuilder(40);
+		sb.append("revlogv1\n");
+		if ((requiresFlags & STORE) != 0) {
+			sb.append("store\n");
+		}
+		if ((requiresFlags & FNCACHE) != 0) {
+			sb.append("fncache\n");
+		}
+		if ((requiresFlags & DOTENCODE) != 0) {
+			sb.append("dotencode\n");
+		}
+		requiresFile.write(sb.toString().getBytes());
+		requiresFile.close();
+		new File(hgDir, "store").mkdir(); // with that, hg verify says ok.
+	}
+
+	public PathRewrite buildDataFilesHelper(SessionContext ctx) {
+		Charset cs = Internals.getFileEncoding(ctx);
+		// 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);
+	}
+}
--- a/src/org/tmatesoft/hg/repo/HgBookmarks.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgBookmarks.java	Thu Aug 16 17:08:34 2012 +0200
@@ -24,6 +24,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.util.LogFacility;
 
@@ -33,17 +34,18 @@
  * @author TMate Software Ltd.
  */
 public final class HgBookmarks {
-	private final HgRepository repo;
+	private final Internals internalRepo;
 	private Map<String, Nodeid> bookmarks = Collections.emptyMap();
 	private String activeBookmark; 
 
-	HgBookmarks(HgRepository hgRepo) {
-		repo = hgRepo;
+	HgBookmarks(Internals internals) {
+		internalRepo = internals;
 	}
 	
 	/*package-local*/ void read() throws HgInvalidControlFileException {
-		final LogFacility log = repo.getContext().getLog();
-		File all = new File (repo.getRepositoryRoot(), HgRepositoryFiles.Bookmarks.getName());
+		final LogFacility log = internalRepo.getContext().getLog();
+		final HgRepository repo = internalRepo.getRepo();
+		File all = internalRepo.getFileFromRepoDir(HgRepositoryFiles.Bookmarks.getName());
 		LinkedHashMap<String, Nodeid> bm = new LinkedHashMap<String, Nodeid>();
 		if (all.canRead()) {
 			LineReader lr1 = new LineReader(all, log);
@@ -74,9 +76,9 @@
 		}
 		
 		activeBookmark = null;
-		File active = new File(repo.getRepositoryRoot(), HgRepositoryFiles.BookmarksCurrent.getName());
+		File active = internalRepo.getFileFromRepoDir(HgRepositoryFiles.BookmarksCurrent.getName());
 		if (active.canRead()) {
-			LineReader lr2 = new LineReader(active, repo.getContext().getLog());
+			LineReader lr2 = new LineReader(active, log);
 			ArrayList<String> c = new ArrayList<String>(2);
 			lr2.read(new LineReader.SimpleLineCollector(), c);
 			if (c.size() > 0) {
--- a/src/org/tmatesoft/hg/repo/HgBranches.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgBranches.java	Thu Aug 16 17:08:34 2012 +0200
@@ -39,6 +39,7 @@
 
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.Experimental;
+import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.util.ProgressSupport;
 
@@ -51,10 +52,12 @@
 	
 	private final Map<String, BranchInfo> branches = new TreeMap<String, BranchInfo>();
 	private final HgRepository repo;
+	private final Internals internalRepo;
 	private boolean isCacheActual = false;
 
-	HgBranches(HgRepository hgRepo) {
-		repo = hgRepo;
+	HgBranches(Internals internals) {
+		internalRepo = internals;
+		repo = internals.getRepo(); // merely a cached value
 	}
 
 	private int readCache() {
@@ -101,24 +104,24 @@
 			return lastInCache;
 		} catch (IOException ex) {
 			 // log error, but otherwise do nothing
-			repo.getContext().getLog().dump(getClass(), Warn, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 			// FALL THROUGH to return -1 indicating no cache information 
 		} catch (NumberFormatException ex) {
-			repo.getContext().getLog().dump(getClass(), Warn, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 			// FALL THROUGH
 		} catch (HgInvalidControlFileException ex) {
 			// shall not happen, thus log as error
-			repo.getContext().getLog().dump(getClass(), Error, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
 			// FALL THROUGH
 		} catch (HgInvalidRevisionException ex) {
-			repo.getContext().getLog().dump(getClass(), Error, ex, null);
+			repo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
 			// FALL THROUGH
 		} finally {
 			if (br != null) {
 				try {
 					br.close();
 				} catch (IOException ex) {
-					repo.getContext().getLog().dump(getClass(), Warn, ex, null); // ignore
+					repo.getSessionContext().getLog().dump(getClass(), Warn, ex, null); // ignore
 				}
 			}
 		}
@@ -275,7 +278,7 @@
 
 	private File getCacheFile() {
 		// prior to 1.8 used to be .hg/branchheads.cache
-		return new File(repo.getRepositoryRoot(), "cache/branchheads");
+		return internalRepo.getFileFromRepoDir("cache/branchheads");
 	}
 
 	public static class BranchInfo {
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Thu Aug 16 17:08:34 2012 +0200
@@ -182,7 +182,7 @@
 					try {
 						fc.close();
 					} catch (IOException ex) {
-						getRepo().getContext().getLog().dump(getClass(), Warn, ex, null);
+						getRepo().getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 					}
 				}
 			}
@@ -208,7 +208,7 @@
 		final int csetRevIndex;
 		if (p.isNull()) {
 			// no dirstate parents 
-			getRepo().getContext().getLog().dump(getClass(), Info, "No dirstate parents, resort to TIP", getPath());
+			getRepo().getSessionContext().getLog().dump(getClass(), Info, "No dirstate parents, resort to TIP", getPath());
 			// if it's a repository with no dirstate, use TIP then
 			csetRevIndex = clog.getLastRevision();
 			if (csetRevIndex == -1) {
@@ -283,7 +283,7 @@
 			metadata = new Metadata();
 		}
 		ErrorHandlingInspector insp;
-		final LogFacility lf = getRepo().getContext().getLog();
+		final LogFacility lf = getRepo().getSessionContext().getLog();
 		if (metadata.none(fileRevisionIndex)) {
 			insp = new ContentPipe(sink, 0, lf);
 		} else if (metadata.known(fileRevisionIndex)) {
--- a/src/org/tmatesoft/hg/repo/HgDirstate.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDirstate.java	Thu Aug 16 17:08:34 2012 +0200
@@ -17,6 +17,7 @@
 package org.tmatesoft.hg.repo;
 
 import static org.tmatesoft.hg.core.Nodeid.NULL;
+import static org.tmatesoft.hg.repo.HgRepositoryFiles.Dirstate;
 import static org.tmatesoft.hg.util.LogFacility.Severity.Debug;
 
 import java.io.BufferedReader;
@@ -33,6 +34,7 @@
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.DataAccess;
 import org.tmatesoft.hg.internal.EncodingHelper;
+import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.util.Pair;
 import org.tmatesoft.hg.util.Path;
 import org.tmatesoft.hg.util.PathRewrite;
@@ -52,8 +54,7 @@
 		Normal, Added, Removed, Merged, // order is being used in code of this class, don't change unless any use is checked
 	}
 
-	private final HgRepository repo;
-	private final File dirstateFile;
+	private final Internals repo;
 	private final Path.Source pathPool;
 	private final PathRewrite canonicalPathRewrite;
 	private Map<Path, Record> normal;
@@ -67,14 +68,14 @@
 	private Pair<Nodeid, Nodeid> parents;
 	
 	// canonicalPath may be null if we don't need to check for names other than in dirstate
-	/*package-local*/ HgDirstate(HgRepository hgRepo, File dirstate, Path.Source pathSource, PathRewrite canonicalPath) {
+	/*package-local*/ HgDirstate(Internals hgRepo, Path.Source pathSource, PathRewrite canonicalPath) {
 		repo = hgRepo;
-		dirstateFile = dirstate; // XXX decide whether file names shall be kept local to reader (see #branches()) or passed from outside
 		pathPool = pathSource;
 		canonicalPathRewrite = canonicalPath;
 	}
 
-	/*package-local*/ void read(EncodingHelper encodingHelper) throws HgInvalidControlFileException {
+	/*package-local*/ void read() throws HgInvalidControlFileException {
+		EncodingHelper encodingHelper = repo.buildFileNameEncodingHelper();
 		normal = added = removed = merged = Collections.<Path, Record>emptyMap();
 		parents = new Pair<Nodeid,Nodeid>(Nodeid.NULL, Nodeid.NULL);
 		if (canonicalPathRewrite != null) {
@@ -82,6 +83,7 @@
 		} else {
 			canonical2dirstateName = Collections.emptyMap();
 		}
+		File dirstateFile = getDirstateFile(repo);
 		if (dirstateFile == null || !dirstateFile.exists()) {
 			return;
 		}
@@ -170,15 +172,20 @@
 		return parents;
 	}
 	
+	private static File getDirstateFile(Internals repo) {
+		return repo.getFileFromRepoDir(Dirstate.getName());
+	}
+
 	/**
 	 * @return pair of parents, both {@link Nodeid#NULL} if dirstate is not available
 	 */
-	/*package-local*/ static Pair<Nodeid, Nodeid> readParents(HgRepository repo, File dirstateFile) throws HgInvalidControlFileException {
+	/*package-local*/ static Pair<Nodeid, Nodeid> readParents(Internals internalRepo) throws HgInvalidControlFileException {
 		// do not read whole dirstate if all we need is WC parent information
+		File dirstateFile = getDirstateFile(internalRepo);
 		if (dirstateFile == null || !dirstateFile.exists()) {
 			return new Pair<Nodeid,Nodeid>(NULL, NULL);
 		}
-		DataAccess da = repo.getDataAccess().create(dirstateFile);
+		DataAccess da = internalRepo.getDataAccess().create(dirstateFile);
 		try {
 			if (da.isEmpty()) {
 				return new Pair<Nodeid,Nodeid>(NULL, NULL);
@@ -195,7 +202,8 @@
 	 * TODO [post-1.0] it's really not a proper place for the method, need WorkingCopyContainer or similar
 	 * @return branch associated with the working directory
 	 */
-	/*package-local*/ static String readBranch(HgRepository repo, File branchFile) throws HgInvalidControlFileException {
+	/*package-local*/ static String readBranch(Internals internalRepo) throws HgInvalidControlFileException {
+		File branchFile = internalRepo.getFileFromRepoDir("branch");
 		String branch = HgRepository.DEFAULT_BRANCH_NAME;
 		if (branchFile.exists()) {
 			try {
@@ -207,7 +215,7 @@
 				branch = b == null || b.length() == 0 ? HgRepository.DEFAULT_BRANCH_NAME : b;
 				r.close();
 			} catch (FileNotFoundException ex) {
-				repo.getContext().getLog().dump(HgDirstate.class, Debug, ex, null); // log verbose debug, exception might be legal here 
+				internalRepo.getContext().getLog().dump(HgDirstate.class, Debug, ex, null); // log verbose debug, exception might be legal here 
 				// IGNORE
 			} catch (IOException ex) {
 				throw new HgInvalidControlFileException("Error reading file with branch information", ex, branchFile);
--- a/src/org/tmatesoft/hg/repo/HgInternals.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgInternals.java	Thu Aug 16 17:08:34 2012 +0200
@@ -26,7 +26,6 @@
 import java.net.UnknownHostException;
 
 import org.tmatesoft.hg.core.Nodeid;
-import org.tmatesoft.hg.core.SessionContext;
 import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.RelativePathRewrite;
@@ -73,8 +72,8 @@
 				}
 			};
 		}
-		HgDirstate ds = new HgDirstate(repo, new File(repo.getRepositoryRoot(), "dirstate"), new Path.SimpleSource(), canonicalPath);
-		ds.read(repo.getImplHelper().buildFileNameEncodingHelper());
+		HgDirstate ds = new HgDirstate(repo.getImplHelper(), new Path.SimpleSource(), canonicalPath);
+		ds.read();
 		return ds;
 	}
 	
@@ -145,16 +144,9 @@
 		// Impl note: simple source is enough as files in the working dir are all unique
 		// even if they might get reused (i.e. after FileIterator#reset() and walking once again),
 		// path caching is better to be done in the code which knows that path are being reused 
-		return new FileWalker(repo.getContext(), repoRoot, pathSrc, workindDirScope);
+		return new FileWalker(repo.getSessionContext(), repoRoot, pathSrc, workindDirScope);
 	}
 	
-	// expose otherwise package-local information primarily to use in our own o.t.hg.core package
-	public static SessionContext getContext(HgRepository repo) {
-		// TODO SessionContext.Source and HgRepo to implement it
-		return repo.getContext();
-	}
-
-
 	// Convenient check of revision index for validity (not all negative values are wrong as long as we use negative constants)
 	public static boolean wrongRevisionIndex(int rev) {
 		// TODO Another method to check,throw and expand TIP at once (check[Revision|Revlog]Index()
--- a/src/org/tmatesoft/hg/repo/HgManifest.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgManifest.java	Thu Aug 16 17:08:34 2012 +0200
@@ -169,7 +169,7 @@
 			i++;
 		} while (manifestFirst == BAD_REVISION && csetFirst+i <= csetLast);
 		if (manifestFirst == BAD_REVISION) {
-			getRepo().getContext().getLog().dump(getClass(), Info, "None of changesets [%d..%d] have associated manifest revision", csetFirst, csetLast);
+			getRepo().getSessionContext().getLog().dump(getClass(), Info, "None of changesets [%d..%d] have associated manifest revision", csetFirst, csetLast);
 			// we ran through all revisions in [start..end] and none of them had manifest.
 			// we reported that to inspector and proceeding is done now.
 			return;
@@ -618,7 +618,7 @@
 				// TODO calculate those missing effectively (e.g. cache and sort nodeids to speed lookup
 				// right away in the #next (may refactor ParentWalker's sequential and sorted into dedicated helper and reuse here)
 				if (manifest.isNull()) {
-					repo.getContext().getLog().dump(getClass(), Severity.Warn, "Changeset %d has no associated manifest entry", u);
+					repo.getSessionContext().getLog().dump(getClass(), Severity.Warn, "Changeset %d has no associated manifest entry", u);
 					// keep -1 in the changelog2manifest map.
 				} else {
 					changelog2manifest[u] = repo.getManifest().getRevisionIndex(manifest);
--- a/src/org/tmatesoft/hg/repo/HgMergeState.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgMergeState.java	Thu Aug 16 17:08:34 2012 +0200
@@ -29,6 +29,7 @@
 
 import org.tmatesoft.hg.core.HgFileRevision;
 import org.tmatesoft.hg.core.Nodeid;
+import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.ManifestRevision;
 import org.tmatesoft.hg.internal.Pool;
 import org.tmatesoft.hg.util.Pair;
@@ -83,11 +84,11 @@
 		}
 	}
 
-	private final HgRepository repo;
+	private final Internals repo;
 	private Entry[] entries;
 
-	HgMergeState(HgRepository hgRepo) {
-		repo = hgRepo;
+	HgMergeState(Internals internalRepo) {
+		repo = internalRepo;
 	}
 
 	/**
@@ -95,15 +96,16 @@
 	 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em>
 	 */
 	public void refresh() throws HgRuntimeException {
+		final HgRepository hgRepo = repo.getRepo();
 		entries = null;
 		// it's possible there are two parents but no merge/state, we shall report this case as 'merging', with proper
 		// first and second parent values
 		stateParent = Nodeid.NULL;
 		Pool<Nodeid> nodeidPool = new Pool<Nodeid>();
 		Pool<Path> fnamePool = new Pool<Path>();
-		Pair<Nodeid, Nodeid> wcParents = repo.getWorkingCopyParents();
+		Pair<Nodeid, Nodeid> wcParents = hgRepo.getWorkingCopyParents();
 		wcp1 = nodeidPool.unify(wcParents.first()); wcp2 = nodeidPool.unify(wcParents.second());
-		final File f = new File(repo.getRepositoryRoot(), "merge/state");
+		final File f = repo.getFileFromRepoDir("merge/state");
 		if (!f.canRead()) {
 			// empty state
 			return;
@@ -115,25 +117,25 @@
 			final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool);
 			final ManifestRevision m2 = new ManifestRevision(nodeidPool, fnamePool);
 			if (!wcp2.isNull()) {
-				final int rp2 = repo.getChangelog().getRevisionIndex(wcp2);
-				repo.getManifest().walk(rp2, rp2, m2);
+				final int rp2 = hgRepo.getChangelog().getRevisionIndex(wcp2);
+				hgRepo.getManifest().walk(rp2, rp2, m2);
 			}
 			BufferedReader br = new BufferedReader(new FileReader(f));
 			String s = br.readLine();
 			stateParent = nodeidPool.unify(Nodeid.fromAscii(s));
-			final int rp1 = repo.getChangelog().getRevisionIndex(stateParent);
-			repo.getManifest().walk(rp1, rp1, m1);
+			final int rp1 = hgRepo.getChangelog().getRevisionIndex(stateParent);
+			hgRepo.getManifest().walk(rp1, rp1, m1);
 			while ((s = br.readLine()) != null) {
 				String[] r = s.split("\\00");
 				Path p1fname = pathPool.path(r[3]);
 				Nodeid nidP1 = m1.nodeid(p1fname);
 				Nodeid nidCA = nodeidPool.unify(Nodeid.fromAscii(r[5]));
-				HgFileRevision p1 = new HgFileRevision(repo, nidP1, m1.flags(p1fname), p1fname);
+				HgFileRevision p1 = new HgFileRevision(hgRepo, nidP1, m1.flags(p1fname), p1fname);
 				HgFileRevision ca;
 				if (nidCA == nidP1 && r[3].equals(r[4])) {
 					ca = p1;
 				} else {
-					ca = new HgFileRevision(repo, nidCA, null, pathPool.path(r[4]));
+					ca = new HgFileRevision(hgRepo, nidCA, null, pathPool.path(r[4]));
 				}
 				HgFileRevision p2;
 				if (!wcp2.isNull() || !r[6].equals(r[4])) {
@@ -143,7 +145,7 @@
 						assert false : "There's not enough information (or I don't know where to look) in merge/state to find out what's the second parent";
 						nidP2 = NULL;
 					}
-					p2 = new HgFileRevision(repo, nidP2, m2.flags(p2fname), p2fname);
+					p2 = new HgFileRevision(hgRepo, nidP2, m2.flags(p2fname), p2fname);
 				} else {
 					// no second parent known. no idea what to do here, assume linear merge, use common ancestor as parent
 					p2 = ca;
--- a/src/org/tmatesoft/hg/repo/HgRemoteRepository.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRemoteRepository.java	Thu Aug 16 17:08:34 2012 +0200
@@ -67,7 +67,7 @@
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
-public class HgRemoteRepository {
+public class HgRemoteRepository implements SessionContext.Source {
 	
 	private final URL url;
 	private final SSLContext sslContext;
@@ -186,6 +186,10 @@
 			return String.format("%s://%s%s", url.getProtocol(), url.getHost(), url.getPath());
 		}
 	}
+	
+	public SessionContext getSessionContext() {
+		return sessionContext;
+	}
 
 	public List<Nodeid> heads() throws HgRemoteConnectionException {
 		try {
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Thu Aug 16 17:08:34 2012 +0200
@@ -34,7 +34,6 @@
 import org.tmatesoft.hg.core.SessionContext;
 import org.tmatesoft.hg.internal.ByteArrayChannel;
 import org.tmatesoft.hg.internal.ConfigFile;
-import org.tmatesoft.hg.internal.DataAccessProvider;
 import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.Filter;
 import org.tmatesoft.hg.internal.Internals;
@@ -54,7 +53,7 @@
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
-public final class HgRepository {
+public final class HgRepository implements SessionContext.Source {
 
 	// IMPORTANT: if new constants added, consider fixing HgInternals#wrongRevisionIndex and HgInvalidRevisionException#getMessage
 
@@ -100,7 +99,6 @@
 	private final File repoDir; // .hg folder
 	private final File workingDir; // .hg/../
 	private final String repoLocation;
-	private final DataAccessProvider dataAccess;
 	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
@@ -133,7 +131,6 @@
 		repoDir = null;
 		workingDir = null;
 		repoLocation = repositoryPath;
-		dataAccess = null;
 		dataPathHelper = repoPathHelper = null;
 		normalizePath = null;
 		sessionContext = null;
@@ -153,11 +150,10 @@
 		if (workingDir == null) {
 			throw new IllegalArgumentException(repoDir.toString());
 		}
-		impl = new org.tmatesoft.hg.internal.Internals(ctx);
 		repoLocation = repositoryPath;
 		sessionContext = ctx;
-		dataAccess = new DataAccessProvider(ctx);
-		impl.parseRequires(this, new File(repoDir, "requires"));
+		impl = new org.tmatesoft.hg.internal.Internals(this, repositoryRoot);
+		impl.parseRequires();
 		normalizePath = impl.buildNormalizePathRewrite(); 
 		dataPathHelper = impl.buildDataFilesHelper();
 		repoPathHelper = impl.buildRepositoryFilesHelper();
@@ -173,7 +169,7 @@
 	}
 
 	public boolean isInvalid() {
-		return repoDir == null || !repoDir.exists() || !repoDir.isDirectory();
+		return impl == null || impl.isInvalid();
 	}
 	
 	public HgChangelog getChangelog() {
@@ -210,12 +206,12 @@
 						tags.readGlobal(new StringReader(content));
 					} catch (CancelledException ex) {
 						 // IGNORE, can't happen, we did not configure cancellation
-						getContext().getLog().dump(getClass(), Debug, ex, null);
+						getSessionContext().getLog().dump(getClass(), Debug, ex, null);
 					} catch (IOException ex) {
 						// UnsupportedEncodingException can't happen (UTF8)
 						// only from readGlobal. Need to reconsider exceptions thrown from there:
 						// BufferedReader wraps String and unlikely to throw IOException, perhaps, log is enough?
-						getContext().getLog().dump(getClass(), Error, ex, null);
+						getSessionContext().getLog().dump(getClass(), Error, ex, null);
 						// XXX need to decide what to do this. failure to read single revision shall not break complete cycle
 					}
 				}
@@ -224,10 +220,10 @@
 			try {
 				file2read = new File(getWorkingDir(), HgTags.getPath());
 				tags.readGlobal(file2read); // XXX replace with HgDataFile.workingCopy
-				file2read = new File(repoDir, HgLocalTags.getName());
+				file2read = impl.getFileFromRepoDir(HgLocalTags.getName()); // XXX pass internalrepo to readLocal, keep filename there
 				tags.readLocal(file2read);
 			} catch (IOException ex) {
-				getContext().getLog().dump(getClass(), Error, ex, null);
+				getSessionContext().getLog().dump(getClass(), Error, ex, null);
 				throw new HgInvalidControlFileException("Failed to read tags", ex, file2read);
 			}
 		}
@@ -241,7 +237,7 @@
 	 */
 	public HgBranches getBranches() throws HgInvalidControlFileException {
 		if (branches == null) {
-			branches = new HgBranches(this);
+			branches = new HgBranches(impl);
 			branches.collect(ProgressSupport.Factory.get(null));
 		}
 		return branches;
@@ -253,7 +249,7 @@
 	 */
 	public HgMergeState getMergeState() {
 		if (mergeState == null) {
-			mergeState = new HgMergeState(this);
+			mergeState = new HgMergeState(impl);
 		}
 		return mergeState;
 	}
@@ -289,7 +285,7 @@
 	 * @throws HgInvalidControlFileException if attempt to read information about working copy parents from dirstate failed 
 	 */
 	public Pair<Nodeid,Nodeid> getWorkingCopyParents() throws HgInvalidControlFileException {
-		return HgDirstate.readParents(this, new File(repoDir, Dirstate.getName()));
+		return HgDirstate.readParents(impl);
 	}
 	
 	/**
@@ -298,7 +294,7 @@
 	 */
 	public String getWorkingCopyBranchName() throws HgInvalidControlFileException {
 		if (wcBranch == null) {
-			wcBranch = HgDirstate.readBranch(this, new File(repoDir, "branch"));
+			wcBranch = HgDirstate.readBranch(impl);
 		}
 		return wcBranch;
 	}
@@ -328,12 +324,12 @@
 	public HgRepoConfig getConfiguration() /* XXX throws HgInvalidControlFileException? Description of the exception suggests it is only for files under ./hg/*/ {
 		if (repoConfig == null) {
 			try {
-				ConfigFile configFile = impl.readConfiguration(this, getRepositoryRoot());
+				ConfigFile configFile = impl.readConfiguration();
 				repoConfig = new HgRepoConfig(configFile);
 			} catch (IOException ex) {
 				String m = "Errors while reading user configuration file";
-				getContext().getLog().dump(getClass(), Warn, ex, m);
-				return new HgRepoConfig(new ConfigFile(getContext())); // empty config, do not cache, allow to try once again
+				getSessionContext().getLog().dump(getClass(), Warn, ex, m);
+				return new HgRepoConfig(new ConfigFile(getSessionContext())); // empty config, do not cache, allow to try once again
 				//throw new HgInvalidControlFileException(m, ex, null);
 			}
 		}
@@ -362,9 +358,8 @@
 				}
 			};
 		}
-		File dirstateFile = new File(repoDir, Dirstate.getName());
-		HgDirstate ds = new HgDirstate(this, dirstateFile, pathFactory, canonicalPath);
-		ds.read(impl.buildFileNameEncodingHelper());
+		HgDirstate ds = new HgDirstate(impl, pathFactory, canonicalPath);
+		ds.read();
 		return ds;
 	}
 
@@ -381,7 +376,7 @@
 			try {
 				final List<String> errors = ignore.read(ignoreFile);
 				if (errors != null) {
-					getContext().getLog().dump(getClass(), Warn, "Syntax errors parsing %s:\n%s", ignoreFile.getName(), Internals.join(errors, ",\n"));
+					getSessionContext().getLog().dump(getClass(), Warn, "Syntax errors parsing %s:\n%s", ignoreFile.getName(), Internals.join(errors, ",\n"));
 				}
 			} catch (IOException ex) {
 				final String m = String.format("Error reading %s file", ignoreFile);
@@ -399,7 +394,7 @@
 	 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em>
 	 */
 	public String getCommitLastMessage() throws HgInvalidControlFileException {
-		File lastMessage = new File(repoDir, LastMessage.getPath());
+		File lastMessage = impl.getFileFromRepoDir(LastMessage.getPath());
 		if (!lastMessage.canRead()) {
 			return null;
 		}
@@ -416,7 +411,7 @@
 				try {
 					fr.close();
 				} catch (IOException ex) {
-					getContext().getLog().dump(getClass(), Warn, "Failed to close %s after read", lastMessage);
+					getSessionContext().getLog().dump(getClass(), Warn, "Failed to close %s after read", lastMessage);
 				}
 			}
 		}
@@ -439,7 +434,7 @@
 	public HgRepositoryLock getWorkingDirLock() {
 		if (wdLock == null) {
 			int timeout = getLockTimeout();
-			File lf = new File(getRepositoryRoot(), "wlock");
+			File lf = impl.getFileFromRepoDir("wlock");
 			synchronized (this) {
 				if (wdLock == null) {
 					wdLock = new HgRepositoryLock(lf, timeout);
@@ -453,7 +448,7 @@
 	public HgRepositoryLock getStoreLock() {
 		if (storeLock == null) {
 			int timeout = getLockTimeout();
-			File fl = new File(getRepositoryRoot(), repoPathHelper.rewrite("lock").toString());
+			File fl = impl.getFileFromRepoDir(repoPathHelper.rewrite("lock").toString());
 			synchronized (this) {
 				if (storeLock == null) {
 					storeLock = new HgRepositoryLock(fl, timeout);
@@ -470,14 +465,17 @@
 	 */
 	public HgBookmarks getBookmarks() throws HgInvalidControlFileException {
 		if (bookmarks == null) {
-			bookmarks = new HgBookmarks(this);
+			bookmarks = new HgBookmarks(impl);
 			bookmarks.read();
 		}
 		return bookmarks;
 	}
 
-	/*package-local*/ DataAccessProvider getDataAccess() {
-		return dataAccess;
+	/**
+	 * @return session environment of the repository
+	 */
+	public SessionContext getSessionContext() {
+		return sessionContext;
 	}
 
 	/**
@@ -492,7 +490,7 @@
 		}
 		File f = new File(repoDir, path.toString());
 		if (f.exists()) {
-			RevlogStream s = new RevlogStream(dataAccess, f);
+			RevlogStream s = new RevlogStream(impl.getDataAccess(), f);
 			if (impl.shallCacheRevlogs()) {
 				streamsCache.put(path, new SoftReference<RevlogStream>(s));
 			}
@@ -502,9 +500,9 @@
 				try {
 					File fake = File.createTempFile(f.getName(), null);
 					fake.deleteOnExit();
-					return new RevlogStream(dataAccess, fake);
+					return new RevlogStream(impl.getDataAccess(), fake);
 				} catch (IOException ex) {
-					getContext().getLog().dump(getClass(), Info, ex, null);
+					getSessionContext().getLog().dump(getClass(), Info, ex, null);
 				}
 			}
 		}
@@ -523,16 +521,12 @@
 		return new File(getWorkingDir(), dataFile.getPath().toString());
 	}
 	
-	/*package-local*/ SessionContext getContext() {
-		return sessionContext;
-	}
-	
 	/*package-local*/ Internals getImplHelper() {
 		return impl;
 	}
 
 	private List<Filter> instantiateFilters(Path p, Filter.Options opts) {
-		List<Filter.Factory> factories = impl.getFilters(this);
+		List<Filter.Factory> factories = impl.getFilters();
 		if (factories.isEmpty()) {
 			return Collections.emptyList();
 		}
--- a/src/org/tmatesoft/hg/repo/HgTags.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgTags.java	Thu Aug 16 17:08:34 2012 +0200
@@ -109,7 +109,7 @@
 				continue;
 			}
 			if (line.length() < 40+2 /*nodeid, space and at least single-char tagname*/) {
-				repo.getContext().getLog().dump(getClass(), Warn, "Bad tags line: %s", line); 
+				repo.getSessionContext().getLog().dump(getClass(), Warn, "Bad tags line: %s", line); 
 				continue;
 			}
 			int spacePos = line.indexOf(' ');
@@ -153,7 +153,7 @@
 				}
 				
 			} else {
-				repo.getContext().getLog().dump(getClass(), Warn, "Bad tags line: %s", line);
+				repo.getSessionContext().getLog().dump(getClass(), Warn, "Bad tags line: %s", line);
 			}
 		}
 	}
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Thu Aug 16 17:08:34 2012 +0200
@@ -365,7 +365,7 @@
 						}
 					}
 				} catch (HgRuntimeException ex) {
-					repo.getContext().getLog().dump(getClass(), Warn, ex, null);
+					repo.getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 					inspector.invalid(fname, ex);
 				}
 			}
@@ -457,7 +457,7 @@
 						inspector.modified(fname);
 					}
 				} catch (HgRuntimeException ex) {
-					repo.getContext().getLog().dump(getClass(), Warn, ex, null);
+					repo.getSessionContext().getLog().dump(getClass(), Warn, ex, null);
 					inspector.invalid(fname, ex);
 				}
 				baseRevNames.remove(fname); // consumed, processed, handled.
@@ -494,7 +494,7 @@
 	private boolean areTheSame(FileInfo f, final byte[] data, Path p) throws HgInvalidFileException {
 		ReadableByteChannel is = null;
 		class Check implements ByteChannel {
-			final boolean debug = repo.getContext().getLog().isDebug(); 
+			final boolean debug = repo.getSessionContext().getLog().isDebug(); 
 			boolean sameSoFar = true;
 			int x = 0;
 
@@ -514,7 +514,7 @@
 								int offset = max(0, x - 4);
 								exp = new String(data, offset, min(data.length - offset, 20));
 							}
-							repo.getContext().getLog().dump(getClass(), Debug, "expected >>%s<< but got >>%s<<", exp, new String(xx));
+							repo.getSessionContext().getLog().dump(getClass(), Debug, "expected >>%s<< but got >>%s<<", exp, new String(xx));
 						}
 						sameSoFar = false;
 						break;
@@ -547,7 +547,7 @@
 				try {
 					is.close();
 				} catch (IOException ex) {
-					repo.getContext().getLog().dump(getClass(), Info, ex, null);
+					repo.getSessionContext().getLog().dump(getClass(), Info, ex, null);
 				}
 				is = f.newInputChannel();
 				fb.clear();
@@ -559,7 +559,7 @@
 			}
 			return check.ultimatelyTheSame();
 		} catch (CancelledException ex) {
-			repo.getContext().getLog().dump(getClass(), Warn, ex, "Unexpected cancellation");
+			repo.getSessionContext().getLog().dump(getClass(), Warn, ex, "Unexpected cancellation");
 			return check.ultimatelyTheSame();
 		} catch (IOException ex) {
 			throw new HgInvalidFileException("File comparison failed", ex).setFileName(p);
@@ -568,7 +568,7 @@
 				try {
 					is.close();
 				} catch (IOException ex) {
-					repo.getContext().getLog().dump(getClass(), Info, ex, null);
+					repo.getSessionContext().getLog().dump(getClass(), Info, ex, null);
 				}
 			}
 		}
@@ -631,7 +631,7 @@
 //		final Path[] dirs = f.toArray(new Path[d.size()]);
 		if (d.isEmpty()) {
 			final Path[] files = f.toArray(new Path[f.size()]);
-			FileIterator fi = new FileListIterator(hgRepo.getContext(), hgRepo.getWorkingDir(), files);
+			FileIterator fi = new FileListIterator(hgRepo.getSessionContext(), hgRepo.getWorkingDir(), files);
 			return new HgWorkingCopyStatusCollector(hgRepo, fi);
 		}
 		//
--- a/src/org/tmatesoft/hg/repo/Revlog.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/Revlog.java	Thu Aug 16 17:08:34 2012 +0200
@@ -202,7 +202,7 @@
 			throw new IllegalArgumentException();
 		}
 		try {
-			ContentPipe insp = new ContentPipe(sink, 0, repo.getContext().getLog());
+			ContentPipe insp = new ContentPipe(sink, 0, repo.getSessionContext().getLog());
 			insp.checkCancelled();
 			content.iterate(revisionIndex, revisionIndex, true, insp);
 			insp.checkFailed();
--- a/src/org/tmatesoft/hg/repo/ext/MqManager.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/src/org/tmatesoft/hg/repo/ext/MqManager.java	Thu Aug 16 17:08:34 2012 +0200
@@ -64,7 +64,7 @@
 		applied = allKnown = Collections.emptyList();
 		queueNames = Collections.emptyList();
 		File repoDir = HgInternals.getRepositoryDir(repo);
-		final LogFacility log = HgInternals.getContext(repo).getLog();
+		final LogFacility log = repo.getSessionContext().getLog();
 		try {
 			File queues = new File(repoDir, "patches.queues");
 			if (queues.isFile()) {
--- a/test/org/tmatesoft/hg/test/TestFileFlags.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/test/org/tmatesoft/hg/test/TestFileFlags.java	Thu Aug 16 17:08:34 2012 +0200
@@ -28,7 +28,6 @@
 import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.RelativePathRewrite;
 import org.tmatesoft.hg.repo.HgDataFile;
-import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgManifest.Flags;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.util.FileInfo;
@@ -66,7 +65,7 @@
 	public void testFlagsInWorkingCopy() throws Exception {
 		File repoRoot = repo.getWorkingDir();
 		Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), repo.getToRepoPathHelper()));
-		FileWalker fw = new FileWalker(HgInternals.getContext(repo), repoRoot, pathSrc);
+		FileWalker fw = new FileWalker(repo.getSessionContext(), repoRoot, pathSrc);
 		
 		if (Internals.runningOnWindows()) {
 			System.out.println("Executing tests on Windows, no actual file flags in working area are checked");
--- a/test/org/tmatesoft/hg/test/TestIncoming.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/test/org/tmatesoft/hg/test/TestIncoming.java	Thu Aug 16 17:08:34 2012 +0200
@@ -32,8 +32,7 @@
 import org.tmatesoft.hg.core.HgIncomingCommand;
 import org.tmatesoft.hg.core.HgLogCommand;
 import org.tmatesoft.hg.core.Nodeid;
-import org.tmatesoft.hg.internal.BasicSessionContext;
-import org.tmatesoft.hg.internal.Internals;
+import org.tmatesoft.hg.internal.RepoInitializer;
 import org.tmatesoft.hg.repo.HgLookup;
 import org.tmatesoft.hg.repo.HgRemoteRepository;
 import org.tmatesoft.hg.repo.HgRepository;
@@ -135,9 +134,9 @@
 
 	static File initEmptyTempRepo(String dirName) throws IOException {
 		File dest = createEmptyDir(dirName);
-		Internals implHelper = new Internals(new BasicSessionContext(null));
-		implHelper.setStorageConfig(1, STORE | FNCACHE | DOTENCODE);
-		implHelper.initEmptyRepository(new File(dest, ".hg"));
+		RepoInitializer ri = new RepoInitializer();
+		ri.setRequires(STORE | FNCACHE | DOTENCODE);
+		ri.initEmptyRepository(new File(dest, ".hg"));
 		return dest;
 	}
 }
--- a/test/org/tmatesoft/hg/test/TestStorePath.java	Mon Aug 13 19:24:29 2012 +0200
+++ b/test/org/tmatesoft/hg/test/TestStorePath.java	Thu Aug 16 17:08:34 2012 +0200
@@ -16,6 +16,8 @@
  */
 package org.tmatesoft.hg.test;
 
+import static org.tmatesoft.hg.internal.RequiresFile.*;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -25,8 +27,10 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.tmatesoft.hg.core.SessionContext;
 import org.tmatesoft.hg.internal.BasicSessionContext;
 import org.tmatesoft.hg.internal.Internals;
+import org.tmatesoft.hg.internal.RepoInitializer;
 import org.tmatesoft.hg.util.PathRewrite;
 
 /**
@@ -42,7 +46,8 @@
 	private PathRewrite storePathHelper;
 	private final Map<String, Object> propertyOverrides = new HashMap<String, Object>();
 
-	private Internals internals;
+	private final SessionContext sessionCtx;
+	private final RepoInitializer repoInit;
 
 	public static void main(String[] args) throws Throwable {
 		final TestStorePath test = new TestStorePath();
@@ -54,9 +59,9 @@
 	
 	public TestStorePath() {
 		propertyOverrides.put("hg.consolelog.debug", true);
-		internals = new Internals(new BasicSessionContext(propertyOverrides, null));
-		internals.setStorageConfig(1, 0x7);
-		storePathHelper = internals.buildDataFilesHelper();
+		sessionCtx = new BasicSessionContext(propertyOverrides, null);
+		repoInit = new RepoInitializer().setRequires(STORE + FNCACHE + DOTENCODE);
+		storePathHelper = repoInit.buildDataFilesHelper(sessionCtx);
 	}
 	
 	@Before
@@ -120,11 +125,11 @@
 		String s = "Привет.txt";
 		//
 		propertyOverrides.put(Internals.CFG_PROPERTY_FS_FILENAME_ENCODING, "cp1251");
-		PathRewrite sph = internals.buildDataFilesHelper();
+		PathRewrite sph = repoInit.buildDataFilesHelper(sessionCtx);
 		errorCollector.checkThat(sph.rewrite(s), CoreMatchers.<CharSequence>equalTo("store/data/~cf~f0~e8~e2~e5~f2.txt.i"));
 		//
 		propertyOverrides.put(Internals.CFG_PROPERTY_FS_FILENAME_ENCODING, "UTF8");
-		sph = internals.buildDataFilesHelper();
+		sph = repoInit.buildDataFilesHelper(sessionCtx);
 		errorCollector.checkThat(sph.rewrite(s), CoreMatchers.<CharSequence>equalTo("store/data/~d0~9f~d1~80~d0~b8~d0~b2~d0~b5~d1~82.txt.i"));
 	}
 }