comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 237:6e1373b54e9b

Allow access to working copy content through HgDataFile. Give access to repository's working dir
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 10 Jun 2011 04:35:21 +0200
parents 1d389c0cb0a5
children 29231022fec8
comparison
equal deleted inserted replaced
236:883300108179 237:6e1373b54e9b
18 18
19 import static org.tmatesoft.hg.repo.HgInternals.wrongLocalRevision; 19 import static org.tmatesoft.hg.repo.HgInternals.wrongLocalRevision;
20 import static org.tmatesoft.hg.repo.HgRepository.*; 20 import static org.tmatesoft.hg.repo.HgRepository.*;
21 21
22 import java.io.ByteArrayOutputStream; 22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
23 import java.io.IOException; 25 import java.io.IOException;
24 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
27 import java.nio.channels.FileChannel;
25 import java.util.ArrayList; 28 import java.util.ArrayList;
26 import java.util.Collection; 29 import java.util.Collection;
27 import java.util.TreeMap; 30 import java.util.TreeMap;
28 31
29 import org.tmatesoft.hg.core.HgDataStreamException; 32 import org.tmatesoft.hg.core.HgDataStreamException;
31 import org.tmatesoft.hg.core.Nodeid; 34 import org.tmatesoft.hg.core.Nodeid;
32 import org.tmatesoft.hg.internal.DataAccess; 35 import org.tmatesoft.hg.internal.DataAccess;
33 import org.tmatesoft.hg.internal.FilterByteChannel; 36 import org.tmatesoft.hg.internal.FilterByteChannel;
34 import org.tmatesoft.hg.internal.RevlogStream; 37 import org.tmatesoft.hg.internal.RevlogStream;
35 import org.tmatesoft.hg.util.ByteChannel; 38 import org.tmatesoft.hg.util.ByteChannel;
39 import org.tmatesoft.hg.util.CancelSupport;
36 import org.tmatesoft.hg.util.CancelledException; 40 import org.tmatesoft.hg.util.CancelledException;
37 import org.tmatesoft.hg.util.Path; 41 import org.tmatesoft.hg.util.Path;
42 import org.tmatesoft.hg.util.ProgressSupport;
38 43
39 44
40 45
41 /** 46 /**
42 * ? name:HgFileNode? 47 * ? name:HgFileNode?
75 80
76 public int length(Nodeid nodeid) { 81 public int length(Nodeid nodeid) {
77 return content.dataLength(getLocalRevision(nodeid)); 82 return content.dataLength(getLocalRevision(nodeid));
78 } 83 }
79 84
80 public void workingCopy(ByteChannel sink) throws IOException, CancelledException { 85 /**
81 throw HgRepository.notImplemented(); 86 * Reads content of the file from working directory. If file present in the working directory, its actual content without
87 * any filters is supplied through the sink. If file does not exist in the working dir, this method provides content of a file
88 * as if it would be refreshed in the working copy, i.e. its corresponding revision
89 * (XXX according to dirstate? file tip?) is read from the repository, and filters repo -> working copy get applied.
90 *
91 * @param sink where to pipe content to
92 * @throws HgDataStreamException to indicate troubles reading repository file
93 * @throws CancelledException if operation was cancelled
94 */
95 public void workingCopy(ByteChannel sink) throws HgDataStreamException, CancelledException {
96 File f = getRepo().getFile(this);
97 if (f.exists()) {
98 final CancelSupport cs = CancelSupport.Factory.get(sink);
99 final ProgressSupport progress = ProgressSupport.Factory.get(sink);
100 final long flength = f.length();
101 final int bsize = (int) Math.min(flength, 32*1024);
102 progress.start((int) (flength > Integer.MAX_VALUE ? flength >>> 15 /*32 kb buf size*/ : flength));
103 ByteBuffer buf = ByteBuffer.allocate(bsize);
104 FileChannel fc = null;
105 try {
106 fc = new FileInputStream(f).getChannel();
107 while (fc.read(buf) != -1) {
108 cs.checkCancelled();
109 buf.flip();
110 int consumed = sink.write(buf);
111 progress.worked(flength > Integer.MAX_VALUE ? 1 : consumed);
112 buf.compact();
113 }
114 } catch (IOException ex) {
115 throw new HgDataStreamException(getPath(), ex);
116 } finally {
117 progress.done();
118 if (fc != null) {
119 try {
120 fc.close();
121 } catch (IOException ex) {
122 ex.printStackTrace();
123 }
124 }
125 }
126 } else {
127 contentWithFilters(TIP, sink);
128 }
82 } 129 }
83 130
84 // public void content(int revision, ByteChannel sink, boolean applyFilters) throws HgDataStreamException, IOException, CancelledException { 131 // public void content(int revision, ByteChannel sink, boolean applyFilters) throws HgDataStreamException, IOException, CancelledException {
85 // byte[] content = content(revision); 132 // byte[] content = content(revision);
86 // final CancelSupport cancelSupport = CancelSupport.Factory.get(sink); 133 // final CancelSupport cancelSupport = CancelSupport.Factory.get(sink);
104 // } while (left > 0); 151 // } while (left > 0);
105 // progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully. 152 // progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully.
106 // } 153 // }
107 154
108 /*XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves?*/ 155 /*XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves?*/
109 public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { 156 public void contentWithFilters(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException {
110 content(revision, new FilterByteChannel(sink, getRepo().getFiltersFromRepoToWorkingDir(getPath()))); 157 if (revision == WORKING_COPY) {
158 workingCopy(sink); // pass un-mangled sink
159 } else {
160 content(revision, new FilterByteChannel(sink, getRepo().getFiltersFromRepoToWorkingDir(getPath())));
161 }
111 } 162 }
112 163
113 // for data files need to check heading of the file content for possible metadata 164 // for data files need to check heading of the file content for possible metadata
114 // @see http://mercurial.selenic.com/wiki/FileFormats#data.2BAC8- 165 // @see http://mercurial.selenic.com/wiki/FileFormats#data.2BAC8-
115 public void content(int revision, ByteChannel sink) throws HgDataStreamException, IOException, CancelledException { 166 public void content(int revision, ByteChannel sink) throws HgDataStreamException, CancelledException {
116 if (revision == TIP) { 167 if (revision == TIP) {
117 revision = getLastRevision(); 168 revision = getLastRevision();
118 } 169 }
119 if (revision == WORKING_COPY) { 170 if (revision == WORKING_COPY) {
171 // sink is supposed to come into workingCopy without filters
172 // thus we shall not get here (into #content) from #contentWithFilters(WC)
120 workingCopy(sink); 173 workingCopy(sink);
121 return; 174 return;
122 } 175 }
123 if (wrongLocalRevision(revision) || revision == BAD_REVISION) { 176 if (wrongLocalRevision(revision) || revision == BAD_REVISION) {
124 throw new IllegalArgumentException(String.valueOf(revision)); 177 throw new IllegalArgumentException(String.valueOf(revision));
139 insp = new MetadataContentPipe(sink, metadata, getPath()); 192 insp = new MetadataContentPipe(sink, metadata, getPath());
140 } 193 }
141 insp.checkCancelled(); 194 insp.checkCancelled();
142 super.content.iterate(revision, revision, true, insp); 195 super.content.iterate(revision, revision, true, insp);
143 try { 196 try {
144 insp.checkFailed(); 197 insp.checkFailed(); // XXX is there real need to throw IOException from ContentPipe?
145 } catch (HgDataStreamException ex) { 198 } catch (HgDataStreamException ex) {
146 throw ex; 199 throw ex;
200 } catch (IOException ex) {
201 throw new HgDataStreamException(getPath(), ex);
147 } catch (HgException ex) { 202 } catch (HgException ex) {
148 // shall not happen, unless we changed ContentPipe or its subclass 203 // shall not happen, unless we changed ContentPipe or its subclass
149 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); 204 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex);
150 } 205 }
151 } 206 }