1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.eclipse.jgit.pgm;
47
48 import java.io.BufferedOutputStream;
49 import java.io.IOException;
50 import java.text.DateFormat;
51 import java.text.MessageFormat;
52 import java.text.SimpleDateFormat;
53 import java.util.Locale;
54 import java.util.TimeZone;
55
56 import org.eclipse.jgit.diff.DiffFormatter;
57 import org.eclipse.jgit.diff.RawTextComparator;
58 import org.eclipse.jgit.diff.RenameDetector;
59 import org.eclipse.jgit.errors.CorruptObjectException;
60 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
61 import org.eclipse.jgit.errors.MissingObjectException;
62 import org.eclipse.jgit.lib.Constants;
63 import org.eclipse.jgit.lib.FileMode;
64 import org.eclipse.jgit.lib.ObjectId;
65 import org.eclipse.jgit.lib.PersonIdent;
66 import org.eclipse.jgit.lib.Repository;
67 import org.eclipse.jgit.pgm.internal.CLIText;
68 import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
69 import org.eclipse.jgit.revwalk.RevCommit;
70 import org.eclipse.jgit.revwalk.RevObject;
71 import org.eclipse.jgit.revwalk.RevTag;
72 import org.eclipse.jgit.revwalk.RevTree;
73 import org.eclipse.jgit.revwalk.RevWalk;
74 import org.eclipse.jgit.treewalk.TreeWalk;
75 import org.eclipse.jgit.treewalk.filter.TreeFilter;
76 import org.kohsuke.args4j.Argument;
77 import org.kohsuke.args4j.Option;
78
79 @Command(common = true, usage = "usage_show")
80 class Show extends TextBuiltin {
81 private final TimeZone myTZ = TimeZone.getDefault();
82
83 private final DateFormat fmt;
84
85 private DiffFormatter diffFmt;
86
87 @Argument(index = 0, metaVar = "metaVar_object")
88 private String objectName;
89
90 @Option(name = "--", metaVar = "metaVar_path", handler = PathTreeFilterHandler.class)
91 protected TreeFilter pathFilter = TreeFilter.ALL;
92
93
94 @Option(name = "-p", usage = "usage_showPatch")
95 boolean showPatch;
96
97 @Option(name = "-M", usage = "usage_detectRenames")
98 private Boolean detectRenames;
99
100 @Option(name = "--no-renames", usage = "usage_noRenames")
101 void noRenames(@SuppressWarnings("unused") boolean on) {
102 detectRenames = Boolean.FALSE;
103 }
104
105 @Option(name = "-l", usage = "usage_renameLimit")
106 private Integer renameLimit;
107
108 @Option(name = "--name-status", usage = "usage_nameStatus")
109 private boolean showNameAndStatusOnly;
110
111 @Option(name = "--ignore-space-at-eol")
112 void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) {
113 diffFmt.setDiffComparator(RawTextComparator.WS_IGNORE_TRAILING);
114 }
115
116 @Option(name = "--ignore-leading-space")
117 void ignoreLeadingSpace(@SuppressWarnings("unused") boolean on) {
118 diffFmt.setDiffComparator(RawTextComparator.WS_IGNORE_LEADING);
119 }
120
121 @Option(name = "-b", aliases = { "--ignore-space-change" })
122 void ignoreSpaceChange(@SuppressWarnings("unused") boolean on) {
123 diffFmt.setDiffComparator(RawTextComparator.WS_IGNORE_CHANGE);
124 }
125
126 @Option(name = "-w", aliases = { "--ignore-all-space" })
127 void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
128 diffFmt.setDiffComparator(RawTextComparator.WS_IGNORE_ALL);
129 }
130
131 @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext")
132 void unified(int lines) {
133 diffFmt.setContext(lines);
134 }
135
136 @Option(name = "--abbrev", metaVar = "metaVar_n")
137 void abbrev(int lines) {
138 diffFmt.setAbbreviationLength(lines);
139 }
140
141 @Option(name = "--full-index")
142 void abbrev(@SuppressWarnings("unused") boolean on) {
143 diffFmt.setAbbreviationLength(Constants.OBJECT_ID_STRING_LENGTH);
144 }
145
146 @Option(name = "--src-prefix", usage = "usage_srcPrefix")
147 void sourcePrefix(String path) {
148 diffFmt.setOldPrefix(path);
149 }
150
151 @Option(name = "--dst-prefix", usage = "usage_dstPrefix")
152 void dstPrefix(String path) {
153 diffFmt.setNewPrefix(path);
154 }
155
156 @Option(name = "--no-prefix", usage = "usage_noPrefix")
157 void noPrefix(@SuppressWarnings("unused") boolean on) {
158 diffFmt.setOldPrefix("");
159 diffFmt.setNewPrefix("");
160 }
161
162
163
164 Show() {
165 fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US);
166 }
167
168
169 @Override
170 protected void init(Repository repository, String gitDir) {
171 super.init(repository, gitDir);
172 diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
173 }
174
175
176 @SuppressWarnings("boxing")
177 @Override
178 protected void run() throws Exception {
179 diffFmt.setRepository(db);
180 try {
181 diffFmt.setPathFilter(pathFilter);
182 if (detectRenames != null)
183 diffFmt.setDetectRenames(detectRenames.booleanValue());
184 if (renameLimit != null && diffFmt.isDetectRenames()) {
185 RenameDetector rd = diffFmt.getRenameDetector();
186 rd.setRenameLimit(renameLimit.intValue());
187 }
188
189 ObjectId objectId;
190 if (objectName == null)
191 objectId = db.resolve(Constants.HEAD);
192 else
193 objectId = db.resolve(objectName);
194
195 try (RevWalk rw = new RevWalk(db)) {
196 RevObject obj = rw.parseAny(objectId);
197 while (obj instanceof RevTag) {
198 show((RevTag) obj);
199 obj = ((RevTag) obj).getObject();
200 rw.parseBody(obj);
201 }
202
203 switch (obj.getType()) {
204 case Constants.OBJ_COMMIT:
205 show(rw, (RevCommit) obj);
206 break;
207
208 case Constants.OBJ_TREE:
209 outw.print("tree ");
210 outw.print(objectName);
211 outw.println();
212 outw.println();
213 show((RevTree) obj);
214 break;
215
216 case Constants.OBJ_BLOB:
217 db.open(obj, obj.getType()).copyTo(System.out);
218 outw.flush();
219 break;
220
221 default:
222 throw die(MessageFormat.format(
223 CLIText.get().cannotReadBecause, obj.name(),
224 obj.getType()));
225 }
226 }
227 } finally {
228 diffFmt.close();
229 }
230 }
231
232 private void show(RevTag tag) throws IOException {
233 outw.print(CLIText.get().tagLabel);
234 outw.print(" ");
235 outw.print(tag.getTagName());
236 outw.println();
237
238 final PersonIdent tagger = tag.getTaggerIdent();
239 if (tagger != null) {
240 outw.println(MessageFormat.format(CLIText.get().taggerInfo,
241 tagger.getName(), tagger.getEmailAddress()));
242
243 final TimeZone taggerTZ = tagger.getTimeZone();
244 fmt.setTimeZone(taggerTZ != null ? taggerTZ : myTZ);
245 outw.println(MessageFormat.format(CLIText.get().dateInfo,
246 fmt.format(tagger.getWhen())));
247 }
248
249 outw.println();
250 final String[] lines = tag.getFullMessage().split("\n");
251 for (String s : lines) {
252 outw.print(" ");
253 outw.print(s);
254 outw.println();
255 }
256
257 outw.println();
258 }
259
260 private void show(RevTree obj) throws MissingObjectException,
261 IncorrectObjectTypeException, CorruptObjectException, IOException {
262 try (TreeWalk walk = new TreeWalk(db)) {
263 walk.reset();
264 walk.addTree(obj);
265
266 while (walk.next()) {
267 outw.print(walk.getPathString());
268 final FileMode mode = walk.getFileMode(0);
269 if (mode == FileMode.TREE)
270 outw.print("/");
271 outw.println();
272 }
273 }
274 }
275
276 private void show(RevWalk rw, RevCommit c) throws Exception {
277 char[] outbuffer = new char[Constants.OBJECT_ID_LENGTH * 2];
278
279 outw.print(CLIText.get().commitLabel);
280 outw.print(" ");
281 c.getId().copyTo(outbuffer, outw);
282 outw.println();
283
284 final PersonIdent author = c.getAuthorIdent();
285 outw.println(MessageFormat.format(CLIText.get().authorInfo,
286 author.getName(), author.getEmailAddress()));
287
288 final TimeZone authorTZ = author.getTimeZone();
289 fmt.setTimeZone(authorTZ != null ? authorTZ : myTZ);
290 outw.println(MessageFormat.format(CLIText.get().dateInfo,
291 fmt.format(author.getWhen())));
292
293 outw.println();
294 final String[] lines = c.getFullMessage().split("\n");
295 for (String s : lines) {
296 outw.print(" ");
297 outw.print(s);
298 outw.println();
299 }
300
301 outw.println();
302 if (c.getParentCount() == 1) {
303 rw.parseHeaders(c.getParent(0));
304 showDiff(c);
305 }
306 outw.flush();
307 }
308
309 private void showDiff(RevCommit c) throws IOException {
310 final RevTree a = c.getParent(0).getTree();
311 final RevTree b = c.getTree();
312
313 if (showNameAndStatusOnly)
314 Diff.nameStatus(outw, diffFmt.scan(a, b));
315 else {
316 outw.flush();
317 diffFmt.format(a, b);
318 diffFmt.flush();
319 }
320 outw.println();
321 }
322 }