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