tikhomirov@231: /* tikhomirov@231: * Copyright (c) 2011 TMate Software Ltd tikhomirov@231: * tikhomirov@231: * This program is free software; you can redistribute it and/or modify tikhomirov@231: * it under the terms of the GNU General Public License as published by tikhomirov@231: * the Free Software Foundation; version 2 of the License. tikhomirov@231: * tikhomirov@231: * This program is distributed in the hope that it will be useful, tikhomirov@231: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@231: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@231: * GNU General Public License for more details. tikhomirov@231: * tikhomirov@231: * For information on how to redistribute this software under tikhomirov@231: * the terms of a license other than GNU General Public License tikhomirov@231: * contact TMate Software at support@hg4j.com tikhomirov@231: */ tikhomirov@231: package org.tmatesoft.hg.repo; tikhomirov@231: tikhomirov@231: import java.io.BufferedReader; tikhomirov@231: import java.io.File; tikhomirov@231: import java.io.FileReader; tikhomirov@231: import java.io.IOException; tikhomirov@231: import java.util.ArrayList; tikhomirov@231: import java.util.Arrays; tikhomirov@231: import java.util.Collections; tikhomirov@231: import java.util.List; tikhomirov@231: tikhomirov@231: import org.tmatesoft.hg.core.HgBadStateException; tikhomirov@231: import org.tmatesoft.hg.core.HgFileRevision; tikhomirov@231: import org.tmatesoft.hg.core.HgLogCommand.FileRevision; tikhomirov@231: import org.tmatesoft.hg.core.Nodeid; tikhomirov@248: import org.tmatesoft.hg.internal.ManifestRevision; tikhomirov@231: import org.tmatesoft.hg.internal.Pool; tikhomirov@231: import org.tmatesoft.hg.util.Path; tikhomirov@231: import org.tmatesoft.hg.util.PathPool; tikhomirov@231: import org.tmatesoft.hg.util.PathRewrite; tikhomirov@231: tikhomirov@231: /** tikhomirov@231: * tikhomirov@231: * @author Artem Tikhomirov tikhomirov@231: * @author TMate Software Ltd. tikhomirov@231: */ tikhomirov@231: public class HgMergeState { tikhomirov@231: private Nodeid wcp1, wcp2; tikhomirov@231: tikhomirov@231: public enum Kind { tikhomirov@231: Resolved, Unresolved; tikhomirov@231: } tikhomirov@231: tikhomirov@231: public static class Entry { tikhomirov@231: private final Kind state; tikhomirov@231: private final HgFileRevision parent1; tikhomirov@231: private final HgFileRevision parent2; tikhomirov@231: private final HgFileRevision ancestor; tikhomirov@231: private final Path wcFile; tikhomirov@231: tikhomirov@231: /*package-local*/Entry(Kind s, Path actualCopy, HgFileRevision p1, HgFileRevision p2, HgFileRevision ca) { tikhomirov@231: if (p1 == null || p2 == null || ca == null || actualCopy == null) { tikhomirov@231: throw new IllegalArgumentException(); tikhomirov@231: } tikhomirov@231: state = s; tikhomirov@231: wcFile = actualCopy; tikhomirov@231: parent1 = p1; tikhomirov@231: parent2 = p2; tikhomirov@231: ancestor = ca; tikhomirov@231: } tikhomirov@231: tikhomirov@231: public Kind getState() { tikhomirov@231: return state; tikhomirov@231: } tikhomirov@231: public Path getActualFile() { tikhomirov@231: return wcFile; tikhomirov@231: } tikhomirov@231: public HgFileRevision getFirstParent() { tikhomirov@231: return parent1; tikhomirov@231: } tikhomirov@231: public HgFileRevision getSecondParent() { tikhomirov@231: return parent2; tikhomirov@231: } tikhomirov@231: public HgFileRevision getCommonAncestor() { tikhomirov@231: return ancestor; tikhomirov@231: } tikhomirov@231: } tikhomirov@231: tikhomirov@231: private final HgRepository repo; tikhomirov@231: private Entry[] entries; tikhomirov@231: tikhomirov@231: HgMergeState(HgRepository hgRepo) { tikhomirov@231: repo = hgRepo; tikhomirov@231: } tikhomirov@231: tikhomirov@231: public void refresh() throws IOException/*XXX it's unlikely caller can do anything reasonable about IOException */ { tikhomirov@231: entries = null; tikhomirov@231: final File f = new File(repo.getRepositoryRoot(), "merge/state"); tikhomirov@231: if (!f.canRead()) { tikhomirov@231: // empty state tikhomirov@231: return; tikhomirov@231: } tikhomirov@231: Nodeid[] wcParents = repo.loadDirstate().parents(); tikhomirov@231: wcp1 = wcParents[0]; wcp2 = wcParents[1]; tikhomirov@231: ArrayList result = new ArrayList(); tikhomirov@231: PathPool pathPool = new PathPool(new PathRewrite.Empty()); tikhomirov@231: Pool nodeidPool = new Pool(); tikhomirov@231: Pool fnamePool = new Pool(); tikhomirov@248: final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool); tikhomirov@248: final ManifestRevision m2 = new ManifestRevision(nodeidPool, fnamePool); tikhomirov@231: final int rp1 = repo.getChangelog().getLocalRevision(wcp1); tikhomirov@231: final int rp2 = repo.getChangelog().getLocalRevision(wcp2); tikhomirov@231: repo.getManifest().walk(rp1, rp1, m1); tikhomirov@231: repo.getManifest().walk(rp2, rp2, m2); tikhomirov@231: BufferedReader br = new BufferedReader(new FileReader(f)); tikhomirov@231: String s = br.readLine(); tikhomirov@231: Nodeid n = Nodeid.fromAscii(s); tikhomirov@231: if (!wcp1.equals(n)) { tikhomirov@231: throw new AssertionError("I assume merge/state records revision of the wc we merge into"); tikhomirov@231: } tikhomirov@231: while ((s = br.readLine()) != null) { tikhomirov@231: String[] r = s.split("\\00"); tikhomirov@231: HgFileRevision p1 = new HgFileRevision(repo, m1.nodeid(r[3]), pathPool.path(r[3])); tikhomirov@231: HgFileRevision ca = new HgFileRevision(repo, Nodeid.fromAscii(r[5]), pathPool.path(r[4])); tikhomirov@231: HgFileRevision p2 = new HgFileRevision(repo, m2.nodeid(r[6]), pathPool.path(r[6])); tikhomirov@231: final Kind k; tikhomirov@231: if ("u".equals(r[1])) { tikhomirov@231: k = Kind.Unresolved; tikhomirov@231: } else if ("r".equals(r[1])) { tikhomirov@231: k = Kind.Resolved; tikhomirov@231: } else { tikhomirov@231: throw new HgBadStateException(r[1]); tikhomirov@231: } tikhomirov@231: Entry e = new Entry(k, pathPool.path(r[0]), p1, p2, ca); tikhomirov@231: result.add(e); tikhomirov@231: } tikhomirov@231: entries = result.toArray(new Entry[result.size()]); tikhomirov@231: br.close(); tikhomirov@231: pathPool.clear(); tikhomirov@231: } tikhomirov@231: tikhomirov@231: public Nodeid getFirstParent() { tikhomirov@231: if (wcp1 == null) { tikhomirov@231: throw new HgBadStateException("Call #refresh() first"); tikhomirov@231: } tikhomirov@231: return wcp1; tikhomirov@231: } tikhomirov@231: tikhomirov@231: public Nodeid getSecondParent() { tikhomirov@231: if (wcp2 == null) { tikhomirov@231: throw new HgBadStateException("Call #refresh() first"); tikhomirov@231: } tikhomirov@231: return wcp2; tikhomirov@231: } tikhomirov@231: tikhomirov@231: public List getConflicts() { tikhomirov@231: return entries == null ? Collections.emptyList() : Arrays.asList(entries); tikhomirov@231: } tikhomirov@231: }