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
;
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
;
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 String branch
;
59 private final String remoteName
;
61 private Repository local
;
63 private RemoteConfig remoteConfig
;
65 private FetchResult fetchResult
;
68 * Create a new clone operation.
71 * remote we should fetch from.
73 * true when all branches have to be fetched (indicates wildcard
74 * in created fetch refspec), false otherwise.
75 * @param selectedBranches
76 * collection of branches to fetch. Ignored when allSelected is
79 * working directory to clone to. The directory may or may not
82 * branch to initially clone from.
84 * name of created remote config as source remote (typically
87 public CloneOperation(final URIish uri
, final boolean allSelected
,
88 final Collection
<Ref
> selectedBranches
, final File workdir
,
89 final String branch
, final String remoteName
) {
91 this.allSelected
= allSelected
;
92 this.selectedBranches
= selectedBranches
;
93 this.workdir
= workdir
;
95 this.remoteName
= remoteName
;
98 public void run(final IProgressMonitor pm
)
99 throws InvocationTargetException
, InterruptedException
{
100 final IProgressMonitor monitor
;
102 monitor
= new NullProgressMonitor();
107 monitor
.beginTask(NLS
.bind(CoreText
.CloneOperation_title
, uri
),
110 doInit(new SubProgressMonitor(monitor
, 100));
111 doFetch(new SubProgressMonitor(monitor
, 4000));
112 doCheckout(new SubProgressMonitor(monitor
, 900));
116 } catch (final Exception e
) {
118 if (monitor
.isCanceled())
119 throw new InterruptedException();
121 throw new InvocationTargetException(e
);
127 private void closeLocal() {
134 private void doInit(final IProgressMonitor monitor
)
135 throws URISyntaxException
, IOException
{
136 monitor
.setTaskName("Initializing local repository");
138 final File gitdir
= new File(workdir
, ".git");
139 local
= new Repository(gitdir
);
141 local
.writeSymref(Constants
.HEAD
, branch
);
143 remoteConfig
= new RemoteConfig(local
.getConfig(), remoteName
);
144 remoteConfig
.addURI(uri
);
146 final String dst
= Constants
.R_REMOTES
+ remoteConfig
.getName();
147 RefSpec wcrs
= new RefSpec();
148 wcrs
= wcrs
.setForceUpdate(true);
149 wcrs
= wcrs
.setSourceDestination(Constants
.R_HEADS
+ "*", dst
+ "/*");
152 remoteConfig
.addFetchRefSpec(wcrs
);
154 for (final Ref ref
: selectedBranches
)
155 if (wcrs
.matchSource(ref
))
156 remoteConfig
.addFetchRefSpec(wcrs
.expandFromSource(ref
));
159 // we're setting up for a clone with a checkout
160 local
.getConfig().setBoolean("core", null, "bare", false);
162 remoteConfig
.update(local
.getConfig());
164 // branch is like 'Constants.R_HEADS + branchName', we need only
165 // the 'branchName' part
166 String branchName
= branch
.substring(Constants
.R_HEADS
.length());
168 // setup the default remote branch for branchName
169 local
.getConfig().setString(RepositoryConfig
.BRANCH_SECTION
,
170 branchName
, "remote", remoteName
);
171 local
.getConfig().setString(RepositoryConfig
.BRANCH_SECTION
,
172 branchName
, "merge", branch
);
174 local
.getConfig().save();
177 private void doFetch(final IProgressMonitor monitor
)
178 throws NotSupportedException
, TransportException
{
179 final Transport tn
= Transport
.open(local
, remoteConfig
);
181 final EclipseGitProgressTransformer pm
;
182 pm
= new EclipseGitProgressTransformer(monitor
);
183 fetchResult
= tn
.fetch(pm
, null);
189 private void doCheckout(final IProgressMonitor monitor
) throws IOException
{
190 final Ref head
= fetchResult
.getAdvertisedRef(branch
);
191 if (head
== null || head
.getObjectId() == null)
194 final GitIndex index
= new GitIndex(local
);
195 final Commit mapCommit
= local
.mapCommit(head
.getObjectId());
196 final Tree tree
= mapCommit
.getTree();
198 final WorkDirCheckout co
;
200 u
= local
.updateRef(Constants
.HEAD
);
201 u
.setNewObjectId(mapCommit
.getCommitId());
204 monitor
.setTaskName("Checking out files");
205 co
= new WorkDirCheckout(local
, local
.getWorkDir(), index
, tree
);
207 monitor
.setTaskName("Writing index");
211 private static void delete(final File d
) {
212 if (d
.isDirectory()) {
213 final File
[] items
= d
.listFiles();
215 for (final File c
: items
)