# HG changeset patch # User Artem Tikhomirov # Date 1297912114 -3600 # Node ID 8248aae33f7db63c109eca393e583be95242c96a # Parent 1c1891ad1c73c40d950f31d4ff4536cd7dd68965 Adopt FileIterator moving towards WCStatusCollector parameterizing. Improved path handling, move 'em around diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/internal/RelativePathRewrite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/RelativePathRewrite.java Thu Feb 17 04:08:34 2011 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 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 java.io.File; + +import org.tmatesoft.hg.util.PathRewrite; + +/** + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class RelativePathRewrite implements PathRewrite { + + private final String rootPath; + + public RelativePathRewrite(File root) { + this(root.getPath()); + } + + public RelativePathRewrite(String rootPath) { + this.rootPath = rootPath; + } + + public String rewrite(String path) { + if (path != null && path.startsWith(rootPath)) { + if (path.length() == rootPath.length()) { + return ""; + } + return path.substring(rootPath.length() + 1); + } + return path; + } +} diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/repo/HgDirstate.java --- a/src/org/tmatesoft/hg/repo/HgDirstate.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgDirstate.java Thu Feb 17 04:08:34 2011 +0100 @@ -25,6 +25,7 @@ import org.tmatesoft.hg.internal.DataAccess; import org.tmatesoft.hg.internal.DataAccessProvider; +import org.tmatesoft.hg.util.Path; /** @@ -38,6 +39,7 @@ private final DataAccessProvider accessProvider; private final File dirstateFile; + // deliberate String, not Path as it seems useless to keep Path here private Map normal; private Map added; private Map removed; @@ -126,18 +128,21 @@ return rv; } - /*package-local*/ Record checkNormal(String fname) { - return normal.get(fname); + /*package-local*/ Record checkNormal(Path fname) { + return normal.get(fname.toString()); } - /*package-local*/ Record checkAdded(String fname) { - return added.get(fname); + /*package-local*/ Record checkAdded(Path fname) { + return added.get(fname.toString()); + } + /*package-local*/ Record checkRemoved(Path fname) { + return removed.get(fname.toString()); } /*package-local*/ Record checkRemoved(String fname) { return removed.get(fname); } - /*package-local*/ Record checkMerged(String fname) { - return merged.get(fname); + /*package-local*/ Record checkMerged(Path fname) { + return merged.get(fname.toString()); } diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/repo/HgIgnore.java --- a/src/org/tmatesoft/hg/repo/HgIgnore.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgIgnore.java Thu Feb 17 04:08:34 2011 +0100 @@ -25,7 +25,10 @@ import java.util.List; import java.util.regex.Pattern; +import org.tmatesoft.hg.util.Path; + /** + * Handling of ignored paths according to .hgignore configuration * * @author Artem Tikhomirov * @author TMate Software Ltd. @@ -119,8 +122,8 @@ return sb.toString(); } - // TODO use Path and PathGlobMatcher - public boolean isIgnored(String path) { + // TODO use PathGlobMatcher + public boolean isIgnored(Path path) { for (Pattern p : entries) { if (p.matcher(path).find()) { return true; diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Thu Feb 17 04:08:34 2011 +0100 @@ -27,8 +27,10 @@ import org.tmatesoft.hg.internal.ConfigFile; import org.tmatesoft.hg.internal.DataAccessProvider; import org.tmatesoft.hg.internal.Filter; +import org.tmatesoft.hg.internal.RelativePathRewrite; import org.tmatesoft.hg.internal.RequiresFile; import org.tmatesoft.hg.internal.RevlogStream; +import org.tmatesoft.hg.util.FileIterator; import org.tmatesoft.hg.util.FileWalker; import org.tmatesoft.hg.util.Path; import org.tmatesoft.hg.util.PathRewrite; @@ -190,8 +192,13 @@ } // FIXME not sure repository shall create walkers - /*package-local*/ FileWalker createWorkingDirWalker() { - return new FileWalker(repoDir.getParentFile()); + /*package-local*/ FileIterator createWorkingDirWalker() { + File repoRoot = repoDir.getParentFile(); + Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), getPathHelper())); + // 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(repoRoot, pathSrc); } /** diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/repo/HgStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgStatusCollector.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgStatusCollector.java Thu Feb 17 04:08:34 2011 +0100 @@ -161,11 +161,12 @@ inspector.modified(pp.path(fname)); } } else { - String copyOrigin = getOriginIfCopy(repo, fname, r1Files, rev1); + Path copyTarget = pp.path(fname); + Path copyOrigin = getOriginIfCopy(repo, copyTarget, r1Files, rev1); if (copyOrigin != null) { - inspector.copied(pp.path(copyOrigin), pp.path(fname)); + inspector.copied(pp.path(copyOrigin) /*pipe through pool, just in case*/, copyTarget); } else { - inspector.added(pp.path(fname)); + inspector.added(copyTarget); } } } @@ -180,7 +181,7 @@ return rv; } - /*package-local*/static String getOriginIfCopy(HgRepository hgRepo, String fname, Collection originals, int originalChangelogRevision) { + /*package-local*/static Path getOriginIfCopy(HgRepository hgRepo, Path fname, Collection originals, int originalChangelogRevision) { HgDataFile df = hgRepo.getFileNode(fname); while (df.isCopy()) { Path original = df.getCopySourceName(); @@ -192,7 +193,7 @@ // (both r1Files.contains is true and original was created earlier than rev1) // without r1Files.contains changelogRevision <= rev1 won't suffice as the file // might get removed somewhere in between (changelogRevision < R < rev1) - return original.toString(); + return original; } break; // copy/rename done later } diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Thu Feb 17 04:08:34 2011 +0100 @@ -34,7 +34,7 @@ import org.tmatesoft.hg.internal.FilterByteChannel; import org.tmatesoft.hg.repo.HgStatusCollector.ManifestRevisionInspector; import org.tmatesoft.hg.util.ByteChannel; -import org.tmatesoft.hg.util.FileWalker; +import org.tmatesoft.hg.util.FileIterator; import org.tmatesoft.hg.util.Path; import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; @@ -47,7 +47,7 @@ public class HgWorkingCopyStatusCollector { private final HgRepository repo; - private final FileWalker repoWalker; + private final FileIterator repoWalker; private HgDirstate dirstate; private HgStatusCollector baseRevisionCollector; private PathPool pathPool; @@ -56,7 +56,7 @@ this(hgRepo, hgRepo.createWorkingDirWalker()); } - HgWorkingCopyStatusCollector(HgRepository hgRepo, FileWalker hgRepoWalker) { + HgWorkingCopyStatusCollector(HgRepository hgRepo, FileIterator hgRepoWalker) { this.repo = hgRepo; this.repoWalker = hgRepoWalker; } @@ -122,11 +122,11 @@ final PathPool pp = getPathPool(); while (repoWalker.hasNext()) { repoWalker.next(); - String fname = repoWalker.name(); + Path fname = repoWalker.name(); File f = repoWalker.file(); if (hgIgnore.isIgnored(fname)) { inspector.ignored(pp.path(fname)); - } else if (knownEntries.remove(fname)) { + } else if (knownEntries.remove(fname.toString())) { // modified, added, removed, clean if (collect != null) { // need to check against base revision, not FS file checkLocalStatusAgainstBaseRevision(baseRevFiles, collect, baseRevision, fname, f, inspector); @@ -167,7 +167,7 @@ //******************************************** - private void checkLocalStatusAgainstFile(String fname, File f, HgStatusInspector inspector) { + private void checkLocalStatusAgainstFile(Path fname, File f, HgStatusInspector inspector) { HgDirstate.Record r; if ((r = getDirstate().checkNormal(fname)) != null) { // either clean or modified @@ -194,17 +194,17 @@ } // XXX refactor checkLocalStatus methods in more OO way - private void checkLocalStatusAgainstBaseRevision(Set baseRevNames, ManifestRevisionInspector collect, int baseRevision, String fname, File f, HgStatusInspector inspector) { + private void checkLocalStatusAgainstBaseRevision(Set baseRevNames, ManifestRevisionInspector collect, int baseRevision, Path fname, File f, HgStatusInspector inspector) { // fname is in the dirstate, either Normal, Added, Removed or Merged - Nodeid nid1 = collect.nodeid(fname); - String flags = collect.flags(fname); + Nodeid nid1 = collect.nodeid(fname.toString()); + String flags = collect.flags(fname.toString()); HgDirstate.Record r; if (nid1 == null) { // normal: added? // added: not known at the time of baseRevision, shall report // merged: was not known, report as added? if ((r = getDirstate().checkNormal(fname)) != null) { - String origin = HgStatusCollector.getOriginIfCopy(repo, fname, baseRevNames, baseRevision); + Path origin = HgStatusCollector.getOriginIfCopy(repo, fname, baseRevNames, baseRevision); if (origin != null) { inspector.copied(getPathPool().path(origin), getPathPool().path(fname)); return; @@ -301,7 +301,7 @@ return false; } - private static String todoGenerateFlags(String fname) { + private static String todoGenerateFlags(Path fname) { // FIXME implement return null; } diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/util/FileIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/util/FileIterator.java Thu Feb 17 04:08:34 2011 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 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.util; + +import java.io.File; + +/** + * Abstracts iteration over file system. + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public interface FileIterator { + + /** + * Brings iterator into initial state to facilitate new use. + */ + void reset(); + + /** + * @return whether can shift to next element + */ + boolean hasNext(); + + /** + * Shift to next element + */ + void next(); + + /** + * @return repository-local path to the current element. + */ + Path name(); + + /** + * @return filesystem element. + */ + File file(); +} diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/util/FileWalker.java --- a/src/org/tmatesoft/hg/util/FileWalker.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/util/FileWalker.java Thu Feb 17 04:08:34 2011 +0100 @@ -25,16 +25,18 @@ * @author Artem Tikhomirov * @author TMate Software Ltd. */ -public class FileWalker { +public class FileWalker implements FileIterator { private final File startDir; + private final Path.Source pathHelper; private final LinkedList dirQueue; private final LinkedList fileQueue; private File nextFile; - private String nextPath; + private Path nextPath; - public FileWalker(File startDir) { - this.startDir = startDir; + public FileWalker(File dir, Path.Source pathFactory) { + startDir = dir; + pathHelper = pathFactory; dirQueue = new LinkedList(); fileQueue = new LinkedList(); reset(); @@ -57,10 +59,10 @@ throw new NoSuchElementException(); } nextFile = fileQueue.removeFirst(); - nextPath = path(nextFile); + nextPath = pathHelper.path(nextFile.getPath()); } - public String name() { + public Path name() { return nextPath; } @@ -68,12 +70,6 @@ return nextFile; } - private String path(File f) { - // XXX LocalHgRepo#normalize - String p = f.getPath().substring(startDir.getPath().length() + 1); - return p.replace('\\', '/').replace("//", "/"); - } - private File[] listFiles(File f) { // in case we need to solve os-related file issues (mac with some encodings?) return f.listFiles(); diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/util/Path.java --- a/src/org/tmatesoft/hg/util/Path.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/util/Path.java Thu Feb 17 04:08:34 2011 +0100 @@ -80,6 +80,31 @@ * Path filter. */ public interface Matcher { - public boolean accept(Path path); + boolean accept(Path path); + } + + /** + * Factory for paths + */ + public interface Source { + Path path(String p); + } + + /** + * Straightforward {@link Source} implementation that creates new Path instance for each supplied string + */ + public static class SimpleSource implements Source { + private final PathRewrite normalizer; + + public SimpleSource(PathRewrite pathRewrite) { + if (pathRewrite == null) { + throw new IllegalArgumentException(); + } + normalizer = pathRewrite; + } + + public Path path(String p) { + return Path.create(normalizer.rewrite(p)); + } } } diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/util/PathPool.java --- a/src/org/tmatesoft/hg/util/PathPool.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/util/PathPool.java Thu Feb 17 04:08:34 2011 +0100 @@ -21,11 +21,12 @@ /** - * + * Produces path from strings and caches result for reuse + * * @author Artem Tikhomirov * @author TMate Software Ltd. */ -public class PathPool { +public class PathPool implements Path.Source { private final WeakHashMap> cache; private final PathRewrite pathRewrite; @@ -36,13 +37,17 @@ public Path path(String p) { p = pathRewrite.rewrite(p); - SoftReference sr = cache.get(p); - Path path = sr == null ? null : sr.get(); - if (path == null) { - path = Path.create(p); - cache.put(p, new SoftReference(path)); + return get(p, true); + } + + // pipes path object through cache to reuse instance, if possible + public Path path(Path p) { + String s = pathRewrite.rewrite(p.toString()); + Path cached = get(s, false); + if (cached == null) { + cache.put(s, new SoftReference(cached = p)); } - return path; + return cached; } // XXX what would be parent of an empty path? diff -r 1c1891ad1c73 -r 8248aae33f7d src/org/tmatesoft/hg/util/PathRewrite.java --- a/src/org/tmatesoft/hg/util/PathRewrite.java Wed Feb 16 22:33:04 2011 +0100 +++ b/src/org/tmatesoft/hg/util/PathRewrite.java Thu Feb 17 04:08:34 2011 +0100 @@ -26,6 +26,7 @@ */ public interface PathRewrite { + // XXX think over CharSequence use instead of String public String rewrite(String path); public static class Empty implements PathRewrite {