IDEA-68731 Batch process files in hg status
[idea/community.git] / plugins / hg4idea / src / org / zmlx / hg4idea / command / HgStatusCommand.java
1 // Copyright 2008-2010 Victor Iacoban
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software distributed under
10 // the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11 // either express or implied. See the License for the specific language governing permissions and
12 // limitations under the License.
13 package org.zmlx.hg4idea.command;
14
15 import com.intellij.openapi.diagnostic.Logger;
16 import com.intellij.openapi.project.Project;
17 import com.intellij.openapi.vcs.FilePath;
18 import com.intellij.openapi.vfs.VirtualFile;
19 import com.intellij.vcsUtil.VcsFileUtil;
20 import org.apache.commons.lang.StringUtils;
21 import org.jetbrains.annotations.Nullable;
22 import org.zmlx.hg4idea.HgChange;
23 import org.zmlx.hg4idea.HgFile;
24 import org.zmlx.hg4idea.HgFileStatusEnum;
25 import org.zmlx.hg4idea.HgRevisionNumber;
26 import org.zmlx.hg4idea.execution.HgCommandExecutor;
27 import org.zmlx.hg4idea.execution.HgCommandResult;
28
29 import java.io.File;
30 import java.util.*;
31
32 public class HgStatusCommand {
33
34   private static final Logger LOG = Logger.getInstance(HgStatusCommand.class.getName());
35
36   private static final int ITEM_COUNT = 3;
37   private static final int STATUS_INDEX = 0;
38
39   private final Project project;
40
41   private boolean includeAdded = true;
42   private boolean includeModified = true;
43   private boolean includeRemoved = true;
44   private boolean includeDeleted = true;
45   private boolean includeUnknown = true;
46   private boolean includeIgnored = true;
47   private boolean includeCopySource = true;
48   private HgRevisionNumber baseRevision;
49   private HgRevisionNumber targetRevision;
50
51   public HgStatusCommand(Project project) {
52     this.project = project;
53   }
54
55   public void setIncludeAdded(boolean includeAdded) {
56     this.includeAdded = includeAdded;
57   }
58
59   public void setIncludeModified(boolean includeModified) {
60     this.includeModified = includeModified;
61   }
62
63   public void setIncludeRemoved(boolean includeRemoved) {
64     this.includeRemoved = includeRemoved;
65   }
66
67   public void setIncludeDeleted(boolean includeDeleted) {
68     this.includeDeleted = includeDeleted;
69   }
70
71   public void setIncludeUnknown(boolean includeUnknown) {
72     this.includeUnknown = includeUnknown;
73   }
74
75   public void setIncludeIgnored(boolean includeIgnored) {
76     this.includeIgnored = includeIgnored;
77   }
78
79   public void setIncludeCopySource(boolean includeCopySource) {
80     this.includeCopySource = includeCopySource;
81   }
82
83   public void setBaseRevision(HgRevisionNumber base) {
84     baseRevision = base;
85   }
86
87   public void setTargetRevision(HgRevisionNumber target) {
88     targetRevision = target;
89   }
90
91   public Set<HgChange> execute(VirtualFile repo) {
92     return execute(repo, null);
93   }
94
95   public Set<HgChange> execute(VirtualFile repo, @Nullable Collection<FilePath> paths) {
96     if (repo == null) {
97       return Collections.emptySet();
98     }
99
100     HgCommandExecutor executor = new HgCommandExecutor(project);
101     executor.setSilent(true);
102
103     List<String> options = new LinkedList<String>();
104     if (includeAdded) {
105       options.add("--added");
106     }
107     if (includeModified) {
108       options.add("--modified");
109     }
110     if (includeRemoved) {
111       options.add("--removed");
112     }
113     if (includeDeleted) {
114       options.add("--deleted");
115     }
116     if (includeUnknown) {
117       options.add("--unknown");
118     }
119     if (includeIgnored) {
120       options.add("--ignored");
121     }
122     if (includeCopySource) {
123       options.add("--copies");
124     }
125     if (baseRevision != null) {
126       options.add("--rev");
127       options.add(baseRevision.getChangeset());
128       if (targetRevision != null) {
129         options.add("--rev");
130         options.add(targetRevision.getChangeset());
131       }
132     }
133
134     final Set<HgChange> changes = new HashSet<HgChange>();
135
136     if (paths != null) {
137       final List<List<String>> chunked = VcsFileUtil.chunkPaths(repo, paths);
138       for (List<String> chunk : chunked) {
139         List<String> args = new ArrayList<String>();
140         args.addAll(options);
141         args.addAll(chunk);
142         HgCommandResult result = executor.executeInCurrentThread(repo, "status", args);
143         changes.addAll(parseChangesFromResult(repo, result));
144       }
145     } else {
146       HgCommandResult result = executor.executeInCurrentThread(repo, "status", options);
147       changes.addAll(parseChangesFromResult(repo, result));
148     }
149     return changes;
150   }
151
152   private static Collection<HgChange> parseChangesFromResult(VirtualFile repo, HgCommandResult result) {
153     final Set<HgChange> changes = new HashSet<HgChange>();
154     HgChange previous = null;
155     if (result == null) {
156       return changes;
157     }
158     for (String line : result.getOutputLines()) {
159       if (StringUtils.isBlank(line) || line.length() < ITEM_COUNT) {
160         LOG.warn("Unexpected line in status '" + line + '\'');
161         continue;
162       }
163       HgFileStatusEnum status = HgFileStatusEnum.valueOf(line.charAt(STATUS_INDEX));
164       File ioFile = new File(repo.getPath(), line.substring(2));
165       if (HgFileStatusEnum.COPY == status && previous != null
166         && previous.getStatus() == HgFileStatusEnum.ADDED) {
167         previous.setStatus(HgFileStatusEnum.COPY);
168         previous.setBeforeFile(new HgFile(repo, ioFile));
169         previous = null;
170       } else {
171         previous = new HgChange(new HgFile(repo, ioFile), status);
172         changes.add(previous);
173       }
174     }
175     return changes;
176   }
177 }