Mercurial > hg4j
comparison src/org/tmatesoft/hg/core/HgFileInformer.java @ 361:8099939af5fa
Utilize status object to supply more information about manifest check for specific file
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 09 Dec 2011 01:13:53 +0100 |
parents | 5f9073eabf06 |
children | 2fadf8695f8a |
comparison
equal
deleted
inserted
replaced
360:150500515714 | 361:8099939af5fa |
---|---|
19 import org.tmatesoft.hg.internal.ManifestRevision; | 19 import org.tmatesoft.hg.internal.ManifestRevision; |
20 import org.tmatesoft.hg.repo.HgDataFile; | 20 import org.tmatesoft.hg.repo.HgDataFile; |
21 import org.tmatesoft.hg.repo.HgInternals; | 21 import org.tmatesoft.hg.repo.HgInternals; |
22 import org.tmatesoft.hg.repo.HgRepository; | 22 import org.tmatesoft.hg.repo.HgRepository; |
23 import org.tmatesoft.hg.util.Path; | 23 import org.tmatesoft.hg.util.Path; |
24 import org.tmatesoft.hg.util.Status; | |
24 | 25 |
25 /** | 26 /** |
26 * Primary purpose is to provide information about file revisions at specific changeset. Multiple {@link #check(Path)} calls | 27 * Primary purpose is to provide information about file revisions at specific changeset. Multiple {@link #check(Path)} calls |
27 * are possible once {@link #changeset(Nodeid)} (and optionally, {@link #followRenames(boolean)}) were set. | 28 * are possible once {@link #changeset(Nodeid)} (and optionally, {@link #followRenames(boolean)}) were set. |
28 * | 29 * |
35 * ... | 36 * ... |
36 * } | 37 * } |
37 * </pre></code> | 38 * </pre></code> |
38 * | 39 * |
39 * FIXME need better name. It's more about manifest of specific changeset, rather than informing (about) files | 40 * FIXME need better name. It's more about manifest of specific changeset, rather than informing (about) files |
41 * TODO may add #manifest(Nodeid) to select manifest according to its revision (not only changeset revision as it's now) | |
40 * | 42 * |
41 * @author Artem Tikhomirov | 43 * @author Artem Tikhomirov |
42 * @author TMate Software Ltd. | 44 * @author TMate Software Ltd. |
43 */ | 45 */ |
44 public class HgFileInformer { | 46 public class HgFileInformer { |
46 private final HgRepository repo; | 48 private final HgRepository repo; |
47 private boolean followRenames; | 49 private boolean followRenames; |
48 private Nodeid cset; | 50 private Nodeid cset; |
49 private ManifestRevision cachedManifest; | 51 private ManifestRevision cachedManifest; |
50 private HgFileRevision fileRevision; | 52 private HgFileRevision fileRevision; |
51 private boolean checked, renamed; | 53 private boolean renamed; |
54 private Status checkResult; | |
52 | 55 |
53 public HgFileInformer(HgRepository hgRepo) { | 56 public HgFileInformer(HgRepository hgRepo) { |
54 repo = hgRepo; | 57 repo = hgRepo; |
55 } | 58 } |
56 | 59 |
81 fileRevision = null; | 84 fileRevision = null; |
82 return this; | 85 return this; |
83 } | 86 } |
84 | 87 |
85 /** | 88 /** |
86 * Find file (or its origin, if {@link #followRenames(boolean)} was set to <code>true</code>) among files known at specified {@link #changeset(Nodeid)}. | 89 * Shortcut to perform {@link #check(Path)} and {@link #exists()}. Result of the check may be accessed via {@link #getCheckStatus()}. |
87 * | 90 * |
88 * @param file name of the file in question | 91 * @param file name of the file in question |
89 * @return <code>true</code> if file is known at the selected changeset. | 92 * @return <code>true</code> if file is known at the selected changeset. |
90 * @throws IllegalArgumentException if {@link #changeset(Nodeid)} not specified or file argument is bad. | 93 * @throws IllegalArgumentException if {@link #changeset(Nodeid)} not specified or file argument is bad. |
91 */ | 94 * @throws HgInvalidControlFileException if access to revlog index/data entry failed |
92 public boolean check(Path file) throws HgInvalidControlFileException { // XXX IStatus instead of boolean? If status, shall it handle exceptions as well? | 95 */ |
96 public boolean checkExists(Path file) throws HgInvalidControlFileException { | |
97 check(file); | |
98 if (!checkResult.isOk() && checkResult.getException() instanceof HgInvalidControlFileException) { | |
99 throw (HgInvalidControlFileException) checkResult.getException(); | |
100 } | |
101 return checkResult.isOk() && exists(); | |
102 } | |
103 | |
104 /** | |
105 * Find file (or its origin, if {@link #followRenames(boolean)} was set to <code>true</code>) among files known at specified {@link #changeset(Nodeid)}. | |
106 * | |
107 * @param file name of the file in question | |
108 * @return status object that describes outcome, {@link Status#isOk() Ok} status indicates successful completion of the operation, but doesn't imply | |
109 * file existence, use {@link #exists()} for that purpose. Message of the status may provide further hints on what exactly had happened. | |
110 * @throws IllegalArgumentException if {@link #changeset(Nodeid)} not specified or file argument is bad. | |
111 */ | |
112 public Status check(Path file) { | |
93 fileRevision = null; | 113 fileRevision = null; |
94 checked = false; | 114 checkResult = null; |
95 renamed = false; | 115 renamed = false; |
96 if (cset == null || file == null || file.isDirectory()) { | 116 if (cset == null || file == null || file.isDirectory()) { |
97 throw new IllegalArgumentException(); | 117 throw new IllegalArgumentException(); |
98 } | 118 } |
99 HgDataFile dataFile = repo.getFileNode(file); | 119 HgDataFile dataFile = repo.getFileNode(file); |
100 if (!dataFile.exists()) { | 120 if (!dataFile.exists()) { |
101 return false; | 121 checkResult = new Status(Status.Kind.OK, String.format("File named %s is not known in the repository", file)); |
102 } | 122 return checkResult; |
103 if (cachedManifest == null) { | 123 } |
104 int csetRev = repo.getChangelog().getLocalRevision(cset); | 124 Nodeid toExtract = null; |
105 cachedManifest = new ManifestRevision(null, null); // XXX how about context and cached manifest revisions | |
106 repo.getManifest().walk(csetRev, csetRev, cachedManifest); | |
107 // cachedManifest shall be meaningful - changelog.getLocalRevision above ensures we've got version that exists. | |
108 } | |
109 Nodeid toExtract = cachedManifest.nodeid(file); | |
110 try { | 125 try { |
126 if (cachedManifest == null) { | |
127 int csetRev = repo.getChangelog().getLocalRevision(cset); | |
128 cachedManifest = new ManifestRevision(null, null); // XXX how about context and cached manifest revisions | |
129 repo.getManifest().walk(csetRev, csetRev, cachedManifest); | |
130 // cachedManifest shall be meaningful - changelog.getLocalRevision above ensures we've got version that exists. | |
131 } | |
132 toExtract = cachedManifest.nodeid(file); | |
111 if (toExtract == null && followRenames) { | 133 if (toExtract == null && followRenames) { |
112 while (toExtract == null && dataFile.isCopy()) { | 134 while (toExtract == null && dataFile.isCopy()) { |
113 renamed = true; | 135 renamed = true; |
114 file = dataFile.getCopySourceName(); | 136 file = dataFile.getCopySourceName(); |
115 dataFile = repo.getFileNode(file); | 137 dataFile = repo.getFileNode(file); |
116 toExtract = cachedManifest.nodeid(file); | 138 toExtract = cachedManifest.nodeid(file); |
117 } | 139 } |
118 } | 140 } |
141 } catch (HgInvalidControlFileException ex) { | |
142 checkResult = new Status(Status.Kind.ERROR, "", ex); | |
143 return checkResult; | |
119 } catch (HgDataStreamException ex) { | 144 } catch (HgDataStreamException ex) { |
120 HgInternals.getContext(repo).getLog().warn(getClass(), ex, "Follow copy/rename failed"); | 145 checkResult = new Status(Status.Kind.ERROR, "Follow copy/rename failed", ex); |
121 // ignore now, however if there's IStatus retval, might report error with reasonable explanation. | 146 HgInternals.getContext(repo).getLog().warn(getClass(), ex, checkResult.getMessage()); |
122 // Perhaps, may add a String reason() method with such info? | 147 return checkResult; |
123 } | 148 } |
124 checked = true; | |
125 if (toExtract != null) { | 149 if (toExtract != null) { |
126 fileRevision = new HgFileRevision(repo, toExtract, dataFile.getPath()); | 150 fileRevision = new HgFileRevision(repo, toExtract, dataFile.getPath()); |
127 return true; | 151 checkResult = new Status(Status.Kind.OK, String.format("File %s, revision %s found at changeset %s", dataFile.getPath(), toExtract.shortNotation(), cset.shortNotation())); |
128 } // else String.format("File %s nor its origins were not known at repository %s revision", file, cset.shortNotation()) | 152 return checkResult; |
129 return false; | 153 } |
154 checkResult = new Status(Status.Kind.OK, String.format("File %s nor its origins were not known at repository %s revision", file, cset.shortNotation())); | |
155 return checkResult; | |
156 } | |
157 | |
158 /** | |
159 * Re-get latest check status object | |
160 */ | |
161 public Status getCheckStatus() { | |
162 assertCheckRan(); | |
163 return checkResult; | |
130 } | 164 } |
131 | 165 |
132 /** | 166 /** |
133 * @return result of the last {@link #check(Path)} call. | 167 * @return result of the last {@link #check(Path)} call. |
134 */ | 168 */ |
172 assertCheckRan(); | 206 assertCheckRan(); |
173 return fileRevision.getRevision(); | 207 return fileRevision.getRevision(); |
174 } | 208 } |
175 | 209 |
176 private void assertCheckRan() { | 210 private void assertCheckRan() { |
177 if (!checked) { | 211 if (checkResult == null) { |
178 throw new HgBadStateException("Shall invoke #check(Path) first"); | 212 throw new HgBadStateException("Shall invoke #check(Path) first"); |
179 } | 213 } |
180 } | 214 } |
181 } | 215 } |