[pgm] Implement clone using CloneCommand
Change-Id: I56699b7bf9a71f673cb308d3015f51de5b06c1d9 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
parent
79201ac95e
commit
563c1ad514
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Matthias Sohn <matthias.sohn@sap.com>
|
||||||
|
* and other copyright owners as documented in the project's IP log.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available
|
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which
|
||||||
|
* accompanies this distribution, is reproduced below, and is
|
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||||
|
* names of its contributors may be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.eclipse.jgit.pgm;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.junit.JGitTestUtil;
|
||||||
|
import org.eclipse.jgit.junit.MockSystemReader;
|
||||||
|
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.transport.URIish;
|
||||||
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CloneTest extends CLIRepositoryTestCase {
|
||||||
|
|
||||||
|
private Git git;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
git = new Git(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClone() throws Exception {
|
||||||
|
createInitialCommit();
|
||||||
|
|
||||||
|
File gitDir = db.getDirectory();
|
||||||
|
String sourceURI = gitDir.toURI().toString();
|
||||||
|
File target = createTempDirectory("target");
|
||||||
|
StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
|
||||||
|
+ " " + target.getPath());
|
||||||
|
String[] result = execute(cmd.toString());
|
||||||
|
assertArrayEquals(new String[] {
|
||||||
|
"Cloning into '" + target.getPath() + "'...",
|
||||||
|
"", "" }, result);
|
||||||
|
|
||||||
|
Git git2 = Git.open(target);
|
||||||
|
List<Ref> branches = git2.branchList().call();
|
||||||
|
assertEquals("expected 1 branch", 1, branches.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createInitialCommit() throws Exception {
|
||||||
|
JGitTestUtil.writeTrashFile(db, "hello.txt", "world");
|
||||||
|
git.add().addFilepattern("hello.txt").call();
|
||||||
|
git.commit().setMessage("Initial commit").call();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloneEmpty() throws Exception {
|
||||||
|
File gitDir = db.getDirectory();
|
||||||
|
String sourceURI = gitDir.toURI().toString();
|
||||||
|
File target = createTempDirectory("target");
|
||||||
|
StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
|
||||||
|
+ " " + target.getPath());
|
||||||
|
String[] result = execute(cmd.toString());
|
||||||
|
assertArrayEquals(new String[] {
|
||||||
|
"Cloning into '" + target.getPath() + "'...",
|
||||||
|
"warning: You appear to have cloned an empty repository.", "",
|
||||||
|
"" }, result);
|
||||||
|
|
||||||
|
Git git2 = Git.open(target);
|
||||||
|
List<Ref> branches = git2.branchList().call();
|
||||||
|
assertEquals("expected 0 branch", 0, branches.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloneIntoCurrentDir() throws Exception {
|
||||||
|
createInitialCommit();
|
||||||
|
File target = createTempDirectory("target");
|
||||||
|
|
||||||
|
MockSystemReader sr = (MockSystemReader) SystemReader.getInstance();
|
||||||
|
sr.setProperty(Constants.OS_USER_DIR, target.getAbsolutePath());
|
||||||
|
|
||||||
|
File gitDir = db.getDirectory();
|
||||||
|
String sourceURI = gitDir.toURI().toString();
|
||||||
|
String name = new URIish(sourceURI).getHumanishName();
|
||||||
|
StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI);
|
||||||
|
String[] result = execute(cmd.toString());
|
||||||
|
assertArrayEquals(new String[] {
|
||||||
|
"Cloning into '" + new File(target, name).getName() + "'...",
|
||||||
|
"", "" }, result);
|
||||||
|
Git git2 = Git.open(new File(target, name));
|
||||||
|
List<Ref> branches = git2.branchList().call();
|
||||||
|
assertEquals("expected 1 branch", 1, branches.size());
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,8 @@ changesNotStagedForCommit=Changes not staged for commit:
|
||||||
changesToBeCommitted=Changes to be committed:
|
changesToBeCommitted=Changes to be committed:
|
||||||
checkoutConflict=error: Your local changes to the following files would be overwritten by checkout:
|
checkoutConflict=error: Your local changes to the following files would be overwritten by checkout:
|
||||||
checkoutConflictPathLine=\t{0}
|
checkoutConflictPathLine=\t{0}
|
||||||
|
clonedEmptyRepository=warning: You appear to have cloned an empty repository.
|
||||||
|
cloningInto=Cloning into ''{0}''...
|
||||||
commitLabel=commit
|
commitLabel=commit
|
||||||
configFileNotFound=configuration file {0} not found
|
configFileNotFound=configuration file {0} not found
|
||||||
conflictingUsageOf_git_dir_andArguments=conflicting usage of --git-dir and arguments
|
conflictingUsageOf_git_dir_andArguments=conflicting usage of --git-dir and arguments
|
||||||
|
|
|
@ -44,30 +44,15 @@
|
||||||
package org.eclipse.jgit.pgm;
|
package org.eclipse.jgit.pgm;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
import org.eclipse.jgit.dircache.DirCache;
|
import org.eclipse.jgit.api.CloneCommand;
|
||||||
import org.eclipse.jgit.dircache.DirCacheCheckout;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.api.errors.InvalidRemoteException;
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
|
||||||
import org.eclipse.jgit.lib.RefUpdate;
|
|
||||||
import org.eclipse.jgit.lib.Repository;
|
|
||||||
import org.eclipse.jgit.lib.StoredConfig;
|
|
||||||
import org.eclipse.jgit.lib.TextProgressMonitor;
|
|
||||||
import org.eclipse.jgit.pgm.internal.CLIText;
|
import org.eclipse.jgit.pgm.internal.CLIText;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
|
||||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
|
|
||||||
import org.eclipse.jgit.transport.FetchResult;
|
|
||||||
import org.eclipse.jgit.transport.RefSpec;
|
|
||||||
import org.eclipse.jgit.transport.RemoteConfig;
|
|
||||||
import org.eclipse.jgit.transport.TagOpt;
|
|
||||||
import org.eclipse.jgit.transport.Transport;
|
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
|
@ -88,8 +73,6 @@ class Clone extends AbstractFetchCommand {
|
||||||
@Argument(index = 1, metaVar = "metaVar_directory")
|
@Argument(index = 1, metaVar = "metaVar_directory")
|
||||||
private String localName;
|
private String localName;
|
||||||
|
|
||||||
private Repository dst;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final boolean requiresRepository() {
|
protected final boolean requiresRepository() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -101,116 +84,42 @@ protected void run() throws Exception {
|
||||||
throw die(CLIText.get().conflictingUsageOf_git_dir_andArguments);
|
throw die(CLIText.get().conflictingUsageOf_git_dir_andArguments);
|
||||||
|
|
||||||
final URIish uri = new URIish(sourceUri);
|
final URIish uri = new URIish(sourceUri);
|
||||||
|
File localNameF;
|
||||||
if (localName == null) {
|
if (localName == null) {
|
||||||
try {
|
try {
|
||||||
localName = uri.getHumanishName();
|
localName = uri.getHumanishName();
|
||||||
|
localNameF = new File(SystemReader.getInstance().getProperty(
|
||||||
|
Constants.OS_USER_DIR), localName);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw die(MessageFormat.format(CLIText.get().cannotGuessLocalNameFrom, sourceUri));
|
throw die(MessageFormat.format(
|
||||||
|
CLIText.get().cannotGuessLocalNameFrom, sourceUri));
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
localNameF = new File(localName);
|
||||||
|
|
||||||
|
if (branch == null)
|
||||||
|
branch = Constants.HEAD;
|
||||||
|
|
||||||
|
CloneCommand command = Git.cloneRepository();
|
||||||
|
command.setURI(sourceUri).setRemote(remoteName)
|
||||||
|
.setNoCheckout(noCheckout).setBranch(branch);
|
||||||
|
|
||||||
|
command.setGitDir(gitdir == null ? null : new File(gitdir));
|
||||||
|
command.setDirectory(localNameF);
|
||||||
|
outw.println(MessageFormat.format(CLIText.get().cloningInto, localName));
|
||||||
|
try {
|
||||||
|
db = command.call().getRepository();
|
||||||
|
if (db.resolve(Constants.HEAD) == null)
|
||||||
|
outw.println(CLIText.get().clonedEmptyRepository);
|
||||||
|
} catch (InvalidRemoteException e) {
|
||||||
|
throw die(MessageFormat.format(CLIText.get().doesNotExist,
|
||||||
|
sourceUri));
|
||||||
|
} finally {
|
||||||
|
if (db != null)
|
||||||
|
db.close();
|
||||||
}
|
}
|
||||||
if (gitdir == null)
|
|
||||||
gitdir = new File(localName, Constants.DOT_GIT).getAbsolutePath();
|
|
||||||
|
|
||||||
dst = new FileRepositoryBuilder().setGitDir(new File(gitdir)).build();
|
|
||||||
dst.create();
|
|
||||||
final StoredConfig dstcfg = dst.getConfig();
|
|
||||||
dstcfg.setBoolean("core", null, "bare", false); //$NON-NLS-1$ //$NON-NLS-2$
|
|
||||||
dstcfg.save();
|
|
||||||
db = dst;
|
|
||||||
|
|
||||||
outw.print(MessageFormat.format(
|
|
||||||
CLIText.get().initializedEmptyGitRepositoryIn, gitdir));
|
|
||||||
outw.println();
|
outw.println();
|
||||||
outw.flush();
|
outw.flush();
|
||||||
|
|
||||||
saveRemote(uri);
|
|
||||||
final FetchResult r = runFetch();
|
|
||||||
|
|
||||||
if (!noCheckout) {
|
|
||||||
final Ref checkoutRef;
|
|
||||||
if (branch == null)
|
|
||||||
checkoutRef = guessHEAD(r);
|
|
||||||
else {
|
|
||||||
checkoutRef = r.getAdvertisedRef(Constants.R_HEADS + branch);
|
|
||||||
if (checkoutRef == null)
|
|
||||||
throw die(MessageFormat.format(
|
|
||||||
CLIText.get().noSuchRemoteRef, branch));
|
|
||||||
}
|
|
||||||
doCheckout(checkoutRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveRemote(final URIish uri) throws URISyntaxException,
|
|
||||||
IOException {
|
|
||||||
final StoredConfig dstcfg = dst.getConfig();
|
|
||||||
final RemoteConfig rc = new RemoteConfig(dstcfg, remoteName);
|
|
||||||
rc.addURI(uri);
|
|
||||||
rc.addFetchRefSpec(new RefSpec().setForceUpdate(true)
|
|
||||||
.setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$
|
|
||||||
Constants.R_REMOTES + remoteName + "/*")); //$NON-NLS-1$
|
|
||||||
rc.update(dstcfg);
|
|
||||||
dstcfg.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private FetchResult runFetch() throws URISyntaxException, IOException {
|
|
||||||
final Transport tn = Transport.open(db, remoteName);
|
|
||||||
final FetchResult r;
|
|
||||||
try {
|
|
||||||
tn.setTagOpt(TagOpt.FETCH_TAGS);
|
|
||||||
r = tn.fetch(new TextProgressMonitor(), null);
|
|
||||||
} finally {
|
|
||||||
tn.close();
|
|
||||||
}
|
|
||||||
showFetchResult(r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Ref guessHEAD(final FetchResult result) {
|
|
||||||
final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD);
|
|
||||||
Ref head = null;
|
|
||||||
for (final Ref r : result.getAdvertisedRefs()) {
|
|
||||||
final String n = r.getName();
|
|
||||||
if (!n.startsWith(Constants.R_HEADS))
|
|
||||||
continue;
|
|
||||||
if (idHEAD == null || head != null)
|
|
||||||
continue;
|
|
||||||
if (r.getObjectId().equals(idHEAD.getObjectId()))
|
|
||||||
head = r;
|
|
||||||
}
|
|
||||||
if (idHEAD != null && head == null)
|
|
||||||
head = idHEAD;
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doCheckout(final Ref branch) throws IOException {
|
|
||||||
if (branch == null)
|
|
||||||
throw die(CLIText.get().cannotChekoutNoHeadsAdvertisedByRemote);
|
|
||||||
if (!Constants.HEAD.equals(branch.getName())) {
|
|
||||||
RefUpdate u = db.updateRef(Constants.HEAD);
|
|
||||||
u.disableRefLog();
|
|
||||||
u.link(branch.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
final RevCommit commit = parseCommit(branch);
|
|
||||||
final RefUpdate u = db.updateRef(Constants.HEAD);
|
|
||||||
u.setNewObjectId(commit);
|
|
||||||
u.forceUpdate();
|
|
||||||
|
|
||||||
DirCache dc = db.lockDirCache();
|
|
||||||
DirCacheCheckout co = new DirCacheCheckout(db, dc, commit.getTree());
|
|
||||||
co.checkout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private RevCommit parseCommit(final Ref branch)
|
|
||||||
throws MissingObjectException, IncorrectObjectTypeException,
|
|
||||||
IOException {
|
|
||||||
final RevWalk rw = new RevWalk(db);
|
|
||||||
final RevCommit commit;
|
|
||||||
try {
|
|
||||||
commit = rw.parseCommit(branch.getObjectId());
|
|
||||||
} finally {
|
|
||||||
rw.release();
|
|
||||||
}
|
|
||||||
return commit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,8 @@ public static String formatLine(String line) {
|
||||||
/***/ public String changesToBeCommitted;
|
/***/ public String changesToBeCommitted;
|
||||||
/***/ public String checkoutConflict;
|
/***/ public String checkoutConflict;
|
||||||
/***/ public String checkoutConflictPathLine;
|
/***/ public String checkoutConflictPathLine;
|
||||||
|
/***/ public String clonedEmptyRepository;
|
||||||
|
/***/ public String cloningInto;
|
||||||
/***/ public String commitLabel;
|
/***/ public String commitLabel;
|
||||||
/***/ public String conflictingUsageOf_git_dir_andArguments;
|
/***/ public String conflictingUsageOf_git_dir_andArguments;
|
||||||
/***/ public String couldNotCreateBranch;
|
/***/ public String couldNotCreateBranch;
|
||||||
|
|
Loading…
Reference in New Issue