Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgDiffCommand.java @ 629:5f52074707b2
Diff/blame methods as command, their residence in HgDataFile was a mistake
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 22 May 2013 16:46:15 +0200 |
parents | |
children | 72c979555cb8 |
comparison
equal
deleted
inserted
replaced
628:6526d8adbc0f | 629:5f52074707b2 |
---|---|
1 /* | |
2 * Copyright (c) 2013 TMate Software Ltd | |
3 * | |
4 * This program is free software; you can redistribute it and/or modify | |
5 * it under the terms of the GNU General Public License as published by | |
6 * the Free Software Foundation; version 2 of the License. | |
7 * | |
8 * This program is distributed in the hope that it will be useful, | |
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 * GNU General Public License for more details. | |
12 * | |
13 * For information on how to redistribute this software under | |
14 * the terms of a license other than GNU General Public License | |
15 * contact TMate Software at support@hg4j.com | |
16 */ | |
17 package org.tmatesoft.hg.core; | |
18 | |
19 import static org.tmatesoft.hg.repo.HgInternals.wrongRevisionIndex; | |
20 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; | |
21 import static org.tmatesoft.hg.repo.HgRepository.TIP; | |
22 | |
23 import org.tmatesoft.hg.internal.BlameHelper; | |
24 import org.tmatesoft.hg.internal.Experimental; | |
25 import org.tmatesoft.hg.internal.FileHistory; | |
26 import org.tmatesoft.hg.internal.FileRevisionHistoryChunk; | |
27 import org.tmatesoft.hg.repo.HgDataFile; | |
28 import org.tmatesoft.hg.repo.HgInternals; | |
29 import org.tmatesoft.hg.repo.HgRepository; | |
30 import org.tmatesoft.hg.repo.HgRuntimeException; | |
31 import org.tmatesoft.hg.util.CancelledException; | |
32 import org.tmatesoft.hg.util.Path; | |
33 | |
34 /** | |
35 * 'hg diff' counterpart, with similar, diff-based, functionality | |
36 * | |
37 * @since 1.1 | |
38 * @author Artem Tikhomirov | |
39 * @author TMate Software Ltd. | |
40 */ | |
41 @Experimental(reason="#execute* methods might get renamed") | |
42 public class HgDiffCommand extends HgAbstractCommand<HgDiffCommand> { | |
43 | |
44 private final HgRepository repo; | |
45 private HgDataFile df; | |
46 private int clogRevIndexStart, clogRevIndexEnd; | |
47 private int clogRevIndexToParents; | |
48 private HgIterateDirection iterateDirection = HgIterateDirection.NewToOld; | |
49 | |
50 public HgDiffCommand(HgRepository hgRepo) { | |
51 repo = hgRepo; | |
52 } | |
53 | |
54 public HgDiffCommand file(Path file) { | |
55 df = repo.getFileNode(file); | |
56 return this; | |
57 } | |
58 | |
59 public HgDiffCommand file(HgDataFile file) { | |
60 df = file; | |
61 return this; | |
62 } | |
63 | |
64 public HgDiffCommand range(int changelogRevIndexStart, int changelogRevIndexEnd) { | |
65 clogRevIndexStart = changelogRevIndexStart; | |
66 clogRevIndexEnd = changelogRevIndexEnd; | |
67 return this; | |
68 } | |
69 | |
70 // FIXME javadoc when needed and difference with range | |
71 public HgDiffCommand changeset(int changelogRevIndex) { | |
72 clogRevIndexToParents = changelogRevIndex; | |
73 return this; | |
74 } | |
75 | |
76 // FIXME javadoc when needed | |
77 public HgDiffCommand order(HgIterateDirection order) { | |
78 iterateDirection = order; | |
79 return this; | |
80 } | |
81 | |
82 // FIXME progress and cancellation | |
83 | |
84 /** | |
85 * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' | |
86 */ | |
87 public void executeDiff(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | |
88 try { | |
89 int fileRevIndex1 = fileRevIndex(df, clogRevIndexStart); | |
90 int fileRevIndex2 = fileRevIndex(df, clogRevIndexEnd); | |
91 BlameHelper bh = new BlameHelper(insp); | |
92 bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); | |
93 bh.diff(fileRevIndex1, clogRevIndexStart, fileRevIndex2, clogRevIndexEnd); | |
94 } catch (HgRuntimeException ex) { | |
95 throw new HgLibraryFailureException(ex); | |
96 } | |
97 } | |
98 | |
99 /** | |
100 * Walk file history range and report changes (diff) for each revision | |
101 */ | |
102 public void executeAnnotate(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | |
103 if (wrongRevisionIndex(clogRevIndexStart) || wrongRevisionIndex(clogRevIndexEnd)) { | |
104 throw new IllegalArgumentException(); | |
105 } | |
106 // FIXME check file and range are set | |
107 try { | |
108 // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants | |
109 // | |
110 int lastRevision = repo.getChangelog().getLastRevision(); | |
111 if (clogRevIndexEnd == TIP) { | |
112 clogRevIndexEnd = lastRevision; | |
113 } | |
114 HgInternals.checkRevlogRange(clogRevIndexStart, clogRevIndexEnd, lastRevision); | |
115 if (!df.exists()) { | |
116 return; | |
117 } | |
118 BlameHelper bh = new BlameHelper(insp); | |
119 FileHistory fileHistory = bh.prepare(df, clogRevIndexStart, clogRevIndexEnd); | |
120 | |
121 int[] fileClogParentRevs = new int[2]; | |
122 int[] fileParentRevs = new int[2]; | |
123 for (FileRevisionHistoryChunk fhc : fileHistory.iterate(iterateDirection)) { | |
124 for (int fri : fhc.fileRevisions(iterateDirection)) { | |
125 int clogRevIndex = fhc.changeset(fri); | |
126 // the way we built fileHistory ensures we won't walk past [changelogRevIndexStart..changelogRevIndexEnd] | |
127 assert clogRevIndex >= clogRevIndexStart; | |
128 assert clogRevIndex <= clogRevIndexEnd; | |
129 fhc.fillFileParents(fri, fileParentRevs); | |
130 fhc.fillCsetParents(fri, fileClogParentRevs); | |
131 bh.annotateChange(fri, clogRevIndex, fileParentRevs, fileClogParentRevs); | |
132 } | |
133 } | |
134 } catch (HgRuntimeException ex) { | |
135 throw new HgLibraryFailureException(ex); | |
136 } | |
137 } | |
138 | |
139 /** | |
140 * Annotates changes of the file against its parent(s). | |
141 * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't | |
142 * walk file history, looks at the specified revision only. Handles both parents (if merge revision). | |
143 */ | |
144 public void executeAnnotateSingleRevision(HgBlameInspector insp) throws HgCallbackTargetException, CancelledException, HgException { | |
145 try { | |
146 int changelogRevisionIndex = clogRevIndexToParents; | |
147 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f | |
148 int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); | |
149 int[] fileRevParents = new int[2]; | |
150 df.parents(fileRevIndex, fileRevParents, null, null); | |
151 if (changelogRevisionIndex == TIP) { | |
152 changelogRevisionIndex = df.getChangesetRevisionIndex(fileRevIndex); | |
153 } | |
154 int[] fileClogParentRevs = new int[2]; | |
155 fileClogParentRevs[0] = fileRevParents[0] == NO_REVISION ? NO_REVISION : df.getChangesetRevisionIndex(fileRevParents[0]); | |
156 fileClogParentRevs[1] = fileRevParents[1] == NO_REVISION ? NO_REVISION : df.getChangesetRevisionIndex(fileRevParents[1]); | |
157 BlameHelper bh = new BlameHelper(insp); | |
158 int clogIndexStart = fileClogParentRevs[0] == NO_REVISION ? (fileClogParentRevs[1] == NO_REVISION ? 0 : fileClogParentRevs[1]) : fileClogParentRevs[0]; | |
159 bh.prepare(df, clogIndexStart, changelogRevisionIndex); | |
160 bh.annotateChange(fileRevIndex, changelogRevisionIndex, fileRevParents, fileClogParentRevs); | |
161 } catch (HgRuntimeException ex) { | |
162 throw new HgLibraryFailureException(ex); | |
163 } | |
164 } | |
165 | |
166 | |
167 private static int fileRevIndex(HgDataFile df, int csetRevIndex) throws HgRuntimeException { | |
168 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); | |
169 return df.getRevisionIndex(fileRev); | |
170 } | |
171 } |