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