Mercurial > hg4j
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 } |