1 /*******************************************************************************
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
5 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
6 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
7 * Copyright (C) 2017, Thomas Wolf <thomas.wolf@paranor.ch>
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the Eclipse Public License 2.0
11 * which accompanies this distribution, and is available at
12 * https://www.eclipse.org/legal/epl-2.0/
14 * SPDX-License-Identifier: EPL-2.0
15 *******************************************************************************/
16 package org
.eclipse
.egit
.core
.op
;
19 import java
.io
.IOException
;
20 import java
.lang
.reflect
.InvocationTargetException
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Collection
;
23 import java
.util
.List
;
24 import java
.util
.concurrent
.CopyOnWriteArrayList
;
26 import org
.eclipse
.core
.runtime
.CoreException
;
27 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
28 import org
.eclipse
.core
.runtime
.SubMonitor
;
29 import org
.eclipse
.egit
.core
.EclipseGitProgressTransformer
;
30 import org
.eclipse
.egit
.core
.internal
.CoreText
;
31 import org
.eclipse
.jgit
.api
.CloneCommand
;
32 import org
.eclipse
.jgit
.api
.Git
;
33 import org
.eclipse
.jgit
.lib
.AnyObjectId
;
34 import org
.eclipse
.jgit
.lib
.Constants
;
35 import org
.eclipse
.jgit
.lib
.Ref
;
36 import org
.eclipse
.jgit
.lib
.Repository
;
37 import org
.eclipse
.jgit
.transport
.CredentialsProvider
;
38 import org
.eclipse
.jgit
.transport
.URIish
;
39 import org
.eclipse
.jgit
.util
.FileUtils
;
40 import org
.eclipse
.osgi
.util
.NLS
;
43 * Clones a repository from a remote location to a local location.
45 public class CloneOperation
{
46 private final URIish uri
;
48 private final boolean allSelected
;
50 private boolean cloneSubmodules
;
52 private final Collection
<Ref
> selectedBranches
;
54 private final File workdir
;
56 private final File gitdir
;
58 private final String refName
;
60 private final String remoteName
;
62 private final int timeout
;
64 private CredentialsProvider credentialsProvider
;
66 private final List
<PostCloneTask
> postCloneTasks
= new CopyOnWriteArrayList
<>();
69 * Create a new clone operation.
72 * remote we should fetch from.
74 * true when all branches have to be fetched (indicates wildcard
75 * in created fetch refspec), false otherwise.
76 * @param selectedBranches
77 * collection of branches to fetch. Ignored when allSelected is
80 * working directory to clone to. The directory may or may not
83 * name of ref (usually tag or branch) to be checked out after
84 * clone, e.g. full <code>refs/heads/master</code> or short
85 * <code>v3.1.0</code>, or null for no checkout
87 * name of created remote config as source remote (typically
92 public CloneOperation(final URIish uri
, final boolean allSelected
,
93 final Collection
<Ref
> selectedBranches
, final File workdir
,
94 final String refName
, final String remoteName
, int timeout
) {
96 this.allSelected
= allSelected
;
97 this.selectedBranches
= selectedBranches
;
98 this.workdir
= workdir
;
99 this.gitdir
= new File(workdir
, Constants
.DOT_GIT
);
100 this.refName
= refName
;
101 this.remoteName
= remoteName
;
102 this.timeout
= timeout
;
106 * Sets a credentials provider
107 * @param credentialsProvider
109 public void setCredentialsProvider(CredentialsProvider credentialsProvider
) {
110 this.credentialsProvider
= credentialsProvider
;
114 * @param cloneSubmodules
115 * true to initialize and update submodules
117 public void setCloneSubmodules(boolean cloneSubmodules
) {
118 this.cloneSubmodules
= cloneSubmodules
;
123 * the monitor to be used for reporting progress and responding
124 * to cancellation. The monitor is never <code>null</code>
125 * @throws InvocationTargetException
126 * @throws InterruptedException
128 public void run(final IProgressMonitor monitor
)
129 throws InvocationTargetException
, InterruptedException
{
130 String title
= NLS
.bind(CoreText
.CloneOperation_title
, uri
);
131 SubMonitor progress
= SubMonitor
.convert(monitor
, title
,
132 postCloneTasks
.isEmpty() ?
10 : 11);
134 EclipseGitProgressTransformer gitMonitor
= new EclipseGitProgressTransformer(
135 progress
.newChild(10));
136 CloneCommand
.Callback callback
= new CloneCommand
.Callback() {
139 public void initializedSubmodules(Collection
<String
> submodules
) {
144 public void cloningSubmodule(String path
) {
145 progress
.setTaskName(NLS
.bind(
146 CoreText
.CloneOperation_submodule_title
, uri
, path
));
150 public void checkingOut(AnyObjectId commit
, String path
) {
154 Repository repository
= null;
156 CloneCommand cloneRepository
= Git
.cloneRepository();
157 cloneRepository
.setCredentialsProvider(credentialsProvider
);
158 if (refName
!= null) {
159 cloneRepository
.setBranch(refName
);
161 cloneRepository
.setNoCheckout(true);
163 cloneRepository
.setDirectory(workdir
);
164 cloneRepository
.setProgressMonitor(gitMonitor
);
165 cloneRepository
.setRemote(remoteName
);
166 cloneRepository
.setURI(uri
.toString());
167 cloneRepository
.setTimeout(timeout
);
168 cloneRepository
.setCloneAllBranches(allSelected
);
169 cloneRepository
.setCloneSubmodules(cloneSubmodules
);
170 if (cloneSubmodules
) {
171 cloneRepository
.setCallback(callback
);
173 if (selectedBranches
!= null) {
174 List
<String
> branches
= new ArrayList
<String
>();
175 for (Ref branch
: selectedBranches
) {
176 branches
.add(branch
.getName());
178 cloneRepository
.setBranchesToClone(branches
);
180 Git git
= cloneRepository
.call();
181 repository
= git
.getRepository();
182 if (!postCloneTasks
.isEmpty()) {
183 progress
.setTaskName(title
);
184 progress
.setWorkRemaining(postCloneTasks
.size());
185 progress
.subTask(CoreText
.CloneOperation_configuring
);
186 for (PostCloneTask task
: postCloneTasks
) {
187 task
.execute(repository
, progress
.newChild(1));
190 } catch (final Exception e
) {
192 if (repository
!= null) {
196 FileUtils
.delete(workdir
, FileUtils
.RECURSIVE
);
197 } catch (IOException ioe
) {
198 throw new InvocationTargetException(e
, NLS
.bind(
199 CoreText
.CloneOperation_failed_cleanup
,
200 ioe
.getLocalizedMessage()));
202 if (monitor
.isCanceled()) {
203 throw new InterruptedException();
205 throw new InvocationTargetException(e
);
208 if (repository
!= null) {
215 * @return The git directory which will contain the repository
217 public File
getGitDir() {
222 * @param task to be performed after clone
224 public void addPostCloneTask(PostCloneTask task
) {
225 postCloneTasks
.add(task
);
229 * A task which can be added to be performed after clone
231 public interface PostCloneTask
{
235 * @param repository the cloned git repository
238 * a progress monitor, or <code>null</code> if progress reporting
239 * and cancellation are not desired
240 * @throws CoreException
242 void execute(Repository repository
, IProgressMonitor monitor
) throws CoreException
;