/* Copyright (c) 2012-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Johnathan Garrett (LMN Solutions) - initial implementation */ package org.locationtech.geogig.cli.porcelain; import java.io.File; import java.io.IOException; import java.util.List; import org.locationtech.geogig.api.GeoGIG; import org.locationtech.geogig.api.plumbing.ResolveGeogigDir; import org.locationtech.geogig.api.porcelain.CloneOp; import org.locationtech.geogig.api.porcelain.InitOp; import org.locationtech.geogig.cli.AbstractCommand; import org.locationtech.geogig.cli.CLICommand; import org.locationtech.geogig.cli.CommandFailedException; import org.locationtech.geogig.cli.GeogigCLI; import org.locationtech.geogig.cli.annotation.RemotesReadOnly; import org.locationtech.geogig.cli.annotation.RequiresRepository; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; /** * Clones a repository into a newly created directory, creates remote-tracking branches for each * branch in the cloned repository (visible using {@code geogig branch -r}), and creates and checks * out an initial branch that is forked from the cloned repository's currently active branch. * <p> * After the clone, a plain {@code geogig fetch} without arguments will update all the * remote-tracking branches, and a {@code geogig pull} without arguments will in addition merge the * remote master branch into the current master branch, if any. * <p> * This default configuration is achieved by creating references to the remote branch heads under * {@code refs/remotes/origin} and by initializing {@code remote.origin.url} and * {@code remote.origin.fetch} configuration variables. * <p> * CLI proxy for {@link CloneOp} * <p> * Usage: * <ul> * <li> {@code geogig clone [--branch <name>] <repository> [<directory>]} * </ul> * * @see CloneOp */ @RemotesReadOnly @RequiresRepository(false) @Parameters(commandNames = "clone", commandDescription = "Clone a repository into a new directory") public class Clone extends AbstractCommand implements CLICommand { @Parameter(names = { "-b", "--branch" }, description = "Branch to checkout when clone is finished.") private String branch; @Parameter(names = { "--depth" }, description = "Depth of the clone. If depth is less than 1, a full clone will be performed.") private int depth = 0; @Parameter(names = { "-u", "--username" }, description = "user name") private String username = null; @Parameter(names = { "-p", "--password" }, description = "password") private String password = null; @Parameter(names = { "--filter" }, description = "Ini filter file. This will create a sparse clone.") private String filterFile; @Parameter(names = { "--config" }, description = "Extra configuration options to set while preparing repository. Separate names from values with an equals sign and delimit configuration options with a colon. Example: storage.objects=bdbje:bdbje.version=0.1") private String config; @Parameter(description = "<repository> [<directory>]") private List<String> args; /** * Executes the clone command using the provided options. */ @Override public void runInternal(GeogigCLI cli) throws IOException { checkParameter(args != null && args.size() > 0, "You must specify a repository to clone."); checkParameter(args.size() < 3, "Too many arguments provided."); if (filterFile != null) { checkParameter(branch != null, "Sparse Clone: You must explicitly specify a remote branch to clone by using '--branch <branch>'."); } String repoURL = args.get(0).replace('\\', '/'); File repoDir; { File currDir = cli.getPlatform().pwd(); // Construct a non-relative repository URL in case of a local remote if (!repoURL.startsWith("http")) { File repo = new File(repoURL); if (!repo.isAbsolute()) { repo = new File(currDir, repoURL).getCanonicalFile(); } repoURL = repo.toURI().getPath(); } if (args != null && args.size() == 2) { String target = args.get(1); File f = new File(target); if (!f.isAbsolute()) { f = new File(currDir, target).getCanonicalFile(); } repoDir = f; } else { String[] sp = repoURL.split("/"); repoDir = new File(currDir, sp[sp.length - 1]).getCanonicalFile(); } if (!repoDir.exists() && !repoDir.mkdirs()) { throw new CommandFailedException("Can't create directory " + repoDir.getAbsolutePath()); } } GeoGIG geogig = new GeoGIG(cli.getGeogigInjector(), repoDir); checkParameter(!geogig.command(ResolveGeogigDir.class).call().isPresent(), "Destination path already exists and is not an empty directory."); geogig.command(InitOp.class).setConfig(Init.splitConfig(config)).setFilterFile(filterFile) .call(); cli.setGeogig(geogig); cli.getPlatform().setWorkingDir(repoDir); cli.getConsole().println("Cloning into '" + cli.getPlatform().pwd().getName() + "'..."); CloneOp clone = cli.getGeogig().command(CloneOp.class); clone.setProgressListener(cli.getProgressListener()); clone.setBranch(branch).setRepositoryURL(repoURL); clone.setUserName(username).setPassword(password); clone.setDepth(depth); clone.call(); cli.getConsole().println("Done."); } }