# HG changeset patch # User Artem Tikhomirov # Date 1307673321 -7200 # Node ID 6e1373b54e9b28f119de9bc3524802b1c7d4a083 # Parent 8833001081793a36320cd6d67073552e53fdb805 Allow access to working copy content through HgDataFile. Give access to repository's working dir diff -r 883300108179 -r 6e1373b54e9b cmdline/org/tmatesoft/hg/console/Main.java --- a/cmdline/org/tmatesoft/hg/console/Main.java Thu Jun 09 06:13:43 2011 +0200 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Fri Jun 10 04:35:21 2011 +0200 @@ -70,12 +70,13 @@ public static void main(String[] args) throws Exception { Main m = new Main(args); + m.testReadWorkingCopy(); // m.testParents(); // m.testEffectiveFileLog(); // m.testCatAtCsetRevision(); // m.testMergeState(); // m.testFileStatus(); - m.dumpBranches(); +// m.dumpBranches(); // m.inflaterLengthException(); // m.dumpIgnored(); // m.dumpDirstate(); @@ -86,6 +87,15 @@ // m.bunchOfTests(); } + private void testReadWorkingCopy() throws Exception { + for (String fname : cmdLineOpts.getList("")) { + HgDataFile fn = hgRepo.getFileNode(fname); + ByteArrayChannel sink = new ByteArrayChannel(); + fn.workingCopy(sink); + System.out.printf("%s: read %d bytes of working copy", fname, sink.toArray().length); + } + } + private void testParents() throws Exception { // hg parents cmd final Pair wcParents = hgRepo.getWorkingCopyParents(); diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/core/HgCatCommand.java --- a/src/org/tmatesoft/hg/core/HgCatCommand.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgCatCommand.java Fri Jun 10 04:35:21 2011 +0200 @@ -21,7 +21,6 @@ import static org.tmatesoft.hg.repo.HgRepository.TIP; import java.io.FileNotFoundException; -import java.io.IOException; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgRepository; @@ -123,7 +122,7 @@ * @throws HgDataStreamException * @throws IllegalArgumentException when command arguments are incomplete or wrong */ - public void execute(ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { + public void execute(ByteChannel sink) throws HgDataStreamException, CancelledException { if (localRevision == BAD_REVISION && revision == null && cset == null) { throw new IllegalArgumentException("File revision, corresponing local number, or a changset nodeid shall be specified"); } diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/core/HgFileRevision.java --- a/src/org/tmatesoft/hg/core/HgFileRevision.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgFileRevision.java Fri Jun 10 04:35:21 2011 +0200 @@ -16,8 +16,6 @@ */ package org.tmatesoft.hg.core; -import java.io.IOException; - import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.ByteChannel; @@ -51,7 +49,7 @@ public Nodeid getRevision() { return revision; } - public void putContentTo(ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { + public void putContentTo(ByteChannel sink) throws HgDataStreamException, CancelledException { HgDataFile fn = repo.getFileNode(path); int localRevision = fn.getLocalRevision(revision); fn.contentWithFilters(localRevision, sink); diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/core/HgLogCommand.java --- a/src/org/tmatesoft/hg/core/HgLogCommand.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Fri Jun 10 04:35:21 2011 +0200 @@ -322,6 +322,6 @@ public interface FileRevision { public abstract Path getPath(); public abstract Nodeid getRevision(); - public abstract void putContentTo(ByteChannel sink) throws HgDataStreamException, IOException, CancelledException; + public abstract void putContentTo(ByteChannel sink) throws HgDataStreamException, CancelledException; } } diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/internal/NewlineFilter.java --- a/src/org/tmatesoft/hg/internal/NewlineFilter.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/NewlineFilter.java Fri Jun 10 04:35:21 2011 +0200 @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Map; -import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.Path; @@ -167,7 +166,7 @@ public void initialize(HgRepository hgRepo, ConfigFile cfg) { failIfInconsistent = cfg.getBoolean("eol", "only-consistent", true); - File cfgFile = new File(new HgInternals(hgRepo).getRepositoryDir().getParentFile(), ".hgeol"); + File cfgFile = new File(hgRepo.getWorkingDir(), ".hgeol"); if (!cfgFile.canRead()) { return; } diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/repo/HgDataFile.java --- a/src/org/tmatesoft/hg/repo/HgDataFile.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Fri Jun 10 04:35:21 2011 +0200 @@ -20,8 +20,11 @@ import static org.tmatesoft.hg.repo.HgRepository.*; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Collection; import java.util.TreeMap; @@ -33,8 +36,10 @@ import org.tmatesoft.hg.internal.FilterByteChannel; import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.util.ByteChannel; +import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; import org.tmatesoft.hg.util.Path; +import org.tmatesoft.hg.util.ProgressSupport; @@ -77,8 +82,50 @@ return content.dataLength(getLocalRevision(nodeid)); } - public void workingCopy(ByteChannel sink) throws IOException, CancelledException { - throw HgRepository.notImplemented(); + /** + * Reads content of the file from working directory. If file present in the working directory, its actual content without + * any filters is supplied through the sink. If file does not exist in the working dir, this method provides content of a file + * as if it would be refreshed in the working copy, i.e. its corresponding revision + * (XXX according to dirstate? file tip?) is read from the repository, and filters repo -> working copy get applied. + * + * @param sink where to pipe content to + * @throws HgDataStreamException to indicate troubles reading repository file + * @throws CancelledException if operation was cancelled + */ + public void workingCopy(ByteChannel sink) throws HgDataStreamException, CancelledException { + File f = getRepo().getFile(this); + if (f.exists()) { + final CancelSupport cs = CancelSupport.Factory.get(sink); + final ProgressSupport progress = ProgressSupport.Factory.get(sink); + final long flength = f.length(); + final int bsize = (int) Math.min(flength, 32*1024); + progress.start((int) (flength > Integer.MAX_VALUE ? flength >>> 15 /*32 kb buf size*/ : flength)); + ByteBuffer buf = ByteBuffer.allocate(bsize); + FileChannel fc = null; + try { + fc = new FileInputStream(f).getChannel(); + while (fc.read(buf) != -1) { + cs.checkCancelled(); + buf.flip(); + int consumed = sink.write(buf); + progress.worked(flength > Integer.MAX_VALUE ? 1 : consumed); + buf.compact(); + } + } catch (IOException ex) { + throw new HgDataStreamException(getPath(), ex); + } finally { + progress.done(); + if (fc != null) { + try { + fc.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + } else { + contentWithFilters(TIP, sink); + } } // public void content(int revision, ByteChannel sink, boolean applyFilters) throws HgDataStreamException, IOException, CancelledException { @@ -106,17 +153,23 @@ // } /*XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves?*/ - public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { - content(revision, new FilterByteChannel(sink, getRepo().getFiltersFromRepoToWorkingDir(getPath()))); + public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException { + if (revision == WORKING_COPY) { + workingCopy(sink); // pass un-mangled sink + } else { + content(revision, new FilterByteChannel(sink, getRepo().getFiltersFromRepoToWorkingDir(getPath()))); + } } // for data files need to check heading of the file content for possible metadata // @see http://mercurial.selenic.com/wiki/FileFormats#data.2BAC8- - public void content(int revision, ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { + public void content(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException { if (revision == TIP) { revision = getLastRevision(); } if (revision == WORKING_COPY) { + // sink is supposed to come into workingCopy without filters + // thus we shall not get here (into #content) from #contentWithFilters(WC) workingCopy(sink); return; } @@ -141,9 +194,11 @@ insp.checkCancelled(); super.content.iterate(revision, revision, true, insp); try { - insp.checkFailed(); + insp.checkFailed(); // XXX is there real need to throw IOException from ContentPipe? } catch (HgDataStreamException ex) { throw ex; + } catch (IOException ex) { + throw new HgDataStreamException(getPath(), ex); } catch (HgException ex) { // shall not happen, unless we changed ContentPipe or its subclass throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/repo/HgInternals.java --- a/src/org/tmatesoft/hg/repo/HgInternals.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgInternals.java Fri Jun 10 04:35:21 2011 +0200 @@ -95,7 +95,7 @@ @Experimental(reason="Don't want to expose io.File from HgRepository; need to create FileIterator for working dir. Need a place to keep that code") /*package-local*/ FileIterator createWorkingDirWalker(Path.Matcher workindDirScope) { - File repoRoot = repo.getRepositoryRoot().getParentFile(); + File repoRoot = repo.getWorkingDir(); Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), repo.getToRepoPathHelper())); // 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), diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Fri Jun 10 04:35:21 2011 +0200 @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.StringReader; import java.lang.ref.SoftReference; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -64,6 +63,7 @@ } private final File repoDir; // .hg folder + private final File workingDir; // .hg/../ private final String repoLocation; private final DataAccessProvider dataAccess; private final PathRewrite normalizePath; @@ -85,6 +85,7 @@ HgRepository(String repositoryPath) { repoDir = null; + workingDir = null; repoLocation = repositoryPath; dataAccess = null; dataPathHelper = repoPathHelper = null; @@ -96,6 +97,10 @@ assert repositoryPath != null; assert repositoryRoot != null; repoDir = repositoryRoot; + workingDir = repoDir.getParentFile(); + if (workingDir == null) { + throw new IllegalArgumentException(repoDir.toString()); + } repoLocation = repositoryPath; dataAccess = new DataAccessProvider(); final boolean runningOnWindows = System.getProperty("os.name").indexOf("Windows") != -1; @@ -230,7 +235,14 @@ return new Pair(NULL == p[0] ? null : p[0], NULL == p[1] ? null : p[1]); } - // local to hide use of io.File. + /** + * @return location where user files (shall) reside + */ + public File getWorkingDir() { + return workingDir; + } + + // shall be of use only for internal classes /*package-local*/ File getRepositoryRoot() { return repoDir; } @@ -307,6 +319,10 @@ /*package-local*/ List getFiltersFromWorkingDirToRepo(Path p) { return instantiateFilters(p, new Filter.Options(Filter.Direction.ToRepo)); } + + /*package-local*/ File getFile(HgDataFile dataFile) { + return new File(getWorkingDir(), dataFile.getPath().toString()); + } private List instantiateFilters(Path p, Filter.Options opts) { List factories = impl.getFilters(this, getConfigFile()); diff -r 883300108179 -r 6e1373b54e9b src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Thu Jun 09 06:13:43 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Fri Jun 10 04:35:21 2011 +0200 @@ -422,7 +422,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.getRepositoryRoot().getParentFile(), files); + FileIterator fi = new FileListIterator(hgRepo.getWorkingDir(), files); return new HgWorkingCopyStatusCollector(hgRepo, fi); } //