changeset 292:a415fe296a50

Refactor PathRewrite to accept any char sequence, not only string
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 14 Sep 2011 02:16:19 +0200
parents 1483e57541ef
children 9774f47d904d
files src/org/tmatesoft/hg/core/HgCloneCommand.java src/org/tmatesoft/hg/internal/Internals.java src/org/tmatesoft/hg/internal/RelativePathRewrite.java src/org/tmatesoft/hg/internal/StoragePathHelper.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/util/Path.java src/org/tmatesoft/hg/util/PathPool.java src/org/tmatesoft/hg/util/PathRewrite.java test/org/tmatesoft/hg/test/StatusOutputParser.java test/org/tmatesoft/hg/test/TestStorePath.java
diffstat 10 files changed, 51 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCloneCommand.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java	Wed Sep 14 02:16:19 2011 +0200
@@ -209,7 +209,7 @@
 				revisionSequence.clear();
 				fncacheFiles.add("data/" + name + ".i"); // FIXME this is pure guess, 
 				// need to investigate more how filenames are kept in fncache
-				File file = new File(hgDir, filename = storagePathHelper.rewrite(name));
+				File file = new File(hgDir, filename = storagePathHelper.rewrite(name).toString());
 				file.getParentFile().mkdirs();
 				indexFile = new FileOutputStream(file);
 			} catch (IOException ex) {
--- a/src/org/tmatesoft/hg/internal/Internals.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/internal/Internals.java	Wed Sep 14 02:16:19 2011 +0200
@@ -54,17 +54,12 @@
 	public PathRewrite buildRepositoryFilesHelper() {
 		if ((requiresFlags & STORE) != 0) {
 			return new PathRewrite() {
-				public String rewrite(String path) {
+				public CharSequence rewrite(CharSequence path) {
 					return "store/" + path;
 				}
 			};
 		} else {
-			return new PathRewrite() {
-				public String rewrite(String path) {
-					//no-op
-					return path;
-				}
-			};
+			return new PathRewrite.Empty();
 		}
 	}
 
@@ -108,4 +103,8 @@
 		new File(hgDir, "store").mkdir(); // with that, hg verify says ok.
 	}
 
+	public static boolean runningOnWindows() {
+		return System.getProperty("os.name").indexOf("Windows") != -1;
+	}
+
 }
--- a/src/org/tmatesoft/hg/internal/RelativePathRewrite.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/internal/RelativePathRewrite.java	Wed Sep 14 02:16:19 2011 +0200
@@ -37,7 +37,8 @@
 		this.rootPath = rootPath;
 	}
 
-	public String rewrite(String path) {
+	public CharSequence rewrite(CharSequence p) {
+		String path = p == null ? null : p.toString();
 		if (path != null && path.startsWith(rootPath)) {
 			if (path.length() == rootPath.length()) {
 				return "";
--- a/src/org/tmatesoft/hg/internal/StoragePathHelper.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/internal/StoragePathHelper.java	Wed Sep 14 02:16:19 2011 +0200
@@ -43,13 +43,14 @@
 	// FIXME document what path argument is, whether it includes .i or .d, and whether it's 'normalized' (slashes) or not.
 	// since .hg/store keeps both .i files and files without extension (e.g. fncache), guees, for data == false 
 	// we shall assume path has extension
-	public String rewrite(String path) {
+	public CharSequence rewrite(CharSequence p) {
 		final String STR_STORE = "store/";
 		final String STR_DATA = "data/";
 		final String STR_DH = "dh/";
 		final String reservedChars = "\\:*?\"<>|";
 		char[] hexByte = new char[2];
 		
+		String path = p.toString();
 		path = path.replace(".hg/", ".hg.hg/").replace(".i/", ".i.hg/").replace(".d/", ".d.hg/");
 		StringBuilder sb = new StringBuilder(path.length() << 1);
 		if (store || fncache) {
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Wed Sep 14 02:16:19 2011 +0200
@@ -32,6 +32,7 @@
 import org.tmatesoft.hg.internal.DataAccessProvider;
 import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.Filter;
+import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.RequiresFile;
 import org.tmatesoft.hg.internal.RevlogStream;
 import org.tmatesoft.hg.internal.SubrepoManager;
@@ -71,6 +72,7 @@
 	private final PathRewrite normalizePath;
 	private final PathRewrite dataPathHelper;
 	private final PathRewrite repoPathHelper;
+	private final boolean isCaseSensitiveFileSystem;
 
 	private HgChangelog changelog;
 	private HgManifest manifest;
@@ -93,6 +95,7 @@
 		dataAccess = null;
 		dataPathHelper = repoPathHelper = null;
 		normalizePath = null;
+		isCaseSensitiveFileSystem = !Internals.runningOnWindows();
 	}
 	
 	HgRepository(String repositoryPath, File repositoryRoot) {
@@ -106,12 +109,14 @@
 		}
 		repoLocation = repositoryPath;
 		dataAccess = new DataAccessProvider();
-		final boolean runningOnWindows = System.getProperty("os.name").indexOf("Windows") != -1;
+		final boolean runningOnWindows = Internals.runningOnWindows();
+		isCaseSensitiveFileSystem = !runningOnWindows;
 		if (runningOnWindows) {
 			normalizePath = new PathRewrite() {
 					
-					public String rewrite(String path) {
+					public CharSequence rewrite(CharSequence p) {
 						// TODO handle . and .. (although unlikely to face them from GUI client)
+						String path = p.toString();
 						path = path.replace('\\', '/').replace("//", "/");
 						if (path.startsWith("/")) {
 							path = path.substring(1);
@@ -142,7 +147,7 @@
 	
 	public HgChangelog getChangelog() {
 		if (this.changelog == null) {
-			String storagePath = repoPathHelper.rewrite("00changelog.i");
+			CharSequence storagePath = repoPathHelper.rewrite("00changelog.i");
 			RevlogStream content = resolve(Path.create(storagePath), true);
 			this.changelog = new HgChangelog(this, content);
 		}
@@ -207,8 +212,8 @@
 	}
 	
 	public HgDataFile getFileNode(String path) {
-		String nPath = normalizePath.rewrite(path);
-		String storagePath = dataPathHelper.rewrite(nPath);
+		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) {
@@ -218,7 +223,7 @@
 	}
 
 	public HgDataFile getFileNode(Path path) {
-		String storagePath = dataPathHelper.rewrite(path.toString());
+		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?
 		if (content == null) {
@@ -273,7 +278,16 @@
 	// 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(PathPool pathPool) {
-		return new HgDirstate(this, new File(repoDir, "dirstate"), pathPool);
+		PathRewrite canonicalPath = null;
+		if (!isCaseSensitiveFileSystem) {
+			canonicalPath = new PathRewrite() {
+
+				public CharSequence rewrite(CharSequence path) {
+					return path.toString().toLowerCase();
+				}
+			};
+		}
+		return new HgDirstate(this, new File(repoDir, "dirstate"), pathPool, canonicalPath);
 	}
 
 	/**
--- a/src/org/tmatesoft/hg/util/Path.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/util/Path.java	Wed Sep 14 02:16:19 2011 +0200
@@ -101,14 +101,19 @@
 		return CompareResult.Unrelated;
 	}
 
-	public static Path create(String path) {
+	public static Path create(CharSequence path) {
 		if (path == null) {
 			throw new IllegalArgumentException();
 		}
-		if (path.indexOf('\\') != -1) {
+		if (path instanceof Path) {
+			Path o = (Path) path;
+			return o;
+		}
+		String p = path.toString();
+		if (p.indexOf('\\') != -1) {
 			throw new IllegalArgumentException();
 		}
-		Path rv = new Path(path);
+		Path rv = new Path(p);
 		return rv;
 	}
 
--- a/src/org/tmatesoft/hg/util/PathPool.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/util/PathPool.java	Wed Sep 14 02:16:19 2011 +0200
@@ -36,14 +36,14 @@
 	}
 
 	public Path path(String p) {
-		p = pathRewrite.rewrite(p);
+		p = pathRewrite.rewrite(p).toString();
 		return get(p, true);
 	}
 
 	// pipes path object through cache to reuse instance, if possible
 	// TODO unify with Pool<Path>
 	public Path path(Path p) {
-		String s = pathRewrite.rewrite(p.toString());
+		String s = pathRewrite.rewrite(p).toString();
 		Path cached = get(s, false);
 		if (cached == null) {
 			cache.put(s, new SoftReference<Path>(cached = p));
--- a/src/org/tmatesoft/hg/util/PathRewrite.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/src/org/tmatesoft/hg/util/PathRewrite.java	Wed Sep 14 02:16:19 2011 +0200
@@ -27,11 +27,10 @@
  */
 public interface PathRewrite {
 
-	// XXX think over CharSequence use instead of String
-	public String rewrite(String path);
+	public CharSequence rewrite(CharSequence path);
 	
 	public static class Empty implements PathRewrite {
-		public String rewrite(String path) {
+		public CharSequence rewrite(CharSequence path) {
 			return path;
 		}
 	}
@@ -51,7 +50,7 @@
 			return this;
 		}
 
-		public String rewrite(String path) {
+		public CharSequence rewrite(CharSequence path) {
 			for (PathRewrite pr : chain) {
 				path = pr.rewrite(path);
 			}
--- a/test/org/tmatesoft/hg/test/StatusOutputParser.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/test/org/tmatesoft/hg/test/StatusOutputParser.java	Wed Sep 14 02:16:19 2011 +0200
@@ -48,10 +48,10 @@
 			
 			private final boolean winPathSeparator = File.separatorChar == '\\';
 
-			public String rewrite(String s) {
+			public CharSequence rewrite(CharSequence s) {
 				if (winPathSeparator) {
 					// Java impl always give slashed path, while Hg uses local, os-specific convention
-					s = s.replace('\\', '/'); 
+					s = s.toString().replace('\\', '/'); 
 				}
 				return s;
 			}
--- a/test/org/tmatesoft/hg/test/TestStorePath.java	Wed Sep 14 02:12:47 2011 +0200
+++ b/test/org/tmatesoft/hg/test/TestStorePath.java	Wed Sep 14 02:16:19 2011 +0200
@@ -16,9 +16,9 @@
  */
 package org.tmatesoft.hg.test;
 
-import static org.hamcrest.CoreMatchers.equalTo;
 import junit.framework.Assert;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Rule;
 import org.junit.Test;
 import org.tmatesoft.hg.internal.Internals;
@@ -66,8 +66,8 @@
 		String n3 = "AUX.THE-QUICK-BROWN-FOX-JU:MPS-OVER-THE-LAZY-DOG-THE-QUICK-BROWN-FOX-JUMPS-OVER-THE-LAZY-DOG.TXT";
 		String r3 = "store/dh/au~78.the-quick-brown-fox-ju~3amps-over-the-lazy-dog-the-quick-brown-fox-jud4dcadd033000ab2b26eb66bae1906bcb15d4a70.i";
 		// TODO segment[8] == [. ], segment[8] in the middle of windows reserved name or character (to see if ~xx is broken)
-		errorCollector.checkThat(storePathHelper.rewrite(n1), equalTo(r1));
-		errorCollector.checkThat(storePathHelper.rewrite(n2), equalTo(r2));
-		errorCollector.checkThat(storePathHelper.rewrite(n3), equalTo(r3));
+		errorCollector.checkThat(storePathHelper.rewrite(n1), CoreMatchers.<CharSequence>equalTo(r1));
+		errorCollector.checkThat(storePathHelper.rewrite(n2), CoreMatchers.<CharSequence>equalTo(r2));
+		errorCollector.checkThat(storePathHelper.rewrite(n3), CoreMatchers.<CharSequence>equalTo(r3));
 	}
 }