Fix enabling team operations on project import
[egit.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / CloneOperation.java
blobbc3f9fb0761a4bcb6219ccd37ea25b8b1a4b0197
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>
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * http://www.eclipse.org/legal/epl-v10.html
12 *******************************************************************************/
13 package org.eclipse.egit.core.op;
15 import java.io.File;
16 import java.io.IOException;
17 import java.lang.reflect.InvocationTargetException;
18 import java.net.URISyntaxException;
19 import java.util.Collection;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.NullProgressMonitor;
23 import org.eclipse.core.runtime.SubProgressMonitor;
24 import org.eclipse.egit.core.CoreText;
25 import org.eclipse.egit.core.EclipseGitProgressTransformer;
26 import org.eclipse.jface.operation.IRunnableWithProgress;
27 import org.eclipse.osgi.util.NLS;
28 import org.eclipse.jgit.errors.NotSupportedException;
29 import org.eclipse.jgit.errors.TransportException;
30 import org.eclipse.jgit.lib.Commit;
31 import org.eclipse.jgit.lib.Constants;
32 import org.eclipse.jgit.lib.GitIndex;
33 import org.eclipse.jgit.lib.Ref;
34 import org.eclipse.jgit.lib.RefUpdate;
35 import org.eclipse.jgit.lib.Repository;
36 import org.eclipse.jgit.lib.RepositoryConfig;
37 import org.eclipse.jgit.lib.Tree;
38 import org.eclipse.jgit.lib.WorkDirCheckout;
39 import org.eclipse.jgit.transport.FetchResult;
40 import org.eclipse.jgit.transport.RefSpec;
41 import org.eclipse.jgit.transport.RemoteConfig;
42 import org.eclipse.jgit.transport.Transport;
43 import org.eclipse.jgit.transport.URIish;
45 /**
46 * Clones a repository from a remote location to a local location.
48 public class CloneOperation implements IRunnableWithProgress {
49 private final URIish uri;
51 private final boolean allSelected;
53 private final Collection<Ref> selectedBranches;
55 private final File workdir;
57 private final File gitdir;
59 private final String branch;
61 private final String remoteName;
63 private Repository local;
65 private RemoteConfig remoteConfig;
67 private FetchResult fetchResult;
69 /**
70 * Create a new clone operation.
72 * @param uri
73 * remote we should fetch from.
74 * @param allSelected
75 * true when all branches have to be fetched (indicates wildcard
76 * in created fetch refspec), false otherwise.
77 * @param selectedBranches
78 * collection of branches to fetch. Ignored when allSelected is
79 * true.
80 * @param workdir
81 * working directory to clone to. The directory may or may not
82 * already exist.
83 * @param branch
84 * branch to initially clone from.
85 * @param remoteName
86 * name of created remote config as source remote (typically
87 * named "origin").
89 public CloneOperation(final URIish uri, final boolean allSelected,
90 final Collection<Ref> selectedBranches, final File workdir,
91 final String branch, final String remoteName) {
92 this.uri = uri;
93 this.allSelected = allSelected;
94 this.selectedBranches = selectedBranches;
95 this.workdir = workdir;
96 this.gitdir = new File(workdir, Constants.DOT_GIT);
97 this.branch = branch;
98 this.remoteName = remoteName;
101 public void run(final IProgressMonitor pm)
102 throws InvocationTargetException, InterruptedException {
103 final IProgressMonitor monitor;
104 if (pm == null)
105 monitor = new NullProgressMonitor();
106 else
107 monitor = pm;
109 try {
110 monitor.beginTask(NLS.bind(CoreText.CloneOperation_title, uri),
111 5000);
112 try {
113 doInit(new SubProgressMonitor(monitor, 100));
114 doFetch(new SubProgressMonitor(monitor, 4000));
115 doCheckout(new SubProgressMonitor(monitor, 900));
116 } finally {
117 closeLocal();
119 } catch (final Exception e) {
120 delete(workdir);
121 if (monitor.isCanceled())
122 throw new InterruptedException();
123 else
124 throw new InvocationTargetException(e);
125 } finally {
126 monitor.done();
132 * @return The git directory which will contain the repository
134 public File getGitDir() {
135 return gitdir;
138 private void closeLocal() {
139 if (local != null) {
140 local.close();
141 local = null;
145 private void doInit(final IProgressMonitor monitor)
146 throws URISyntaxException, IOException {
147 monitor.setTaskName("Initializing local repository");
149 local = new Repository(gitdir);
150 local.create();
152 final RefUpdate head = local.updateRef(Constants.HEAD);
153 head.disableRefLog();
154 head.link(branch);
156 remoteConfig = new RemoteConfig(local.getConfig(), remoteName);
157 remoteConfig.addURI(uri);
159 final String dst = Constants.R_REMOTES + remoteConfig.getName();
160 RefSpec wcrs = new RefSpec();
161 wcrs = wcrs.setForceUpdate(true);
162 wcrs = wcrs.setSourceDestination(Constants.R_HEADS + "*", dst + "/*");
164 if (allSelected) {
165 remoteConfig.addFetchRefSpec(wcrs);
166 } else {
167 for (final Ref ref : selectedBranches)
168 if (wcrs.matchSource(ref))
169 remoteConfig.addFetchRefSpec(wcrs.expandFromSource(ref));
172 // we're setting up for a clone with a checkout
173 local.getConfig().setBoolean("core", null, "bare", false);
175 remoteConfig.update(local.getConfig());
177 // branch is like 'Constants.R_HEADS + branchName', we need only
178 // the 'branchName' part
179 String branchName = branch.substring(Constants.R_HEADS.length());
181 // setup the default remote branch for branchName
182 local.getConfig().setString(RepositoryConfig.BRANCH_SECTION,
183 branchName, "remote", remoteName);
184 local.getConfig().setString(RepositoryConfig.BRANCH_SECTION,
185 branchName, "merge", branch);
187 local.getConfig().save();
190 private void doFetch(final IProgressMonitor monitor)
191 throws NotSupportedException, TransportException {
192 final Transport tn = Transport.open(local, remoteConfig);
193 try {
194 final EclipseGitProgressTransformer pm;
195 pm = new EclipseGitProgressTransformer(monitor);
196 fetchResult = tn.fetch(pm, null);
197 } finally {
198 tn.close();
202 private void doCheckout(final IProgressMonitor monitor) throws IOException {
203 final Ref head = fetchResult.getAdvertisedRef(branch);
204 if (head == null || head.getObjectId() == null)
205 return;
207 final GitIndex index = new GitIndex(local);
208 final Commit mapCommit = local.mapCommit(head.getObjectId());
209 final Tree tree = mapCommit.getTree();
210 final RefUpdate u;
211 final WorkDirCheckout co;
213 u = local.updateRef(Constants.HEAD);
214 u.setNewObjectId(mapCommit.getCommitId());
215 u.forceUpdate();
217 monitor.setTaskName("Checking out files");
218 co = new WorkDirCheckout(local, local.getWorkDir(), index, tree);
219 co.checkout();
220 monitor.setTaskName("Writing index");
221 index.write();
224 private static void delete(final File d) {
225 if (d.isDirectory()) {
226 final File[] items = d.listFiles();
227 if (items != null) {
228 for (final File c : items)
229 delete(c);
232 d.delete();