tikhomirov@47: /* tikhomirov@72: * Copyright (c) 2010-2011 TMate Software Ltd tikhomirov@72: * tikhomirov@72: * This program is free software; you can redistribute it and/or modify tikhomirov@72: * it under the terms of the GNU General Public License as published by tikhomirov@72: * the Free Software Foundation; version 2 of the License. tikhomirov@72: * tikhomirov@72: * This program is distributed in the hope that it will be useful, tikhomirov@72: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@72: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@72: * GNU General Public License for more details. tikhomirov@72: * tikhomirov@72: * For information on how to redistribute this software under tikhomirov@72: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@1: */ tikhomirov@72: package org.tmatesoft.hg.console; tikhomirov@1: tikhomirov@47: import java.util.Formatter; tikhomirov@47: import java.util.LinkedList; tikhomirov@47: import java.util.List; tikhomirov@65: tikhomirov@129: import org.tmatesoft.hg.core.HgChangeset; tikhomirov@131: import org.tmatesoft.hg.core.HgLogCommand; tikhomirov@131: import org.tmatesoft.hg.core.HgLogCommand.FileRevision; tikhomirov@74: import org.tmatesoft.hg.core.Nodeid; tikhomirov@97: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@74: import org.tmatesoft.hg.repo.HgDataFile; tikhomirov@74: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@133: import org.tmatesoft.hg.util.Path; tikhomirov@47: tikhomirov@1: tikhomirov@1: /** tikhomirov@72: * @author Artem Tikhomirov tikhomirov@72: * @author TMate Software Ltd. tikhomirov@1: */ tikhomirov@1: public class Log { tikhomirov@1: tikhomirov@1: public static void main(String[] args) throws Exception { tikhomirov@74: Options cmdLineOpts = Options.parse(args); tikhomirov@74: HgRepository hgRepo = cmdLineOpts.findRepository(); tikhomirov@1: if (hgRepo.isInvalid()) { tikhomirov@1: System.err.printf("Can't find repository in: %s\n", hgRepo.getLocation()); tikhomirov@1: return; tikhomirov@1: } tikhomirov@1: System.out.println(hgRepo.getLocation()); tikhomirov@47: final Dump dump = new Dump(hgRepo); tikhomirov@49: dump.complete = true; //cmdLineOpts; tikhomirov@60: dump.verbose = false; //cmdLineOpts; tikhomirov@47: dump.reverseOrder = true; tikhomirov@131: HgLogCommand cmd = new HgLogCommand(hgRepo); tikhomirov@49: if (cmdLineOpts.users != null) { tikhomirov@49: for (String u : cmdLineOpts.users) { tikhomirov@65: cmd.user(u); tikhomirov@49: } tikhomirov@49: } tikhomirov@65: if (cmdLineOpts.branches != null) { tikhomirov@65: for (String b : cmdLineOpts.branches) { tikhomirov@65: cmd.branch(b); tikhomirov@65: } tikhomirov@65: } tikhomirov@65: if (cmdLineOpts.limit != -1) { tikhomirov@65: cmd.limit(cmdLineOpts.limit); tikhomirov@65: tikhomirov@65: } tikhomirov@6: if (cmdLineOpts.files.isEmpty()) { tikhomirov@48: if (cmdLineOpts.limit == -1) { tikhomirov@49: // no revisions and no limit tikhomirov@65: cmd.execute(dump); tikhomirov@48: } else { tikhomirov@49: // in fact, external (to dump inspector) --limit processing yelds incorrect results when other args tikhomirov@49: // e.g. -u or -b are used (i.e. with -u shall give csets with user, not check last csets for user tikhomirov@48: int[] r = new int[] { 0, hgRepo.getChangelog().getRevisionCount() }; tikhomirov@48: if (fixRange(r, dump.reverseOrder, cmdLineOpts.limit) == 0) { tikhomirov@48: System.out.println("No changes"); tikhomirov@48: return; tikhomirov@48: } tikhomirov@65: cmd.range(r[0], r[1]).execute(dump); tikhomirov@48: } tikhomirov@47: dump.complete(); tikhomirov@6: } else { tikhomirov@6: for (String fname : cmdLineOpts.files) { tikhomirov@6: HgDataFile f1 = hgRepo.getFileNode(fname); tikhomirov@8: System.out.println("History of the file: " + f1.getPath()); tikhomirov@77: String normalizesName = hgRepo.getPathHelper().rewrite(fname); tikhomirov@48: if (cmdLineOpts.limit == -1) { tikhomirov@80: cmd.file(Path.create(normalizesName), true).execute(dump); tikhomirov@48: } else { tikhomirov@48: int[] r = new int[] { 0, f1.getRevisionCount() }; tikhomirov@48: if (fixRange(r, dump.reverseOrder, cmdLineOpts.limit) == 0) { tikhomirov@48: System.out.println("No changes"); tikhomirov@48: continue; tikhomirov@48: } tikhomirov@80: cmd.range(r[0], r[1]).file(Path.create(normalizesName), true).execute(dump); tikhomirov@48: } tikhomirov@47: dump.complete(); tikhomirov@6: } tikhomirov@6: } tikhomirov@2: // tikhomirov@49: // XXX new ChangelogWalker().setFile("hello.c").setRevisionRange(1, 4).accept(new Visitor); tikhomirov@1: } tikhomirov@48: tikhomirov@48: private static int fixRange(int[] start_end, boolean reverse, int limit) { tikhomirov@48: assert start_end.length == 2; tikhomirov@48: if (limit < start_end[1]) { tikhomirov@48: if (reverse) { tikhomirov@48: // adjust left boundary of the range tikhomirov@48: start_end[0] = start_end[1] - limit; tikhomirov@48: } else { tikhomirov@48: start_end[1] = limit; // adjust right boundary tikhomirov@48: } tikhomirov@48: } tikhomirov@48: int rv = start_end[1] - start_end[0]; tikhomirov@48: start_end[1]--; // range needs index, not length tikhomirov@48: return rv; tikhomirov@48: } tikhomirov@47: tikhomirov@131: private static final class Dump implements HgLogCommand.FileHistoryHandler { tikhomirov@47: // params tikhomirov@60: boolean complete = false; // roughly --debug tikhomirov@47: boolean reverseOrder = false; tikhomirov@60: boolean verbose = true; // roughly -v tikhomirov@47: // own tikhomirov@47: private LinkedList l = new LinkedList(); tikhomirov@47: private final HgRepository repo; tikhomirov@98: private HgChangelog.ParentWalker changelogWalker; tikhomirov@60: private final int tip ; tikhomirov@47: tikhomirov@47: public Dump(HgRepository hgRepo) { tikhomirov@49: repo = hgRepo; tikhomirov@49: tip = hgRepo.getChangelog().getRevisionCount() - 1; tikhomirov@47: } tikhomirov@80: tikhomirov@80: public void copy(FileRevision from, FileRevision to) { tikhomirov@80: System.out.printf("Got notified that %s(%s) was originally known as %s(%s)\n", to.getPath(), to.getRevision(), from.getPath(), from.getRevision()); tikhomirov@80: } tikhomirov@47: tikhomirov@129: public void next(HgChangeset changeset) { tikhomirov@65: final String s = print(changeset); tikhomirov@47: if (reverseOrder) { tikhomirov@80: // XXX in fact, need to insert s into l according to changeset.getRevision() tikhomirov@80: // because when file history is being followed, revisions of the original file (with smaller revNumber) tikhomirov@80: // are reported *after* revisions of present file and with addFirst appear above them tikhomirov@47: l.addFirst(s); tikhomirov@47: } else { tikhomirov@47: System.out.print(s); tikhomirov@47: } tikhomirov@47: } tikhomirov@47: tikhomirov@47: public void complete() { tikhomirov@47: if (!reverseOrder) { tikhomirov@47: return; tikhomirov@47: } tikhomirov@47: for (String s : l) { tikhomirov@47: System.out.print(s); tikhomirov@47: } tikhomirov@47: l.clear(); tikhomirov@49: changelogWalker = null; tikhomirov@47: } tikhomirov@47: tikhomirov@129: private String print(HgChangeset cset) { tikhomirov@47: StringBuilder sb = new StringBuilder(); tikhomirov@47: Formatter f = new Formatter(sb); tikhomirov@65: final Nodeid csetNodeid = cset.getNodeid(); tikhomirov@65: f.format("changeset: %d:%s\n", cset.getRevision(), complete ? csetNodeid : csetNodeid.shortNotation()); tikhomirov@65: if (cset.getRevision() == tip || repo.getTags().isTagged(csetNodeid)) { tikhomirov@50: tikhomirov@50: sb.append("tag: "); tikhomirov@50: for (String t : repo.getTags().tags(csetNodeid)) { tikhomirov@50: sb.append(t); tikhomirov@50: sb.append(' '); tikhomirov@50: } tikhomirov@65: if (cset.getRevision() == tip) { tikhomirov@50: sb.append("tip"); tikhomirov@50: } tikhomirov@50: sb.append('\n'); tikhomirov@49: } tikhomirov@47: if (complete) { tikhomirov@124: // if (changelogWalker == null) { tikhomirov@124: // changelogWalker = repo.getChangelog().new ParentWalker(); tikhomirov@124: // changelogWalker.init(); tikhomirov@124: // } tikhomirov@124: // Nodeid p1 = changelogWalker.safeFirstParent(csetNodeid); tikhomirov@124: // Nodeid p2 = changelogWalker.safeSecondParent(csetNodeid); tikhomirov@124: Nodeid p1 = cset.getFirstParentRevision(); tikhomirov@124: Nodeid p2 = cset.getSecondParentRevision(); tikhomirov@88: int p1x = p1 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevision(p1); tikhomirov@88: int p2x = p2 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevision(p2); tikhomirov@88: int mx = repo.getManifest().getLocalRevision(cset.getManifestRevision()); tikhomirov@65: f.format("parent: %d:%s\nparent: %d:%s\nmanifest: %d:%s\n", p1x, p1, p2x, p2, mx, cset.getManifestRevision()); tikhomirov@47: } tikhomirov@65: f.format("user: %s\ndate: %s\n", cset.getUser(), cset.getDate()); tikhomirov@60: if (!complete && verbose) { tikhomirov@65: final List files = cset.getAffectedFiles(); tikhomirov@48: sb.append("files: "); tikhomirov@65: for (Path s : files) { tikhomirov@47: sb.append(' '); tikhomirov@47: sb.append(s); tikhomirov@47: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@60: if (complete) { tikhomirov@65: if (!cset.getModifiedFiles().isEmpty()) { tikhomirov@60: sb.append("files: "); tikhomirov@65: for (FileRevision s : cset.getModifiedFiles()) { tikhomirov@60: sb.append(' '); tikhomirov@65: sb.append(s.getPath()); tikhomirov@60: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@65: if (!cset.getAddedFiles().isEmpty()) { tikhomirov@60: sb.append("files+: "); tikhomirov@65: for (FileRevision s : cset.getAddedFiles()) { tikhomirov@65: sb.append(' '); tikhomirov@65: sb.append(s.getPath()); tikhomirov@65: } tikhomirov@65: sb.append('\n'); tikhomirov@65: } tikhomirov@65: if (!cset.getRemovedFiles().isEmpty()) { tikhomirov@65: sb.append("files-: "); tikhomirov@65: for (Path s : cset.getRemovedFiles()) { tikhomirov@60: sb.append(' '); tikhomirov@60: sb.append(s); tikhomirov@60: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@65: // if (cset.extras() != null) { tikhomirov@65: // sb.append("extra: "); tikhomirov@65: // for (Map.Entry e : cset.extras().entrySet()) { tikhomirov@65: // sb.append(' '); tikhomirov@65: // sb.append(e.getKey()); tikhomirov@65: // sb.append('='); tikhomirov@65: // sb.append(e.getValue()); tikhomirov@65: // } tikhomirov@65: // sb.append('\n'); tikhomirov@65: // } tikhomirov@60: } tikhomirov@60: if (complete || verbose) { tikhomirov@65: f.format("description:\n%s\n\n", cset.getComment()); tikhomirov@47: } else { tikhomirov@65: f.format("summary: %s\n\n", cset.getComment()); tikhomirov@47: } tikhomirov@47: return sb.toString(); tikhomirov@47: } tikhomirov@47: } tikhomirov@1: }