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.core; tikhomirov@231: tikhomirov@231: import org.tmatesoft.hg.repo.HgDataFile; tikhomirov@231: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@231: import org.tmatesoft.hg.util.ByteChannel; tikhomirov@231: import org.tmatesoft.hg.util.CancelledException; tikhomirov@345: import org.tmatesoft.hg.util.Pair; tikhomirov@231: import org.tmatesoft.hg.util.Path; tikhomirov@231: tikhomirov@231: /** tikhomirov@231: * Keeps together information about specific file revision tikhomirov@231: * tikhomirov@231: * @author Artem Tikhomirov tikhomirov@231: * @author TMate Software Ltd. tikhomirov@231: */ tikhomirov@249: public final class HgFileRevision { tikhomirov@231: private final HgRepository repo; tikhomirov@231: private final Nodeid revision; tikhomirov@231: private final Path path; tikhomirov@316: private Path origin; tikhomirov@316: private Boolean isCopy = null; // null means not yet known tikhomirov@345: private Pair parents; tikhomirov@316: tikhomirov@231: public HgFileRevision(HgRepository hgRepo, Nodeid rev, Path p) { tikhomirov@231: if (hgRepo == null || rev == null || p == null) { tikhomirov@231: // since it's package local, it is our code to blame for non validated arguments tikhomirov@316: throw new IllegalArgumentException(); tikhomirov@231: } tikhomirov@231: repo = hgRepo; tikhomirov@231: revision = rev; tikhomirov@231: path = p; tikhomirov@231: } tikhomirov@316: tikhomirov@316: // this cons shall be used when we know whether p was a copy. Perhaps, shall pass Map instead to stress orig argument is not optional tikhomirov@316: HgFileRevision(HgRepository hgRepo, Nodeid rev, Path p, Path orig) { tikhomirov@316: this(hgRepo, rev, p); tikhomirov@316: isCopy = Boolean.valueOf(orig == null); tikhomirov@316: origin = orig; tikhomirov@316: } tikhomirov@231: tikhomirov@231: public Path getPath() { tikhomirov@231: return path; tikhomirov@231: } tikhomirov@364: tikhomirov@231: public Nodeid getRevision() { tikhomirov@231: return revision; tikhomirov@231: } tikhomirov@364: tikhomirov@364: public boolean wasCopied() throws HgException { tikhomirov@316: if (isCopy == null) { tikhomirov@316: checkCopy(); tikhomirov@316: } tikhomirov@316: return isCopy.booleanValue(); tikhomirov@316: } tikhomirov@316: /** tikhomirov@316: * @return null if {@link #wasCopied()} is false, name of the copy source otherwise. tikhomirov@316: */ tikhomirov@364: public Path getOriginIfCopy() throws HgException { tikhomirov@316: if (wasCopied()) { tikhomirov@316: return origin; tikhomirov@316: } tikhomirov@316: return null; tikhomirov@316: } tikhomirov@316: tikhomirov@345: /** tikhomirov@345: * Access revisions this file revision originates from. tikhomirov@345: * Note, these revisions are records in the file history, not that of the whole repository (aka changeset revisions) tikhomirov@345: * In most cases, only one parent revision would be present, only for merge revisions one can expect both. tikhomirov@345: * tikhomirov@345: * @return parent revisions of this file revision, with {@link Nodeid#NULL} for missing values. tikhomirov@345: */ tikhomirov@354: public Pair getParents() throws HgInvalidControlFileException { tikhomirov@345: if (parents == null) { tikhomirov@345: HgDataFile fn = repo.getFileNode(path); tikhomirov@345: int localRevision = fn.getLocalRevision(revision); tikhomirov@345: int[] pr = new int[2]; tikhomirov@345: byte[] p1 = new byte[20], p2 = new byte[20]; tikhomirov@345: // XXX Revlog#parents is not the best method to use here tikhomirov@345: // need smth that gives Nodeids (piped through Pool from repo's context) tikhomirov@345: fn.parents(localRevision, pr, p1, p2); tikhomirov@345: parents = new Pair(Nodeid.fromBinary(p1, 0), Nodeid.fromBinary(p2, 0)); tikhomirov@345: } tikhomirov@345: return parents; tikhomirov@345: } tikhomirov@345: tikhomirov@354: public void putContentTo(ByteChannel sink) throws HgDataStreamException, HgInvalidControlFileException, CancelledException { tikhomirov@231: HgDataFile fn = repo.getFileNode(path); tikhomirov@231: int localRevision = fn.getLocalRevision(revision); tikhomirov@231: fn.contentWithFilters(localRevision, sink); tikhomirov@231: } tikhomirov@231: tikhomirov@364: private void checkCopy() throws HgInvalidControlFileException, HgDataStreamException { tikhomirov@316: HgDataFile fn = repo.getFileNode(path); tikhomirov@364: if (fn.isCopy()) { tikhomirov@364: if (fn.getRevision(0).equals(revision)) { tikhomirov@364: // this HgFileRevision represents first revision of the copy tikhomirov@364: isCopy = Boolean.TRUE; tikhomirov@364: origin = fn.getCopySourceName(); tikhomirov@364: return; tikhomirov@316: } tikhomirov@316: } tikhomirov@316: isCopy = Boolean.FALSE; tikhomirov@316: } tikhomirov@231: }