Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgDirstate.java @ 348:a0864b2892cd
Expose errors reading mercurial control files with exception
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 24 Nov 2011 02:57:03 +0100 |
parents | 72c6eda838a6 |
children | aa2e589d4e84 |
comparison
equal
deleted
inserted
replaced
347:8da7ade36c57 | 348:a0864b2892cd |
---|---|
18 | 18 |
19 import static org.tmatesoft.hg.core.Nodeid.NULL; | 19 import static org.tmatesoft.hg.core.Nodeid.NULL; |
20 | 20 |
21 import java.io.BufferedReader; | 21 import java.io.BufferedReader; |
22 import java.io.File; | 22 import java.io.File; |
23 import java.io.FileNotFoundException; | |
23 import java.io.FileReader; | 24 import java.io.FileReader; |
24 import java.io.IOException; | 25 import java.io.IOException; |
25 import java.util.Collections; | 26 import java.util.Collections; |
26 import java.util.HashMap; | 27 import java.util.HashMap; |
27 import java.util.LinkedHashMap; | 28 import java.util.LinkedHashMap; |
28 import java.util.Map; | 29 import java.util.Map; |
29 import java.util.TreeSet; | 30 import java.util.TreeSet; |
30 | 31 |
31 import org.tmatesoft.hg.core.HgBadStateException; | 32 import org.tmatesoft.hg.core.HgInvalidControlFileException; |
32 import org.tmatesoft.hg.core.Nodeid; | 33 import org.tmatesoft.hg.core.Nodeid; |
33 import org.tmatesoft.hg.internal.DataAccess; | 34 import org.tmatesoft.hg.internal.DataAccess; |
34 import org.tmatesoft.hg.util.Pair; | 35 import org.tmatesoft.hg.util.Pair; |
35 import org.tmatesoft.hg.util.Path; | 36 import org.tmatesoft.hg.util.Path; |
36 import org.tmatesoft.hg.util.PathPool; | 37 import org.tmatesoft.hg.util.PathPool; |
71 dirstateFile = dirstate; // XXX decide whether file names shall be kept local to reader (see #branches()) or passed from outside | 72 dirstateFile = dirstate; // XXX decide whether file names shall be kept local to reader (see #branches()) or passed from outside |
72 this.pathPool = pathPool; | 73 this.pathPool = pathPool; |
73 canonicalPathRewrite = canonicalPath; | 74 canonicalPathRewrite = canonicalPath; |
74 } | 75 } |
75 | 76 |
76 private void read() { | 77 /*package-local*/ void read() throws HgInvalidControlFileException { |
77 normal = added = removed = merged = Collections.<Path, Record>emptyMap(); | 78 normal = added = removed = merged = Collections.<Path, Record>emptyMap(); |
78 if (canonicalPathRewrite != null) { | 79 if (canonicalPathRewrite != null) { |
79 canonical2dirstateName = new HashMap<Path,Path>(); | 80 canonical2dirstateName = new HashMap<Path,Path>(); |
80 } else { | 81 } else { |
81 canonical2dirstateName = Collections.emptyMap(); | 82 canonical2dirstateName = Collections.emptyMap(); |
142 } else { | 143 } else { |
143 // FIXME log error? | 144 // FIXME log error? |
144 } | 145 } |
145 } | 146 } |
146 } catch (IOException ex) { | 147 } catch (IOException ex) { |
147 repo.getContext().getLog().error(getClass(), ex, null); | 148 throw new HgInvalidControlFileException("Dirstate read failed", ex, dirstateFile); |
148 // FIXME clean dirstate? | |
149 } finally { | 149 } finally { |
150 da.done(); | 150 da.done(); |
151 } | 151 } |
152 } | 152 } |
153 | 153 |
162 | 162 |
163 /** | 163 /** |
164 * @return pair of working copy parents, with {@link Nodeid#NULL} for missing values. | 164 * @return pair of working copy parents, with {@link Nodeid#NULL} for missing values. |
165 */ | 165 */ |
166 public Pair<Nodeid,Nodeid> parents() { | 166 public Pair<Nodeid,Nodeid> parents() { |
167 if (parents == null) { | 167 assert parents != null; // instance not initialized with #read() |
168 parents = readParents(repo, dirstateFile); | |
169 } | |
170 return parents; | 168 return parents; |
171 } | 169 } |
172 | 170 |
173 /** | 171 /** |
174 * @return pair of parents, both {@link Nodeid#NULL} if dirstate is not available | 172 * @return pair of parents, both {@link Nodeid#NULL} if dirstate is not available |
175 */ | 173 */ |
176 /*package-local*/ static Pair<Nodeid, Nodeid> readParents(HgRepository repo, File dirstateFile) { | 174 /*package-local*/ static Pair<Nodeid, Nodeid> readParents(HgRepository repo, File dirstateFile) throws HgInvalidControlFileException { |
177 // do not read whole dirstate if all we need is WC parent information | 175 // do not read whole dirstate if all we need is WC parent information |
178 if (dirstateFile == null || !dirstateFile.exists()) { | 176 if (dirstateFile == null || !dirstateFile.exists()) { |
179 return new Pair<Nodeid,Nodeid>(NULL, NULL); | 177 return new Pair<Nodeid,Nodeid>(NULL, NULL); |
180 } | 178 } |
181 DataAccess da = repo.getDataAccess().create(dirstateFile); | 179 DataAccess da = repo.getDataAccess().create(dirstateFile); |
183 return new Pair<Nodeid,Nodeid>(NULL, NULL); | 181 return new Pair<Nodeid,Nodeid>(NULL, NULL); |
184 } | 182 } |
185 try { | 183 try { |
186 return internalReadParents(da); | 184 return internalReadParents(da); |
187 } catch (IOException ex) { | 185 } catch (IOException ex) { |
188 throw new HgBadStateException(ex); // XXX in fact, our exception is not the best solution here. | 186 throw new HgInvalidControlFileException("Error reading working copy parents from dirstate", ex, dirstateFile); |
189 } finally { | 187 } finally { |
190 da.done(); | 188 da.done(); |
191 } | 189 } |
192 } | 190 } |
193 | 191 |
194 /** | 192 /** |
193 * FIXME move to a better place, e.g. WorkingCopy container that tracks both dirstate and branches (and, perhaps, undo, lastcommit and other similar information) | |
195 * @return branch associated with the working directory | 194 * @return branch associated with the working directory |
196 */ | 195 */ |
197 public String branch() { | 196 public String branch() throws HgInvalidControlFileException { |
198 // XXX is it really proper place for the method? | 197 // XXX is it really proper place for the method? |
199 if (currentBranch == null) { | 198 if (currentBranch == null) { |
200 currentBranch = readBranch(repo); | 199 currentBranch = readBranch(repo); |
201 } | 200 } |
202 return currentBranch; | 201 return currentBranch; |
204 | 203 |
205 /** | 204 /** |
206 * XXX is it really proper place for the method? | 205 * XXX is it really proper place for the method? |
207 * @return branch associated with the working directory | 206 * @return branch associated with the working directory |
208 */ | 207 */ |
209 /*package-local*/ static String readBranch(HgRepository repo) { | 208 /*package-local*/ static String readBranch(HgRepository repo) throws HgInvalidControlFileException { |
210 String branch = HgRepository.DEFAULT_BRANCH_NAME; | 209 String branch = HgRepository.DEFAULT_BRANCH_NAME; |
211 File branchFile = new File(repo.getRepositoryRoot(), "branch"); | 210 File branchFile = new File(repo.getRepositoryRoot(), "branch"); |
212 if (branchFile.exists()) { | 211 if (branchFile.exists()) { |
213 try { | 212 try { |
214 BufferedReader r = new BufferedReader(new FileReader(branchFile)); | 213 BufferedReader r = new BufferedReader(new FileReader(branchFile)); |
216 if (b != null) { | 215 if (b != null) { |
217 b = b.trim().intern(); | 216 b = b.trim().intern(); |
218 } | 217 } |
219 branch = b == null || b.length() == 0 ? HgRepository.DEFAULT_BRANCH_NAME : b; | 218 branch = b == null || b.length() == 0 ? HgRepository.DEFAULT_BRANCH_NAME : b; |
220 r.close(); | 219 r.close(); |
220 } catch (FileNotFoundException ex) { | |
221 repo.getContext().getLog().debug(HgDirstate.class, ex, null); // log verbose debug, exception might be legal here | |
222 // IGNORE | |
221 } catch (IOException ex) { | 223 } catch (IOException ex) { |
222 repo.getContext().getLog().debug(HgDirstate.class, ex, null); // log verbose debug, exception might be legal here (i.e. FileNotFound) | 224 throw new HgInvalidControlFileException("Error reading file with branch information", ex, branchFile); |
223 // IGNORE | |
224 } | 225 } |
225 } | 226 } |
226 return branch; | 227 return branch; |
227 } | 228 } |
228 | 229 |
229 // new, modifiable collection | 230 // new, modifiable collection |
230 /*package-local*/ TreeSet<Path> all() { | 231 /*package-local*/ TreeSet<Path> all() { |
231 if (normal == null) { | 232 assert normal != null; |
232 read(); | |
233 } | |
234 TreeSet<Path> rv = new TreeSet<Path>(); | 233 TreeSet<Path> rv = new TreeSet<Path>(); |
235 @SuppressWarnings("unchecked") | 234 @SuppressWarnings("unchecked") |
236 Map<Path, Record>[] all = new Map[] { normal, added, removed, merged }; | 235 Map<Path, Record>[] all = new Map[] { normal, added, removed, merged }; |
237 for (int i = 0; i < all.length; i++) { | 236 for (int i = 0; i < all.length; i++) { |
238 for (Record r : all[i].values()) { | 237 for (Record r : all[i].values()) { |
297 } | 296 } |
298 } | 297 } |
299 return null; | 298 return null; |
300 } | 299 } |
301 | 300 |
302 | |
303 /*package-local*/ void dump() { | |
304 read(); | |
305 @SuppressWarnings("unchecked") | |
306 Map<Path, Record>[] all = new Map[] { normal, added, removed, merged }; | |
307 char[] x = new char[] {'n', 'a', 'r', 'm' }; | |
308 for (int i = 0; i < all.length; i++) { | |
309 for (Record r : all[i].values()) { | |
310 System.out.printf("%c %3o%6d %30tc\t\t%s", x[i], r.mode, r.size, (long) r.time * 1000, r.name1); | |
311 if (r.name2 != null) { | |
312 System.out.printf(" --> %s", r.name2); | |
313 } | |
314 System.out.println(); | |
315 } | |
316 System.out.println(); | |
317 } | |
318 } | |
319 | |
320 public void walk(Inspector inspector) { | 301 public void walk(Inspector inspector) { |
321 if (normal == null) { | 302 assert normal != null; |
322 read(); | |
323 } | |
324 @SuppressWarnings("unchecked") | 303 @SuppressWarnings("unchecked") |
325 Map<Path, Record>[] all = new Map[] { normal, added, removed, merged }; | 304 Map<Path, Record>[] all = new Map[] { normal, added, removed, merged }; |
326 for (int i = 0; i < all.length; i++) { | 305 for (int i = 0; i < all.length; i++) { |
327 EntryKind k = EntryKind.values()[i]; | 306 EntryKind k = EntryKind.values()[i]; |
328 for (Record r : all[i].values()) { | 307 for (Record r : all[i].values()) { |
375 | 354 |
376 public int size() { | 355 public int size() { |
377 return size; | 356 return size; |
378 } | 357 } |
379 | 358 |
359 public int mode() { | |
360 return mode; | |
361 } | |
362 | |
380 @Override | 363 @Override |
381 public Record clone() { | 364 public Record clone() { |
382 try { | 365 try { |
383 return (Record) super.clone(); | 366 return (Record) super.clone(); |
384 } catch (CloneNotSupportedException ex) { | 367 } catch (CloneNotSupportedException ex) { |