tikhomirov@47: /* tikhomirov@47: * Copyright (c) 2010, 2011 Artem Tikhomirov tikhomirov@1: */ tikhomirov@1: package com.tmate.hgkit.console; tikhomirov@1: tikhomirov@47: import java.util.Formatter; tikhomirov@49: import java.util.LinkedHashSet; tikhomirov@47: import java.util.LinkedList; tikhomirov@47: import java.util.List; tikhomirov@49: import java.util.Map; tikhomirov@49: import java.util.Set; tikhomirov@47: tikhomirov@2: import com.tmate.hgkit.fs.RepositoryLookup; tikhomirov@2: import com.tmate.hgkit.ll.Changeset; tikhomirov@2: import com.tmate.hgkit.ll.HgDataFile; tikhomirov@1: import com.tmate.hgkit.ll.HgRepository; tikhomirov@47: import com.tmate.hgkit.ll.Nodeid; tikhomirov@49: import com.tmate.hgkit.ll.Revlog; tikhomirov@60: import com.tmate.hgkit.ll.StatusCollector; tikhomirov@1: tikhomirov@1: /** tikhomirov@1: * @author artem tikhomirov@1: */ tikhomirov@1: public class Log { tikhomirov@1: tikhomirov@1: public static void main(String[] args) throws Exception { tikhomirov@2: RepositoryLookup repoLookup = new RepositoryLookup(); tikhomirov@4: RepositoryLookup.Options cmdLineOpts = RepositoryLookup.Options.parse(args); tikhomirov@4: HgRepository hgRepo = repoLookup.detect(cmdLineOpts); 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@49: dump.branches = cmdLineOpts.branches; tikhomirov@49: if (cmdLineOpts.users != null) { tikhomirov@49: dump.users = new LinkedHashSet(); tikhomirov@49: for (String u : cmdLineOpts.users) { tikhomirov@49: dump.users.add(u.toLowerCase()); tikhomirov@49: } tikhomirov@49: } tikhomirov@6: if (cmdLineOpts.files.isEmpty()) { tikhomirov@48: if (cmdLineOpts.limit == -1) { tikhomirov@49: // no revisions and no limit tikhomirov@48: hgRepo.getChangelog().all(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@48: hgRepo.getChangelog().range(r[0], r[1], 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@48: if (cmdLineOpts.limit == -1) { tikhomirov@48: f1.history(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@48: f1.history(r[0], r[1], 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@49: // Differences with standard hg log output tikhomirov@49: // - complete == true (--debug) files are not broke down to modified,+ and - tikhomirov@47: private static final class Dump implements Changeset.Inspector { tikhomirov@47: // params tikhomirov@60: boolean complete = false; // roughly --debug tikhomirov@47: boolean reverseOrder = false; tikhomirov@49: Set branches; tikhomirov@49: Set users; // shall be lowercased tikhomirov@60: boolean verbose = true; // roughly -v tikhomirov@47: // own tikhomirov@47: private LinkedList l = new LinkedList(); tikhomirov@47: private final HgRepository repo; tikhomirov@49: private Revlog.ParentWalker changelogWalker; tikhomirov@60: private final int tip ; tikhomirov@60: private StatusCollector statusHelper; tikhomirov@47: tikhomirov@47: public Dump(HgRepository hgRepo) { tikhomirov@49: repo = hgRepo; tikhomirov@49: tip = hgRepo.getChangelog().getRevisionCount() - 1; tikhomirov@47: } tikhomirov@47: tikhomirov@47: public void next(int revisionNumber, Nodeid nodeid, Changeset cset) { tikhomirov@49: if (branches != null && !branches.contains(cset.branch())) { tikhomirov@49: return; tikhomirov@49: } tikhomirov@49: if (users != null) { tikhomirov@49: String csetUser = cset.user().toLowerCase(); tikhomirov@49: boolean found = false; tikhomirov@49: for (String u : users) { tikhomirov@49: if (csetUser.indexOf(u) != -1) { tikhomirov@49: found = true; tikhomirov@49: break; tikhomirov@49: } tikhomirov@49: } tikhomirov@49: if (!found) { tikhomirov@49: return; tikhomirov@49: } tikhomirov@49: } tikhomirov@47: final String s = print(revisionNumber, nodeid, cset); tikhomirov@47: if (reverseOrder) { 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@47: private String print(int revNumber, Nodeid csetNodeid, Changeset cset) { tikhomirov@47: StringBuilder sb = new StringBuilder(); tikhomirov@47: Formatter f = new Formatter(sb); tikhomirov@47: f.format("changeset: %d:%s\n", revNumber, complete ? csetNodeid : csetNodeid.shortNotation()); tikhomirov@50: if (revNumber == 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@50: if (revNumber == tip) { tikhomirov@50: sb.append("tip"); tikhomirov@50: } tikhomirov@50: sb.append('\n'); tikhomirov@49: } tikhomirov@47: if (complete) { tikhomirov@49: if (changelogWalker == null) { tikhomirov@49: changelogWalker = repo.getChangelog().new ParentWalker(); tikhomirov@49: changelogWalker.init(); tikhomirov@49: } tikhomirov@49: Nodeid p1 = changelogWalker.safeFirstParent(csetNodeid); tikhomirov@49: Nodeid p2 = changelogWalker.safeSecondParent(csetNodeid); tikhomirov@49: int p1x = p1 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevisionNumber(p1); tikhomirov@49: int p2x = p2 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevisionNumber(p2); tikhomirov@49: int mx = repo.getManifest().getLocalRevisionNumber(cset.manifest()); tikhomirov@49: f.format("parent: %d:%s\nparent: %d:%s\nmanifest: %d:%s\n", p1x, p1, p2x, p2, mx, cset.manifest()); tikhomirov@47: } tikhomirov@47: f.format("user: %s\ndate: %s\n", cset.user(), cset.dateString()); tikhomirov@60: if (!complete && verbose) { tikhomirov@47: final List files = cset.files(); tikhomirov@48: sb.append("files: "); tikhomirov@47: for (String 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@60: if (statusHelper == null) { tikhomirov@60: statusHelper = new StatusCollector(repo); tikhomirov@60: } tikhomirov@60: StatusCollector.Record r = new StatusCollector.Record(); tikhomirov@60: statusHelper.change(revNumber, r); tikhomirov@60: if (!r.getModified().isEmpty()) { tikhomirov@60: sb.append("files: "); tikhomirov@60: for (String s : r.getModified()) { tikhomirov@60: sb.append(' '); tikhomirov@60: sb.append(s); tikhomirov@60: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@60: if (!r.getAdded().isEmpty()) { tikhomirov@60: sb.append("files+: "); tikhomirov@60: for (String s : r.getAdded()) { tikhomirov@60: sb.append(' '); tikhomirov@60: sb.append(s); tikhomirov@60: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@60: if (!r.getRemoved().isEmpty()) { tikhomirov@60: sb.append("files-: "); tikhomirov@60: for (String s : r.getRemoved()) { tikhomirov@60: sb.append(' '); tikhomirov@60: sb.append(s); tikhomirov@60: } tikhomirov@60: sb.append('\n'); tikhomirov@60: } tikhomirov@49: if (cset.extras() != null) { tikhomirov@60: sb.append("extra: "); tikhomirov@49: for (Map.Entry e : cset.extras().entrySet()) { tikhomirov@49: sb.append(' '); tikhomirov@49: sb.append(e.getKey()); tikhomirov@49: sb.append('='); tikhomirov@49: sb.append(e.getValue()); tikhomirov@49: } tikhomirov@60: sb.append('\n'); tikhomirov@49: } tikhomirov@60: } tikhomirov@60: if (complete || verbose) { tikhomirov@60: f.format("description:\n%s\n\n", cset.comment()); tikhomirov@47: } else { tikhomirov@47: f.format("summary: %s\n\n", cset.comment()); tikhomirov@47: } tikhomirov@47: return sb.toString(); tikhomirov@47: } tikhomirov@47: } tikhomirov@1: }