/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
*
* 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.domain.materials.mercurial;
import com.thoughtworks.go.domain.materials.Modification;
import com.thoughtworks.go.domain.materials.Revision;
import com.thoughtworks.go.domain.materials.SCMCommand;
import com.thoughtworks.go.util.command.*;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import static com.thoughtworks.go.util.ExceptionUtils.bomb;
import static com.thoughtworks.go.util.ExceptionUtils.bombUnless;
import static com.thoughtworks.go.util.command.CommandLine.createCommandLine;
import static com.thoughtworks.go.util.command.ProcessOutputStreamConsumer.inMemoryConsumer;
import static java.lang.String.format;
public class HgCommand extends SCMCommand {
private static final Logger LOGGER = Logger.getLogger(HgCommand.class);
private final File workingDir;
private static String templatePath;
private final String branch;
private final String url;
private final List<SecretString> secrets;
public HgCommand(String materialFingerprint, File workingDir, String branch, String url, List<SecretString> secrets) {
super(materialFingerprint);
this.workingDir = workingDir;
this.branch = branch;
this.url = url;
this.secrets = secrets != null ? secrets : new ArrayList<>();
}
private boolean pull(ConsoleOutputStreamConsumer outputStreamConsumer) {
CommandLine hg = hg("pull", "-b", branch, "--config", String.format("paths.default=%s", url));
return execute(hg, outputStreamConsumer) == 0;
}
public String version() {
CommandLine hg = createCommandLine("hg").withArgs("version");
return execute(hg, "hg version check").outputAsString();
}
public int clone(ConsoleOutputStreamConsumer outputStreamConsumer, UrlArgument repositoryUrl) {
CommandLine hg = createCommandLine("hg").withArgs("clone").withArg("-b").withArg(branch).withArg(repositoryUrl)
.withArg(workingDir.getAbsolutePath()).withNonArgSecrets(secrets);
return execute(hg, outputStreamConsumer);
}
public void checkConnection(UrlArgument repositoryURL) {
execute(createCommandLine("hg").withArgs("id", "--id").withArg(repositoryURL).withNonArgSecrets(secrets), repositoryURL.forDisplay());
}
public void updateTo(Revision revision, ConsoleOutputStreamConsumer outputStreamConsumer) {
if (!pull(outputStreamConsumer) || !update(revision, outputStreamConsumer)) {
bomb(format("Unable to update to revision [%s]", revision));
}
}
private boolean update(Revision revision, ConsoleOutputStreamConsumer outputStreamConsumer) {
CommandLine hg = hg("update", "--clean", "-r", revision.getRevision());
return execute(hg, outputStreamConsumer) == 0;
}
public void add(ConsoleOutputStreamConsumer outputStreamConsumer, File file) {
CommandLine hg = hg("add", file.getAbsolutePath());
execute(hg, outputStreamConsumer);
}
public void commit(ConsoleOutputStreamConsumer consumer, String comment, String username) {
CommandLine hg = hg("commit", "-m", comment, "-u", username);
execute(hg, consumer);
}
public void push(ConsoleOutputStreamConsumer consumer) {
CommandLine hg = hg("push");
execute(hg, consumer);
}
public List<Modification> latestOneModificationAsModifications() {
return findRecentModifications(1);
}
private String templatePath() {
if (templatePath == null) {
String file = HgCommand.class.getResource("/hg.template").getFile();
try {
templatePath = URLDecoder.decode(new File(file).getAbsolutePath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
templatePath = URLDecoder.decode(new File(file).getAbsolutePath());
}
}
return templatePath;
}
List<Modification> findRecentModifications(int count) {
// Currently impossible to check modifications on a remote repository.
InMemoryStreamConsumer consumer = inMemoryConsumer();
bombUnless(pull(consumer), "Failed to run hg pull command: " + consumer.getAllOutput());
CommandLine hg = hg("log", "--limit", String.valueOf(count), "-b", branch, "--style", templatePath());
return new HgModificationSplitter(execute(hg)).modifications();
}
public List<Modification> modificationsSince(Revision revision) {
InMemoryStreamConsumer consumer = inMemoryConsumer();
bombUnless(pull(consumer), "Failed to run hg pull command: " + consumer.getAllOutput());
CommandLine hg = hg("log",
"-r", "tip:" + revision.getRevision(),
"-b", branch,
"--style", templatePath());
return new HgModificationSplitter(execute(hg)).filterOutRevision(revision);
}
public ConsoleResult workingRepositoryUrl() {
CommandLine hg = hg("showconfig", "paths.default");
final ConsoleResult result = execute(hg);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Current repository url of [" + workingDir + "]: " + result.outputForDisplayAsString());
LOGGER.trace("Target repository url: " + url);
}
return result;
}
private CommandLine hg(String... arguments) {
return createCommandLine("hg").withArgs(arguments).withNonArgSecrets(secrets).withWorkingDir(workingDir);
}
private static ConsoleResult execute(CommandLine hgCmd, String processTag) {
return hgCmd.runOrBomb(processTag);
}
private ConsoleResult execute(CommandLine hgCmd) {
return runOrBomb(hgCmd);
}
private int execute(CommandLine hgCmd, ConsoleOutputStreamConsumer outputStreamConsumer) {
return run(hgCmd, outputStreamConsumer);
}
}