Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgDataFile.java @ 603:707b5c7c6fa4
Refactor HgBlameFacility: relevant action methods moved to proper home (HgDataFile), as facility doesn't provide anything but packaging of relevant methods/interfaces
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 06 May 2013 18:29:57 +0200 |
parents | e3717fc7d26f |
children | e1b29756f901 |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java Mon May 06 17:11:29 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Mon May 06 18:29:57 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 TMate Software Ltd + * Copyright (c) 2010-2013 TMate Software Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ */ package org.tmatesoft.hg.repo; +import static org.tmatesoft.hg.core.HgIterateDirection.OldToNew; import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; import static org.tmatesoft.hg.repo.HgRepository.*; import static org.tmatesoft.hg.util.LogFacility.Severity.Info; @@ -28,14 +29,20 @@ import java.nio.channels.FileChannel; import java.util.Arrays; +import org.tmatesoft.hg.core.HgCallbackTargetException; import org.tmatesoft.hg.core.HgChangesetFileSneaker; +import org.tmatesoft.hg.core.HgIterateDirection; import org.tmatesoft.hg.core.Nodeid; +import org.tmatesoft.hg.internal.BlameHelper; import org.tmatesoft.hg.internal.DataAccess; +import org.tmatesoft.hg.internal.FileHistory; +import org.tmatesoft.hg.internal.FileRevisionHistoryChunk; import org.tmatesoft.hg.internal.FilterByteChannel; import org.tmatesoft.hg.internal.FilterDataAccess; import org.tmatesoft.hg.internal.Internals; import org.tmatesoft.hg.internal.Metadata; import org.tmatesoft.hg.internal.RevlogStream; +import org.tmatesoft.hg.repo.HgBlameInspector; import org.tmatesoft.hg.util.ByteChannel; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; @@ -428,6 +435,86 @@ return getRepo().getManifest().getFileFlags(changesetRevIndex, getPath()); } + /** + * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' + */ + public void diff(int clogRevIndex1, int clogRevIndex2, HgBlameInspector insp) throws HgCallbackTargetException { + // FIXME clogRevIndex1 and clogRevIndex2 may point to different files, need to decide whether to throw an exception + // or to attempt to look up correct file node (tricky) + int fileRevIndex1 = fileRevIndex(this, clogRevIndex1); + int fileRevIndex2 = fileRevIndex(this, clogRevIndex2); + BlameHelper bh = new BlameHelper(insp, 5); + bh.useFileUpTo(this, clogRevIndex2); + bh.diff(fileRevIndex1, clogRevIndex1, fileRevIndex2, clogRevIndex2); + } + + /** + * Walk file history up/down to revision at given changeset and report changes for each revision + */ + public void annotate(int changelogRevisionIndex, HgBlameInspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { + annotate(0, changelogRevisionIndex, insp, iterateOrder); + } + + /** + * Walk file history range and report changes for each revision + */ + public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, HgBlameInspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { + if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) { + throw new IllegalArgumentException(); + } + // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants + // + int lastRevision = getRepo().getChangelog().getLastRevision(); + if (changelogRevIndexEnd == TIP) { + changelogRevIndexEnd = lastRevision; + } + HgInternals.checkRevlogRange(changelogRevIndexStart, changelogRevIndexEnd, lastRevision); + if (!exists()) { + return; + } + FileHistory fileHistory = new FileHistory(this, changelogRevIndexStart, changelogRevIndexEnd); + fileHistory.build(); + BlameHelper bh = new BlameHelper(insp, 10); + for (FileRevisionHistoryChunk fhc : fileHistory.iterate(OldToNew)) { + // iteration order is not important here + bh.useFileUpTo(fhc.getFile(), fhc.getEndChangeset()); + } + int[] fileClogParentRevs = new int[2]; + int[] fileParentRevs = new int[2]; + for (FileRevisionHistoryChunk fhc : fileHistory.iterate(iterateOrder)) { + for (int fri : fhc.fileRevisions(iterateOrder)) { + int clogRevIndex = fhc.changeset(fri); + // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd] + assert clogRevIndex >= changelogRevIndexStart; + assert clogRevIndex <= changelogRevIndexEnd; + fhc.fillFileParents(fri, fileParentRevs); + fhc.fillCsetParents(fri, fileClogParentRevs); + bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs); + } + } + } + + /** + * Annotates changes of the file against its parent(s). + * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't + * walk file history, looks at the specified revision only. Handles both parents (if merge revision). + */ + public void annotateSingleRevision(int changelogRevisionIndex, HgBlameInspector insp) throws HgCallbackTargetException { + // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f + int fileRevIndex = fileRevIndex(this, changelogRevisionIndex); + int[] fileRevParents = new int[2]; + parents(fileRevIndex, fileRevParents, null, null); + if (changelogRevisionIndex == TIP) { + changelogRevisionIndex = getChangesetRevisionIndex(fileRevIndex); + } + BlameHelper bh = new BlameHelper(insp, 5); + bh.useFileUpTo(this, changelogRevisionIndex); + int[] fileClogParentRevs = new int[2]; + fileClogParentRevs[0] = fileRevParents[0] == NO_REVISION ? NO_REVISION : getChangesetRevisionIndex(fileRevParents[0]); + fileClogParentRevs[1] = fileRevParents[1] == NO_REVISION ? NO_REVISION : getChangesetRevisionIndex(fileRevParents[1]); + bh.annotateChange(fileRevIndex, changelogRevisionIndex, fileRevParents, fileClogParentRevs); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getSimpleName()); @@ -445,6 +532,13 @@ RevlogStream.Inspector insp = new MetadataInspector(metadata, null); super.content.iterate(localRev, localRev, true, insp); } + + + private static int fileRevIndex(HgDataFile df, int csetRevIndex) { + Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); + return df.getRevisionIndex(fileRev); + } + private static class MetadataInspector extends ErrorHandlingInspector implements RevlogStream.Inspector { private final Metadata metadata;