blob: 1981ae50f9945ac6beed537f314022867457bf84 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.idea.blaze.base.vcs.git;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.async.process.ExternalTask;
import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.sync.workspace.WorkingSet;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Vcs diff provider for git.
*/
public class GitDiffProvider {
private static final Logger LOG = Logger.getInstance(GitDiffProvider.class);
/**
* Finds all changes between HEAD and the git commit specified by
* the provided SHA.<br>
* Returns null if an error occurred.
*/
@Nullable
public static WorkingSet calculateDiff(
WorkspaceRoot workspaceRoot,
String upstreamSha) {
String gitRoot = getConsoleOutput(workspaceRoot, "git", "rev-parse", "--show-toplevel");
if (gitRoot == null) {
return null;
}
GitStatusLineProcessor processor = new GitStatusLineProcessor(workspaceRoot, gitRoot);
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
// Do a git diff to find all modified files we know about
int retVal = ExternalTask.builder(workspaceRoot, ImmutableList.of("git", "diff", "--name-status", "--no-renames", upstreamSha))
.stdout(LineProcessingOutputStream.of(processor))
.stderr(stderr)
.build()
.run();
if (retVal != 0) {
LOG.error(stderr);
return null;
}
// Finally list all untracked files, as they're not caught by the git diff step above
String untrackedFilesOutput = getConsoleOutput(workspaceRoot, "git", "ls-files", "--others", "--exclude-standard");
if (untrackedFilesOutput == null) {
return null;
}
List<WorkspacePath> untrackedFiles = Arrays.asList(untrackedFilesOutput.split("\n"))
.stream()
.filter(s -> !Strings.isNullOrEmpty(s))
.filter(WorkspacePath::validate)
.map(WorkspacePath::new)
.collect(Collectors.toList());
return new WorkingSet(
ImmutableList.<WorkspacePath>builder().addAll(processor.addedFiles).addAll(untrackedFiles).build(),
ImmutableList.copyOf(processor.modifiedFiles),
ImmutableList.copyOf(processor.deletedFiles)
);
}
/**
* @return the console output, in string form, or null if there was a non-zero exit code.
*/
@Nullable
private static String getConsoleOutput(WorkspaceRoot workspaceRoot, String... commands) {
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
int retVal = ExternalTask.builder(workspaceRoot, ImmutableList.copyOf(commands))
.stdout(stdout)
.stderr(stderr)
.build()
.run();
if (retVal != 0) {
LOG.error(stderr);
return null;
}
return StringUtil.trimEnd(stdout.toString(), "\n");
}
}