Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 401:a57a21aa4190
Support WORKING_COPY constant for dataFile.length() operation
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 27 Feb 2012 19:16:01 +0100 |
parents | 0ae53c32ecef |
children | ee8264d80747 |
comparison
equal
deleted
inserted
replaced
400:deb64baaa412 | 401:a57a21aa4190 |
---|---|
111 * @return size of the file content at the revision identified by local revision number. | 111 * @return size of the file content at the revision identified by local revision number. |
112 * @throws HgInvalidRevisionException if supplied argument doesn't represent revision index in this revlog (<em>runtime exception</em>) | 112 * @throws HgInvalidRevisionException if supplied argument doesn't represent revision index in this revlog (<em>runtime exception</em>) |
113 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 113 * @throws HgInvalidControlFileException if access to revlog index/data entry failed |
114 */ | 114 */ |
115 public int length(int fileRevisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { | 115 public int length(int fileRevisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
116 // FIXME support WORKING_COPY constant | 116 if (wrongRevisionIndex(fileRevisionIndex) || fileRevisionIndex == BAD_REVISION) { |
117 throw new HgInvalidRevisionException(fileRevisionIndex); | |
118 } | |
119 if (fileRevisionIndex == TIP) { | |
120 fileRevisionIndex = getLastRevision(); | |
121 } else if (fileRevisionIndex == WORKING_COPY) { | |
122 File f = getRepo().getFile(this); | |
123 if (f.exists()) { | |
124 return (int) /*FIXME long!*/ f.length(); | |
125 } | |
126 Nodeid fileRev = getWorkingCopyRevision(); | |
127 if (fileRev == null) { | |
128 throw new HgInvalidRevisionException(String.format("File %s is not part of working copy", getPath()), null, fileRevisionIndex); | |
129 } | |
130 fileRevisionIndex = getRevisionIndex(fileRev); | |
131 } | |
117 if (metadata == null || !metadata.checked(fileRevisionIndex)) { | 132 if (metadata == null || !metadata.checked(fileRevisionIndex)) { |
118 checkAndRecordMetadata(fileRevisionIndex); | 133 checkAndRecordMetadata(fileRevisionIndex); |
119 } | 134 } |
120 final int dataLen = content.dataLength(fileRevisionIndex); | 135 final int dataLen = content.dataLength(fileRevisionIndex); |
121 if (metadata.known(fileRevisionIndex)) { | 136 if (metadata.known(fileRevisionIndex)) { |
125 } | 140 } |
126 | 141 |
127 /** | 142 /** |
128 * Reads content of the file from working directory. If file present in the working directory, its actual content without | 143 * Reads content of the file from working directory. If file present in the working directory, its actual content without |
129 * any filters is supplied through the sink. If file does not exist in the working dir, this method provides content of a file | 144 * any filters is supplied through the sink. If file does not exist in the working dir, this method provides content of a file |
130 * as if it would be refreshed in the working copy, i.e. its corresponding revision | 145 * as if it would be refreshed in the working copy, i.e. its corresponding revision (according to dirstate) is read from the |
131 * (XXX according to dirstate? file tip?) is read from the repository, and filters repo -> working copy get applied. | 146 * repository, and filters repo -> working copy get applied. |
147 * | |
148 * NOTE, if file is missing from the working directory and is not part of the dirstate (but otherwise legal repository file, | |
149 * e.g. from another branch), no content would be supplied. | |
132 * | 150 * |
133 * @param sink content consumer | 151 * @param sink content consumer |
134 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 152 * @throws HgInvalidControlFileException if access to revlog index/data entry failed |
135 * @throws HgInvalidFileException if access to file in working directory failed | 153 * @throws HgInvalidFileException if access to file in working directory failed |
136 * @throws CancelledException if execution of the operation was cancelled | 154 * @throws CancelledException if execution of the operation was cancelled |
165 getRepo().getContext().getLog().info(getClass(), ex, null); | 183 getRepo().getContext().getLog().info(getClass(), ex, null); |
166 } | 184 } |
167 } | 185 } |
168 } | 186 } |
169 } else { | 187 } else { |
170 final Pair<Nodeid, Nodeid> wcParents = getRepo().getWorkingCopyParents(); | 188 Nodeid fileRev = getWorkingCopyRevision(); |
171 Nodeid p = wcParents.first().isNull() ? wcParents.second() : wcParents.first(); | 189 if (fileRev == null) { |
172 if (p.isNull()) { | 190 // no content for this data file in the working copy - it is not part of the actual working state. |
173 // no dirstate parents - no content | 191 // XXX perhaps, shall report this to caller somehow, not silently pass no data? |
174 // XXX what if it's repository with no dirstate? Shall I use TIP then? | |
175 return; | 192 return; |
176 } | 193 } |
177 final HgChangelog clog = getRepo().getChangelog(); | 194 final int fileRevIndex = getRevisionIndex(fileRev); |
195 contentWithFilters(fileRevIndex, sink); | |
196 } | |
197 } | |
198 | |
199 /** | |
200 * @return file revision as recorded in repository manifest for dirstate parent, or <code>null</code> if no file revision can be found | |
201 */ | |
202 private Nodeid getWorkingCopyRevision() throws HgInvalidControlFileException { | |
203 final Pair<Nodeid, Nodeid> wcParents = getRepo().getWorkingCopyParents(); | |
204 Nodeid p = wcParents.first().isNull() ? wcParents.second() : wcParents.first(); | |
205 final HgChangelog clog = getRepo().getChangelog(); | |
206 final int csetRevIndex; | |
207 if (p.isNull()) { | |
208 // no dirstate parents | |
209 getRepo().getContext().getLog().info(getClass(), "No dirstate parents, resort to TIP", getPath()); | |
210 // if it's a repository with no dirstate, use TIP then | |
211 csetRevIndex = clog.getLastRevision(); | |
212 if (csetRevIndex == -1) { | |
213 // shall not happen provided there's .i for this data file (hence at least one cset) | |
214 // and perhaps exception is better here. However, null as "can't find" indication seems reasonable. | |
215 return null; | |
216 } | |
217 } else { | |
178 // common case to avoid searching complete changelog for nodeid match | 218 // common case to avoid searching complete changelog for nodeid match |
179 final Nodeid tipRev = clog.getRevision(TIP); | 219 final Nodeid tipRev = clog.getRevision(TIP); |
180 final int csetRevIndex; | |
181 if (tipRev.equals(p)) { | 220 if (tipRev.equals(p)) { |
182 csetRevIndex = clog.getLastRevision(); | 221 csetRevIndex = clog.getLastRevision(); |
183 } else { | 222 } else { |
184 // bad luck, need to search honestly | 223 // bad luck, need to search honestly |
185 csetRevIndex = getRepo().getChangelog().getRevisionIndex(p); | 224 csetRevIndex = getRepo().getChangelog().getRevisionIndex(p); |
186 } | 225 } |
187 Nodeid fileRev = getRepo().getManifest().getFileRevision(csetRevIndex, getPath()); | 226 } |
188 final int fileRevIndex = getRevisionIndex(fileRev); | 227 Nodeid fileRev = getRepo().getManifest().getFileRevision(csetRevIndex, getPath()); |
189 contentWithFilters(fileRevIndex, sink); | 228 // it's possible for a file to be in working dir and have store/.i but to belong e.g. to a different |
190 } | 229 // branch than the one from dirstate. Thus it's possible to get null fileRev |
230 // which would serve as an indication this data file is not part of working copy | |
231 return fileRev; | |
191 } | 232 } |
192 | 233 |
193 /** | 234 /** |
194 * Access content of a file revision | 235 * Access content of a file revision |
195 * XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves? | 236 * XXX not sure distinct method contentWithFilters() is the best way to do, perhaps, callers shall add filters themselves? |
503 return sb.toString(); | 544 return sb.toString(); |
504 } | 545 } |
505 | 546 |
506 private void checkAndRecordMetadata(int localRev) throws HgInvalidControlFileException { | 547 private void checkAndRecordMetadata(int localRev) throws HgInvalidControlFileException { |
507 // content() always initializes metadata. | 548 // content() always initializes metadata. |
508 // FIXME this is expensive way to find out metadata, distinct RevlogStream.Iterator would be better. | 549 // TODO [post-1.0] this is expensive way to find out metadata, distinct RevlogStream.Iterator would be better. |
509 // Alternatively, may parameterize MetadataContentPipe to do prepare only. | 550 // Alternatively, may parameterize MetadataContentPipe to do prepare only. |
510 // For reference, when throwing CancelledException, hg status -A --rev 3:80 takes 70 ms | 551 // For reference, when throwing CancelledException, hg status -A --rev 3:80 takes 70 ms |
511 // however, if we just consume buffer instead (buffer.position(buffer.limit()), same command takes ~320ms | 552 // however, if we just consume buffer instead (buffer.position(buffer.limit()), same command takes ~320ms |
512 // (compared to command-line counterpart of 190ms) | 553 // (compared to command-line counterpart of 190ms) |
513 try { | 554 try { |