Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/DirstateReader.java @ 526:2f9ed6bcefa2
Initial support for Revert command with accompanying minor refactoring
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Tue, 15 Jan 2013 17:07:19 +0100 |
| parents | src/org/tmatesoft/hg/repo/HgDirstate.java@0be5be8d57e9 |
| children | 47b7bedf0569 |
comparison
equal
deleted
inserted
replaced
| 525:0be5be8d57e9 | 526:2f9ed6bcefa2 |
|---|---|
| 1 /* | |
| 2 * Copyright (c) 2010-2013 TMate Software Ltd | |
| 3 * | |
| 4 * This program is free software; you can redistribute it and/or modify | |
| 5 * it under the terms of the GNU General Public License as published by | |
| 6 * the Free Software Foundation; version 2 of the License. | |
| 7 * | |
| 8 * This program is distributed in the hope that it will be useful, | |
| 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 11 * GNU General Public License for more details. | |
| 12 * | |
| 13 * For information on how to redistribute this software under | |
| 14 * the terms of a license other than GNU General Public License | |
| 15 * contact TMate Software at support@hg4j.com | |
| 16 */ | |
| 17 package org.tmatesoft.hg.internal; | |
| 18 | |
| 19 import static org.tmatesoft.hg.core.Nodeid.NULL; | |
| 20 import static org.tmatesoft.hg.repo.HgRepositoryFiles.Dirstate; | |
| 21 import static org.tmatesoft.hg.util.LogFacility.Severity.Debug; | |
| 22 | |
| 23 import java.io.BufferedReader; | |
| 24 import java.io.File; | |
| 25 import java.io.FileNotFoundException; | |
| 26 import java.io.FileReader; | |
| 27 import java.io.IOException; | |
| 28 | |
| 29 import org.tmatesoft.hg.core.Nodeid; | |
| 30 import org.tmatesoft.hg.repo.HgDirstate; | |
| 31 import org.tmatesoft.hg.repo.HgDirstate.EntryKind; | |
| 32 import org.tmatesoft.hg.repo.HgInvalidControlFileException; | |
| 33 import org.tmatesoft.hg.repo.HgRepository; | |
| 34 import org.tmatesoft.hg.util.LogFacility.Severity; | |
| 35 import org.tmatesoft.hg.util.Pair; | |
| 36 import org.tmatesoft.hg.util.Path; | |
| 37 | |
| 38 | |
| 39 /** | |
| 40 * Parse dirstate file | |
| 41 * | |
| 42 * @see http://mercurial.selenic.com/wiki/DirState | |
| 43 * @see http://mercurial.selenic.com/wiki/FileFormats#dirstate | |
| 44 * | |
| 45 * @author Artem Tikhomirov | |
| 46 * @author TMate Software Ltd. | |
| 47 */ | |
| 48 public final class DirstateReader { | |
| 49 // dirstate read code originally lived in org.tmatesoft.hg.repo.HgDirstate | |
| 50 | |
| 51 private final Internals repo; | |
| 52 private final Path.Source pathPool; | |
| 53 private Pair<Nodeid, Nodeid> parents; | |
| 54 | |
| 55 public DirstateReader(Internals hgRepo, Path.Source pathSource) { | |
| 56 repo = hgRepo; | |
| 57 pathPool = pathSource; | |
| 58 } | |
| 59 | |
| 60 public void readInto(HgDirstate.Inspector target) throws HgInvalidControlFileException { | |
| 61 EncodingHelper encodingHelper = repo.buildFileNameEncodingHelper(); | |
| 62 parents = new Pair<Nodeid,Nodeid>(Nodeid.NULL, Nodeid.NULL); | |
| 63 File dirstateFile = getDirstateFile(repo); | |
| 64 if (dirstateFile == null || !dirstateFile.exists()) { | |
| 65 return; | |
| 66 } | |
| 67 DataAccess da = repo.getDataAccess().create(dirstateFile); | |
| 68 try { | |
| 69 if (da.isEmpty()) { | |
| 70 return; | |
| 71 } | |
| 72 parents = internalReadParents(da); | |
| 73 // hg init; hg up produces an empty repository where dirstate has parents (40 bytes) only | |
| 74 while (!da.isEmpty()) { | |
| 75 final byte state = da.readByte(); | |
| 76 final int fmode = da.readInt(); | |
| 77 final int size = da.readInt(); | |
| 78 final int time = da.readInt(); | |
| 79 final int nameLen = da.readInt(); | |
| 80 String fn1 = null, fn2 = null; | |
| 81 byte[] name = new byte[nameLen]; | |
| 82 da.readBytes(name, 0, nameLen); | |
| 83 for (int i = 0; i < nameLen; i++) { | |
| 84 if (name[i] == 0) { | |
| 85 fn1 = encodingHelper.fromDirstate(name, 0, i); | |
| 86 fn2 = encodingHelper.fromDirstate(name, i+1, nameLen - i - 1); | |
| 87 break; | |
| 88 } | |
| 89 } | |
| 90 if (fn1 == null) { | |
| 91 fn1 = encodingHelper.fromDirstate(name, 0, nameLen); | |
| 92 } | |
| 93 HgDirstate.Record r = new HgDirstate.Record(fmode, size, time, pathPool.path(fn1), fn2 == null ? null : pathPool.path(fn2)); | |
| 94 if (state == 'n') { | |
| 95 target.next(EntryKind.Normal, r); | |
| 96 } else if (state == 'a') { | |
| 97 target.next(EntryKind.Added, r); | |
| 98 } else if (state == 'r') { | |
| 99 target.next(EntryKind.Removed, r); | |
| 100 } else if (state == 'm') { | |
| 101 target.next(EntryKind.Merged, r); | |
| 102 } else { | |
| 103 repo.getSessionContext().getLog().dump(getClass(), Severity.Warn, "Dirstate record for file %s (size: %d, tstamp:%d) has unknown state '%c'", r.name(), r.size(), r.modificationTime(), state); | |
| 104 } | |
| 105 } | |
| 106 } catch (IOException ex) { | |
| 107 throw new HgInvalidControlFileException("Dirstate read failed", ex, dirstateFile); | |
| 108 } finally { | |
| 109 da.done(); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 private static Pair<Nodeid, Nodeid> internalReadParents(DataAccess da) throws IOException { | |
| 114 byte[] parents = new byte[40]; | |
| 115 da.readBytes(parents, 0, 40); | |
| 116 Nodeid n1 = Nodeid.fromBinary(parents, 0); | |
| 117 Nodeid n2 = Nodeid.fromBinary(parents, 20); | |
| 118 parents = null; | |
| 119 return new Pair<Nodeid, Nodeid>(n1, n2); | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * @return pair of working copy parents, with {@link Nodeid#NULL} for missing values. | |
| 124 */ | |
| 125 public Pair<Nodeid,Nodeid> parents() { | |
| 126 assert parents != null; // instance not initialized with #read() | |
| 127 return parents; | |
| 128 } | |
| 129 | |
| 130 private static File getDirstateFile(Internals repo) { | |
| 131 return repo.getFileFromRepoDir(Dirstate.getName()); | |
| 132 } | |
| 133 | |
| 134 /** | |
| 135 * @return pair of parents, both {@link Nodeid#NULL} if dirstate is not available | |
| 136 */ | |
| 137 public static Pair<Nodeid, Nodeid> readParents(Internals internalRepo) throws HgInvalidControlFileException { | |
| 138 // do not read whole dirstate if all we need is WC parent information | |
| 139 File dirstateFile = getDirstateFile(internalRepo); | |
| 140 if (dirstateFile == null || !dirstateFile.exists()) { | |
| 141 return new Pair<Nodeid,Nodeid>(NULL, NULL); | |
| 142 } | |
| 143 DataAccess da = internalRepo.getDataAccess().create(dirstateFile); | |
| 144 try { | |
| 145 if (da.isEmpty()) { | |
| 146 return new Pair<Nodeid,Nodeid>(NULL, NULL); | |
| 147 } | |
| 148 return internalReadParents(da); | |
| 149 } catch (IOException ex) { | |
| 150 throw new HgInvalidControlFileException("Error reading working copy parents from dirstate", ex, dirstateFile); | |
| 151 } finally { | |
| 152 da.done(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 /** | |
| 157 * TODO [post-1.0] it's really not a proper place for the method, need WorkingCopyContainer or similar | |
| 158 * @return branch associated with the working directory | |
| 159 */ | |
| 160 public static String readBranch(Internals internalRepo) throws HgInvalidControlFileException { | |
| 161 File branchFile = internalRepo.getFileFromRepoDir("branch"); // FIXME constant in the HgRepositoryFiles | |
| 162 String branch = HgRepository.DEFAULT_BRANCH_NAME; | |
| 163 if (branchFile.exists()) { | |
| 164 try { | |
| 165 BufferedReader r = new BufferedReader(new FileReader(branchFile)); | |
| 166 String b = r.readLine(); | |
| 167 if (b != null) { | |
| 168 b = b.trim().intern(); | |
| 169 } | |
| 170 branch = b == null || b.length() == 0 ? HgRepository.DEFAULT_BRANCH_NAME : b; | |
| 171 r.close(); | |
| 172 } catch (FileNotFoundException ex) { | |
| 173 internalRepo.getSessionContext().getLog().dump(HgDirstate.class, Debug, ex, null); // log verbose debug, exception might be legal here | |
| 174 // IGNORE | |
| 175 } catch (IOException ex) { | |
| 176 throw new HgInvalidControlFileException("Error reading file with branch information", ex, branchFile); | |
| 177 } | |
| 178 } | |
| 179 return branch; | |
| 180 } | |
| 181 } |
