refactor: simplify collection.toArray()
[egit/eclipse.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / CloneOperation.java
blob30528aecc8569c7c008c53406f5b62c437710b57
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;
18 import java.io.File;
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;
42 /**
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<>();
68 /**
69 * Create a new clone operation.
71 * @param uri
72 * remote we should fetch from.
73 * @param allSelected
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
78 * true.
79 * @param workdir
80 * working directory to clone to. The directory may or may not
81 * already exist.
82 * @param refName
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
86 * @param remoteName
87 * name of created remote config as source remote (typically
88 * named "origin").
89 * @param timeout
90 * timeout in seconds
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) {
95 this.uri = uri;
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;
122 * @param monitor
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() {
138 @Override
139 public void initializedSubmodules(Collection<String> submodules) {
140 // Nothing to do
143 @Override
144 public void cloningSubmodule(String path) {
145 progress.setTaskName(NLS.bind(
146 CoreText.CloneOperation_submodule_title, uri, path));
149 @Override
150 public void checkingOut(AnyObjectId commit, String path) {
151 // Nothing to do
154 Repository repository = null;
155 try {
156 CloneCommand cloneRepository = Git.cloneRepository();
157 cloneRepository.setCredentialsProvider(credentialsProvider);
158 if (refName != null) {
159 cloneRepository.setBranch(refName);
160 } else {
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) {
191 try {
192 if (repository != null) {
193 repository.close();
194 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();
204 } else {
205 throw new InvocationTargetException(e);
207 } finally {
208 if (repository != null) {
209 repository.close();
215 * @return The git directory which will contain the repository
217 public File getGitDir() {
218 return gitdir;
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 {
234 * Executes the task
235 * @param repository the cloned git repository
237 * @param monitor
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;