comparison src/org/tmatesoft/hg/internal/Internals.java @ 414:bb278ccf9866

Pull changes from smartgit3 branch
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 21 Mar 2012 20:51:12 +0100
parents 7f27122011c3 63c5a9d7ca3f
children ee8264d80747
comparison
equal deleted inserted replaced
413:7f27122011c3 414:bb278ccf9866
19 import static org.tmatesoft.hg.internal.RequiresFile.*; 19 import static org.tmatesoft.hg.internal.RequiresFile.*;
20 20
21 import java.io.File; 21 import java.io.File;
22 import java.io.FileOutputStream; 22 import java.io.FileOutputStream;
23 import java.io.IOException; 23 import java.io.IOException;
24 import java.nio.charset.Charset;
24 import java.util.ArrayList; 25 import java.util.ArrayList;
25 import java.util.Arrays; 26 import java.util.Arrays;
26 import java.util.Collections; 27 import java.util.Collections;
28 import java.util.Iterator;
27 import java.util.LinkedHashSet; 29 import java.util.LinkedHashSet;
28 import java.util.List; 30 import java.util.List;
29 import java.util.StringTokenizer; 31 import java.util.StringTokenizer;
30 32
31 import org.tmatesoft.hg.core.SessionContext; 33 import org.tmatesoft.hg.core.SessionContext;
53 * XXX perhaps, need to respect this property not only for data files, but for manifest and changelog as well? 55 * XXX perhaps, need to respect this property not only for data files, but for manifest and changelog as well?
54 * (@see HgRepository#getChangelog and #getManifest()) 56 * (@see HgRepository#getChangelog and #getManifest())
55 */ 57 */
56 public static final String CFG_PROPERTY_REVLOG_STREAM_CACHE = "hg4j.repo.disable_revlog_cache"; 58 public static final String CFG_PROPERTY_REVLOG_STREAM_CACHE = "hg4j.repo.disable_revlog_cache";
57 59
60 /**
61 * Name of charset to use when translating Unicode filenames to Mercurial storage paths, string,
62 * to resolve with {@link Charset#forName(String)}.
63 * E.g. <code>"cp1251"</code> or <code>"Latin-1"</code>.
64 *
65 * <p>Mercurial uses system encoding when mangling storage paths. Default value
66 * based on 'file.encoding' Java system property is usually fine here, however
67 * in certain scenarios it may be desirable to force a different one, and this
68 * property is exactly for this purpose.
69 *
70 * <p>E.g. Eclipse defaults to project encoding (Launch config, Common page) when launching an application,
71 * and if your project happen to use anything but filesystem default (say, UTF8 on cp1251 system),
72 * native storage paths won't match
73 */
74 public static final String CFG_PROPERTY_FS_FILENAME_ENCODING = "hg.fs.filename.encoding";
75
58 private int requiresFlags = 0; 76 private int requiresFlags = 0;
59 private List<Filter.Factory> filterFactories; 77 private List<Filter.Factory> filterFactories;
78 private final SessionContext sessionContext;
60 private final boolean isCaseSensitiveFileSystem; 79 private final boolean isCaseSensitiveFileSystem;
61 private final boolean shallCacheRevlogsInRepo; 80 private final boolean shallCacheRevlogsInRepo;
62
63 81
64 public Internals(SessionContext ctx) { 82 public Internals(SessionContext ctx) {
83 this.sessionContext = ctx;
65 isCaseSensitiveFileSystem = !runningOnWindows(); 84 isCaseSensitiveFileSystem = !runningOnWindows();
66 Object p = ctx.getProperty(CFG_PROPERTY_REVLOG_STREAM_CACHE, true); 85 Object p = ctx.getProperty(CFG_PROPERTY_REVLOG_STREAM_CACHE, true);
67 shallCacheRevlogsInRepo = p instanceof Boolean ? ((Boolean) p).booleanValue() : Boolean.parseBoolean(String.valueOf(p)); 86 shallCacheRevlogsInRepo = p instanceof Boolean ? ((Boolean) p).booleanValue() : Boolean.parseBoolean(String.valueOf(p));
68 } 87 }
69 88
80 requiresFlags = flags; 99 requiresFlags = flags;
81 } 100 }
82 101
83 public PathRewrite buildNormalizePathRewrite() { 102 public PathRewrite buildNormalizePathRewrite() {
84 if (runningOnWindows()) { 103 if (runningOnWindows()) {
85 return new PathRewrite() { 104 return new WinToNixPathRewrite();
86
87 public CharSequence rewrite(CharSequence p) {
88 // TODO handle . and .. (although unlikely to face them from GUI client)
89 String path = p.toString();
90 path = path.replace('\\', '/').replace("//", "/");
91 if (path.startsWith("/")) {
92 path = path.substring(1);
93 }
94 return path;
95 }
96 };
97 } else { 105 } else {
98 return new PathRewrite.Empty(); // or strip leading slash, perhaps? 106 return new PathRewrite.Empty(); // or strip leading slash, perhaps?
99 } 107 }
100 } 108 }
101 109
102 // XXX perhaps, should keep both fields right here, not in the HgRepository 110 // XXX perhaps, should keep both fields right here, not in the HgRepository
103 public PathRewrite buildDataFilesHelper() { 111 public PathRewrite buildDataFilesHelper() {
104 return new StoragePathHelper((requiresFlags & STORE) != 0, (requiresFlags & FNCACHE) != 0, (requiresFlags & DOTENCODE) != 0); 112 // Note, tests in TestStorePath depend on the encoding not being cached
113 Charset cs = getFileEncoding();
114 // StoragePathHelper needs fine-grained control over char encoding, hence doesn't use EncodingHelper
115 return new StoragePathHelper((requiresFlags & STORE) != 0, (requiresFlags & FNCACHE) != 0, (requiresFlags & DOTENCODE) != 0, cs);
105 } 116 }
106 117
107 public PathRewrite buildRepositoryFilesHelper() { 118 public PathRewrite buildRepositoryFilesHelper() {
108 if ((requiresFlags & STORE) != 0) { 119 if ((requiresFlags & STORE) != 0) {
109 return new PathRewrite() { 120 return new PathRewrite() {
153 new File(hgDir, "store").mkdir(); // with that, hg verify says ok. 164 new File(hgDir, "store").mkdir(); // with that, hg verify says ok.
154 } 165 }
155 166
156 public boolean isCaseSensitiveFileSystem() { 167 public boolean isCaseSensitiveFileSystem() {
157 return isCaseSensitiveFileSystem; 168 return isCaseSensitiveFileSystem;
169 }
170
171 public EncodingHelper buildFileNameEncodingHelper() {
172 return new EncodingHelper(getFileEncoding());
173 }
174
175 private Charset getFileEncoding() {
176 Object altEncoding = sessionContext.getProperty(CFG_PROPERTY_FS_FILENAME_ENCODING, null);
177 Charset cs;
178 if (altEncoding == null) {
179 cs = Charset.defaultCharset();
180 } else {
181 try {
182 cs = Charset.forName(altEncoding.toString());
183 } catch (IllegalArgumentException ex) {
184 // both IllegalCharsetNameException and UnsupportedCharsetException are subclasses of IAE, too
185 // not severe enough to throw an exception, imo. Just record the fact it's bad ad we ignore it
186 sessionContext.getLog().error(Internals.class, ex, String.format("Bad configuration value for filename encoding %s", altEncoding));
187 cs = Charset.defaultCharset();
188 }
189 }
190 return cs;
158 } 191 }
159 192
160 public static boolean runningOnWindows() { 193 public static boolean runningOnWindows() {
161 return System.getProperty("os.name").indexOf("Windows") != -1; 194 return System.getProperty("os.name").indexOf("Windows") != -1;
162 } 195 }
341 } 374 }
342 375
343 public boolean shallCacheRevlogs() { 376 public boolean shallCacheRevlogs() {
344 return shallCacheRevlogsInRepo; 377 return shallCacheRevlogsInRepo;
345 } 378 }
379
380 public static <T> CharSequence join(Iterable<T> col, CharSequence separator) {
381 if (col == null) {
382 return String.valueOf(col);
383 }
384 Iterator<T> it = col.iterator();
385 if (!it.hasNext()) {
386 return "[]";
387 }
388 String v = String.valueOf(it.next());
389 StringBuilder sb = new StringBuilder(v);
390 while (it.hasNext()) {
391 sb.append(separator);
392 v = String.valueOf(it.next());
393 sb.append(v);
394 }
395 return sb;
396 }
346 } 397 }