1 /*
2 * #%L
3 * JavaHg
4 * %%
5 * Copyright (C) 2011 aragost Trifork ag
6 * %%
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 * #L%
25 */
26 package com.aragost.javahg.commands;
27
28 import java.io.IOException;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.Map;
32
33 import com.aragost.javahg.Changeset;
34 import com.aragost.javahg.Repository;
35 import com.aragost.javahg.commands.flags.AnnotateCommandFlags;
36 import com.aragost.javahg.internals.HgInputStream;
37 import com.google.common.collect.Lists;
38 import com.google.common.collect.Maps;
39 import com.google.common.collect.Sets;
40
41 /**
42 * Command class for executing <tt>hg annotate</tt>. Set flags from
43 * {@link AnnotateCommandFlags} and see the {@link #execute} method
44 * for how to run the command.
45 */
46 public class AnnotateCommand extends AnnotateCommandFlags {
47
48 /**
49 * @param repository
50 * the repository associated with this command.
51 */
52 public AnnotateCommand(Repository repository) {
53 super(repository);
54 cmdAppend("--number");
55 }
56
57 /**
58 * Execute <tt>hg annotate</tt> for the specified file.
59 * <p>
60 * On the command line, Mercurial can annotate more than one file,
61 * JavaHg can only annotate one file for each call (but the
62 * overhead is negligible to make multiple calls).
63 *
64 * @param file
65 * @return list of annotated lines.
66 * @throws IOException
67 */
68 public List<AnnotateLine> execute(String file) throws IOException {
69 Repository repo = getRepository();
70 List<Integer> revisions = Lists.newArrayList();
71 List<String> lines = Lists.newArrayList();
72 HgInputStream stream = launchStream(file);
73 while (stream.peek() != -1) {
74 revisions.add(stream.revisionUpTo(':'));
75 stream.skip(1);
76 lines.add(stream.textUpTo('\n'));
77 }
78 Map<Integer, Changeset> revNumMap = createRevNumMap(repo, revisions);
79 int size = lines.size();
80 List<AnnotateLine> result = Lists.newArrayListWithCapacity(size);
81 for (int i = 0 ; i < size; i ++) {
82 Changeset changeset = revNumMap.get(revisions.get(i));
83 result.add(new AnnotateLine(changeset, lines.get(i)));
84 }
85 return result;
86 }
87
88 /**
89 * Create a map mapping revision numbers to Changesets
90 *
91 * @param repo
92 * @param revisions
93 * @return
94 */
95 private Map<Integer, Changeset> createRevNumMap(Repository repo, List<Integer> revisions) {
96 Collection<Integer> uniqRevs = Sets.newHashSet(revisions);
97 String[] revs = new String[uniqRevs.size()];
98 int index = 0;
99 for (Integer rev : uniqRevs) {
100 revs[index++] = String.valueOf(rev);
101 }
102 LogCommand logCmd = LogCommand.on(repo).rev(revs);
103 Map<Integer, Changeset> revNumMap = Maps.newHashMap();
104 for (Changeset cs : logCmd.execute()) {
105 revNumMap.put(cs.getRevision(), cs);
106 }
107 return revNumMap;
108 }
109
110 }