diff src/org/tmatesoft/hg/internal/Internals.java @ 411:464b4404e75d smartgit3

Issue 29: Bad storage path translation - translate Unicode chars to filesystem encoding
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 20 Mar 2012 17:56:50 +0100
parents 0f5696623512
children 63c5a9d7ca3f
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/Internals.java	Fri Mar 16 20:19:51 2012 +0100
+++ b/src/org/tmatesoft/hg/internal/Internals.java	Tue Mar 20 17:56:50 2012 +0100
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -56,13 +57,30 @@
 	 */
 	public static final String CFG_PROPERTY_REVLOG_STREAM_CACHE = "hg4j.repo.disable_revlog_cache";
 	
+	/**
+	 * Name of charset to use when translating Unicode filenames to Mercurial storage paths, string, 
+	 * to resolve with {@link Charset#forName(String)}.
+	 * E.g. <code>"cp1251"</code> or <code>"Latin-1"</code>.
+	 * 
+	 * <p>Mercurial uses system encoding when mangling storage paths. Default value
+	 * based on 'file.encoding' Java system property is usually fine here, however
+	 * in certain scenarios it may be desirable to force a different one, and this 
+	 * property is exactly for this purpose.
+	 * 
+	 * <p>E.g. Eclipse defaults to project encoding (Launch config, Common page) when launching an application, 
+	 * and if your project happen to use anything but filesystem default (say, UTF8 on cp1251 system),
+	 * native storage paths won't match
+	 */
+	public static final String CFG_PROPERT_FS_FILENAME_ENCODING = "hg.fs.filename.encoding";
+	
 	private int requiresFlags = 0;
 	private List<Filter.Factory> filterFactories;
+	private final SessionContext sessionContext;
 	private final boolean isCaseSensitiveFileSystem;
 	private final boolean shallCacheRevlogsInRepo;
-	
 
 	public Internals(SessionContext ctx) {
+		this.sessionContext = ctx;
 		isCaseSensitiveFileSystem = !runningOnWindows();
 		Object p = ctx.getProperty(CFG_PROPERTY_REVLOG_STREAM_CACHE, true);
 		shallCacheRevlogsInRepo = p instanceof Boolean ? ((Boolean) p).booleanValue() : Boolean.parseBoolean(String.valueOf(p));
@@ -91,7 +109,21 @@
 
 	// XXX perhaps, should keep both fields right here, not in the HgRepository
 	public PathRewrite buildDataFilesHelper() {
-		return new StoragePathHelper((requiresFlags & STORE) != 0, (requiresFlags & FNCACHE) != 0, (requiresFlags & DOTENCODE) != 0);
+		Object altEncoding = sessionContext.getProperty(CFG_PROPERT_FS_FILENAME_ENCODING, null);
+		Charset cs;
+		if (altEncoding == null) {
+			cs = Charset.defaultCharset();
+		} else {
+			try {
+				cs = Charset.forName(altEncoding.toString());
+			} 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().error(getClass(), ex, String.format("Bad configuration value for filename encoding %s", altEncoding));
+				cs = Charset.defaultCharset();
+			}
+		}
+		return new StoragePathHelper((requiresFlags & STORE) != 0, (requiresFlags & FNCACHE) != 0, (requiresFlags & DOTENCODE) != 0, cs);
 	}
 
 	public PathRewrite buildRepositoryFilesHelper() {