git4idea: rolling back change incompatible with cygwin git
[fedora-idea.git] / plugins / git4idea / src / git4idea / changes / ChangeCollector.java
blob4ff1a386c46b77c157d0dcba64d75ec3463753bf
1 /*
2 * Copyright 2000-2007 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package git4idea.changes;
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.vcs.FileStatus;
20 import com.intellij.openapi.vcs.VcsException;
21 import com.intellij.openapi.vcs.changes.Change;
22 import com.intellij.openapi.vcs.changes.ContentRevision;
23 import com.intellij.openapi.vfs.VirtualFile;
24 import git4idea.GitContentRevision;
25 import git4idea.GitRevisionNumber;
26 import git4idea.GitUtil;
27 import git4idea.commands.GitHandler;
28 import git4idea.commands.GitSimpleHandler;
30 import java.util.*;
32 /**
33 * A collector for changes in the Git. It is introduced because changes are not
34 * cannot be got as a sum of stateless operations.
36 class ChangeCollector {
37 /**
38 * a vcs root for changes
40 private final VirtualFile myVcsRoot;
41 /**
42 * a project for change collection
44 private final Project myProject;
45 /**
46 * Unversioned files
48 private final List<VirtualFile> myUnversioned = new ArrayList<VirtualFile>();
49 /**
50 * Names that are listed as unmerged
52 private final Set<String> myUnmergedNames = new HashSet<String>();
53 /**
54 * Names that are listed as unmerged
56 private final List<Change> myChanges = new ArrayList<Change>();
57 /**
58 * This flag indicates that collecting changes has been failed.
60 private boolean myIsFailed = true;
61 /**
62 * This flag indicates that collecting changes has been started
64 private boolean myIsCollected = false;
66 /**
67 * A constructor
69 * @param project a project
70 * @param vcsRoot a vcs root
72 public ChangeCollector(final Project project, final VirtualFile vcsRoot) {
73 myVcsRoot = vcsRoot;
74 myProject = project;
77 /**
78 * Get unversioned files
80 * @return an unversioned files
81 * @throws VcsException if there is a problem with executing Git
83 public Collection<VirtualFile> unversioned() throws VcsException {
84 ensureCollected();
85 return myUnversioned;
88 /**
89 * Get changes
91 * @return an unversioned files
92 * @throws VcsException if there is a problem with executing Git
94 public Collection<Change> changes() throws VcsException {
95 ensureCollected();
96 return myChanges;
101 * Ensure that changes has been collected.
103 * @throws VcsException an exception
105 private void ensureCollected() throws VcsException {
106 if (myIsCollected) {
107 if (myIsFailed) {
108 throw new IllegalStateException("The method should not be called after after exception has been thrown.");
110 else {
111 return;
114 myIsCollected = true;
115 collectUnmergedAndUnversioned();
116 collectDiffChanges();
117 myIsFailed = false;
121 * Collect diff with head
123 * @throws VcsException if there is a problem with running git
125 private void collectDiffChanges() throws VcsException {
126 GitSimpleHandler handler = new GitSimpleHandler(myProject, myVcsRoot, GitHandler.DIFF);
127 handler.addParameters("--name-status", "--diff-filter=ADCMRUX", "-M", "HEAD");
128 //handler.endOptions();
129 handler.setNoSSH(true);
130 handler.setSilent(true);
131 handler.setStdoutSuppressed(true);
132 handler.endOptions();
133 try {
134 String output = handler.run();
135 GitChangeUtils.parseChanges(myProject, myVcsRoot, null, GitChangeUtils.loadRevision(myProject, myVcsRoot, "HEAD"), output, myChanges,
136 myUnmergedNames);
138 catch (VcsException ex) {
139 if (!GitChangeUtils.isHeadMissing(ex)) {
140 throw ex;
142 handler = new GitSimpleHandler(myProject, myVcsRoot, GitHandler.LS_FILES);
143 handler.addParameters("--cached");
144 handler.setNoSSH(true);
145 handler.setSilent(true);
146 handler.setStdoutSuppressed(true);
147 // During init diff does not works because HEAD
148 // will appear only after the first commit.
149 // In that case added files are cached in index.
150 String output = handler.run();
151 if (output.length() > 0) {
152 StringTokenizer tokenizer = new StringTokenizer(output, "\n\r");
153 while (tokenizer.hasMoreTokens()) {
154 final String s = tokenizer.nextToken();
155 Change ch = new Change(null, GitContentRevision.createRevision(myVcsRoot, s, null, myProject, false), FileStatus.ADDED);
156 myChanges.add(ch);
163 * Collect unversioned and unmerged files
165 * @throws VcsException if there is a problem with running git
167 private void collectUnmergedAndUnversioned() throws VcsException {
168 // prepare handler
169 GitSimpleHandler handler = new GitSimpleHandler(myProject, myVcsRoot, GitHandler.LS_FILES);
170 handler.addParameters("-v", "--others", "--unmerged", "--exclude-standard");
171 handler.setSilent(true);
172 handler.setNoSSH(true);
173 handler.setStdoutSuppressed(true);
174 // run handler and collect changes
175 String list = handler.run();
176 for (String line : list.split("\n")) {
177 if (line.length() == 0) {
178 continue;
180 String[] tokens = line.split("[\t ]+");
181 String file = GitUtil.unescapePath(tokens[tokens.length - 1]);
182 if ("?".equals(tokens[0])) {
183 myUnversioned.add(myVcsRoot.findFileByRelativePath(file));
185 else { //noinspection HardCodedStringLiteral
186 if ("M".equals(tokens[0])) {
187 if (!myUnmergedNames.add(file)) {
188 continue;
190 // TODO handle conflict rename-modify
191 // TODO handle conflict copy-modify
192 // TODO handle conflict delete-modify
193 // TODO handle conflict rename-delete
194 // assume modify-modify conflict
195 ContentRevision before = GitContentRevision.createRevision(myVcsRoot, file, new GitRevisionNumber("orig_head"), myProject, false);
196 ContentRevision after = GitContentRevision.createRevision(myVcsRoot, file, null, myProject, false);
197 myChanges.add(new Change(before, after, FileStatus.MERGED_WITH_CONFLICTS));
199 else {
200 throw new VcsException("Unsupported type of the merge conflict detected: " + line);