comparison src/org/tmatesoft/hg/repo/HgMergeState.java @ 270:c6450b0b1fd5

Avoid IAE:nullid when looking into stale merge/state file
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 24 Aug 2011 04:10:17 +0200
parents 4c3b9f679412
children 7232b94f2ae3
comparison
equal deleted inserted replaced
269:7af843ecc378 270:c6450b0b1fd5
13 * For information on how to redistribute this software under 13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.repo; 17 package org.tmatesoft.hg.repo;
18
19 import static org.tmatesoft.hg.core.Nodeid.NULL;
18 20
19 import java.io.BufferedReader; 21 import java.io.BufferedReader;
20 import java.io.File; 22 import java.io.File;
21 import java.io.FileReader; 23 import java.io.FileReader;
22 import java.io.IOException; 24 import java.io.IOException;
38 * 40 *
39 * @author Artem Tikhomirov 41 * @author Artem Tikhomirov
40 * @author TMate Software Ltd. 42 * @author TMate Software Ltd.
41 */ 43 */
42 public class HgMergeState { 44 public class HgMergeState {
43 private Nodeid wcp1, wcp2; 45 private Nodeid wcp1, wcp2, stateParent;
44 46
45 public enum Kind { 47 public enum Kind {
46 Resolved, Unresolved; 48 Resolved, Unresolved;
47 } 49 }
48 50
93 final File f = new File(repo.getRepositoryRoot(), "merge/state"); 95 final File f = new File(repo.getRepositoryRoot(), "merge/state");
94 if (!f.canRead()) { 96 if (!f.canRead()) {
95 // empty state 97 // empty state
96 return; 98 return;
97 } 99 }
100 Pool<Nodeid> nodeidPool = new Pool<Nodeid>();
101 Pool<String> fnamePool = new Pool<String>();
98 Nodeid[] wcParents = repo.loadDirstate().parents(); 102 Nodeid[] wcParents = repo.loadDirstate().parents();
99 wcp1 = wcParents[0]; wcp2 = wcParents[1]; 103 wcp1 = nodeidPool.unify(wcParents[0]); wcp2 = nodeidPool.unify(wcParents[1]);
100 ArrayList<Entry> result = new ArrayList<Entry>(); 104 ArrayList<Entry> result = new ArrayList<Entry>();
101 PathPool pathPool = new PathPool(new PathRewrite.Empty()); 105 PathPool pathPool = new PathPool(new PathRewrite.Empty());
102 Pool<Nodeid> nodeidPool = new Pool<Nodeid>();
103 Pool<String> fnamePool = new Pool<String>();
104 final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool); 106 final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool);
105 final ManifestRevision m2 = new ManifestRevision(nodeidPool, fnamePool); 107 final ManifestRevision m2 = new ManifestRevision(nodeidPool, fnamePool);
106 final int rp1 = repo.getChangelog().getLocalRevision(wcp1); 108 if (!wcp2.isNull()) {
107 final int rp2 = repo.getChangelog().getLocalRevision(wcp2); 109 final int rp2 = repo.getChangelog().getLocalRevision(wcp2);
108 repo.getManifest().walk(rp1, rp1, m1); 110 repo.getManifest().walk(rp2, rp2, m2);
109 repo.getManifest().walk(rp2, rp2, m2); 111 }
110 BufferedReader br = new BufferedReader(new FileReader(f)); 112 BufferedReader br = new BufferedReader(new FileReader(f));
111 String s = br.readLine(); 113 String s = br.readLine();
112 Nodeid n = Nodeid.fromAscii(s); 114 stateParent = nodeidPool.unify(Nodeid.fromAscii(s));
113 if (!wcp1.equals(n)) { 115 final int rp1 = repo.getChangelog().getLocalRevision(stateParent);
114 throw new AssertionError("I assume merge/state records revision of the wc we merge into"); 116 repo.getManifest().walk(rp1, rp1, m1);
115 }
116 while ((s = br.readLine()) != null) { 117 while ((s = br.readLine()) != null) {
117 String[] r = s.split("\\00"); 118 String[] r = s.split("\\00");
118 HgFileRevision p1 = new HgFileRevision(repo, m1.nodeid(r[3]), pathPool.path(r[3])); 119 Nodeid nidP1 = m1.nodeid(r[3]);
119 HgFileRevision ca = new HgFileRevision(repo, Nodeid.fromAscii(r[5]), pathPool.path(r[4])); 120 Nodeid nidCA = nodeidPool.unify(Nodeid.fromAscii(r[5]));
120 HgFileRevision p2 = new HgFileRevision(repo, m2.nodeid(r[6]), pathPool.path(r[6])); 121 HgFileRevision p1 = new HgFileRevision(repo, nidP1, pathPool.path(r[3]));
122 HgFileRevision ca;
123 if (nidCA == nidP1 && r[3].equals(r[4])) {
124 ca = p1;
125 } else {
126 ca = new HgFileRevision(repo, nidCA, pathPool.path(r[4]));
127 }
128 HgFileRevision p2;
129 if (!wcp2.isNull() || !r[6].equals(r[4])) {
130 Nodeid nidP2 = m2.nodeid(r[6]);
131 if (nidP2 == null) {
132 assert false : "There's not enough information (or I don't know where to look) in merge/state to find out what's the second parent";
133 nidP2 = NULL;
134 }
135 p2 = new HgFileRevision(repo, nidP2, pathPool.path(r[6]));
136 } else {
137 // no second parent known. no idea what to do here, assume linear merge, use common ancestor as parent
138 p2 = ca;
139 }
121 final Kind k; 140 final Kind k;
122 if ("u".equals(r[1])) { 141 if ("u".equals(r[1])) {
123 k = Kind.Unresolved; 142 k = Kind.Unresolved;
124 } else if ("r".equals(r[1])) { 143 } else if ("r".equals(r[1])) {
125 k = Kind.Resolved; 144 k = Kind.Resolved;
130 result.add(e); 149 result.add(e);
131 } 150 }
132 entries = result.toArray(new Entry[result.size()]); 151 entries = result.toArray(new Entry[result.size()]);
133 br.close(); 152 br.close();
134 pathPool.clear(); 153 pathPool.clear();
154 }
155
156
157 public boolean isMerging() {
158 return !getFirstParent().isNull() && !getSecondParent().isNull() && !isStale();
159 }
160
161 /**
162 * @return <code>true</code> when recorded merge state doesn't seem to correspond to present working copy
163 */
164 public boolean isStale() {
165 if (wcp1 == null) {
166 throw new HgBadStateException("Call #refresh() first");
167 }
168 return !wcp1.equals(stateParent);
135 } 169 }
136 170
137 public Nodeid getFirstParent() { 171 public Nodeid getFirstParent() {
138 if (wcp1 == null) { 172 if (wcp1 == null) {
139 throw new HgBadStateException("Call #refresh() first"); 173 throw new HgBadStateException("Call #refresh() first");
146 throw new HgBadStateException("Call #refresh() first"); 180 throw new HgBadStateException("Call #refresh() first");
147 } 181 }
148 return wcp2; 182 return wcp2;
149 } 183 }
150 184
185 public Nodeid getStateParent() {
186 if (stateParent == null) {
187 throw new HgBadStateException("Call #refresh() first");
188 }
189 return stateParent;
190 }
191
151 public List<Entry> getConflicts() { 192 public List<Entry> getConflicts() {
152 return entries == null ? Collections.<Entry>emptyList() : Arrays.asList(entries); 193 return entries == null ? Collections.<Entry>emptyList() : Arrays.asList(entries);
153 } 194 }
154 } 195 }