Mercurial > jhg
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 { |
