2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
26 * The Original Software is NetBeans. The Initial Developer of the Original
27 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
28 * Microsystems, Inc. All Rights Reserved.
29 * Portions Copyright 2009 Alexander Coles (Ikonoklastik Productions).
31 * If you wish your version of this file to be governed by only the CDDL
32 * or only the GPL Version 2, indicate your decision by adding
33 * "[Contributor] elects to include this software in this distribution
34 * under the [CDDL or GPL Version 2] license." If you do not indicate a
35 * single choice of license, a recipient has the option to distribute
36 * your version of this file under either the CDDL, the GPL Version 2 or
37 * to extend the choice of license to its licensees as provided above.
38 * However, if you add GPL Version 2 code and therefore, elected the GPL
39 * Version 2 license, then the option applies only if the new code is
40 * made subject to such option by the copyright holder.
42 package org
.nbgit
.ui
.clone
;
44 import java
.awt
.event
.ActionEvent
;
46 import java
.io
.IOException
;
47 import java
.net
.MalformedURLException
;
48 import java
.net
.URISyntaxException
;
50 import javax
.swing
.SwingUtilities
;
52 import org
.nbgit
.GitModuleConfig
;
53 import org
.nbgit
.GitProgressMonitor
;
54 import org
.nbgit
.GitProgressSupport
;
55 import org
.nbgit
.OutputLogger
;
56 import org
.nbgit
.ui
.ContextAction
;
57 import org
.nbgit
.util
.GitProjectUtils
;
58 import org
.nbgit
.util
.GitUtils
;
59 import org
.netbeans
.api
.project
.Project
;
60 import org
.netbeans
.api
.project
.ProjectManager
;
61 import org
.netbeans
.modules
.versioning
.spi
.VCSContext
;
62 import org
.openide
.DialogDisplayer
;
63 import org
.openide
.NotifyDescriptor
;
64 import org
.openide
.filesystems
.FileObject
;
65 import org
.openide
.filesystems
.FileUtil
;
66 import org
.openide
.util
.Exceptions
;
67 import org
.openide
.util
.NbBundle
;
68 import org
.openide
.util
.RequestProcessor
;
69 import org
.spearce
.jgit
.errors
.NotSupportedException
;
70 import org
.spearce
.jgit
.errors
.TransportException
;
71 import org
.spearce
.jgit
.lib
.Commit
;
72 import org
.spearce
.jgit
.lib
.Constants
;
73 import org
.spearce
.jgit
.lib
.GitIndex
;
74 import org
.spearce
.jgit
.lib
.Ref
;
75 import org
.spearce
.jgit
.lib
.RefUpdate
;
76 import org
.spearce
.jgit
.lib
.Repository
;
77 import org
.spearce
.jgit
.lib
.RepositoryConfig
;
78 import org
.spearce
.jgit
.lib
.Tree
;
79 import org
.spearce
.jgit
.lib
.WorkDirCheckout
;
80 import org
.spearce
.jgit
.transport
.FetchResult
;
81 import org
.spearce
.jgit
.transport
.RefSpec
;
82 import org
.spearce
.jgit
.transport
.RemoteConfig
;
83 import org
.spearce
.jgit
.transport
.Transport
;
84 import org
.spearce
.jgit
.transport
.URIish
;
86 public class CloneAction
extends ContextAction
{
88 public CloneAction(String name
, VCSContext context
) {
93 protected void performAction(ActionEvent event
) {
94 final File root
= GitUtils
.getRootFile(context
);
95 if (root
== null) return;
97 // Get unused Clone Folder name
98 File tmp
= root
.getParentFile();
99 File projFile
= GitUtils
.getProjectFile(context
);
100 String folderName
= root
.getName();
101 Boolean projIsRepos
= true;
102 if (!root
.equals(projFile
)) {
103 // Git Repository is not the same as project root
107 for (int i
= 0; i
< 10000; i
++) {
108 if (!new File(tmp
, folderName
+ "_clone" + i
).exists()) { // NOI18N
109 tmp
= new File(tmp
, folderName
+ "_clone" + i
); // NOI18N
113 Clone clone
= new Clone(root
, tmp
);
114 if (!clone
.showDialog()) {
118 URIish source
= null;
120 source
= new URIish(root
.toURL());
121 } catch (MalformedURLException ex
) {
122 Exceptions
.printStackTrace(ex
);
125 performClone(source
, clone
.getTargetDir(), projIsRepos
, projFile
, true, true);
128 public static RequestProcessor
.Task
performClone(final URIish source
, final File target
, boolean projIsRepos
,
129 File projFile
, boolean scanForProjects
) {
130 return performClone(source
, target
, projIsRepos
, projFile
, false, scanForProjects
);
133 private static RequestProcessor
.Task
performClone(
136 final Boolean projIsRepos
,
138 final boolean isLocalClone
,
139 final boolean scanForProjects
) {
141 RequestProcessor rp
= Git
.getInstance().getRequestProcessor(source
.toString());
142 final GitProgressSupport support
= new GitProgressSupport() {
144 Repository repo
= Git
.getInstance().getRepository(target
);
147 protected void perform() {
148 String projName
= (projFile
!= null)
149 ? GitProjectUtils
.getProjectName(projFile
)
151 OutputLogger logger
= getLogger();
154 if (projName
!= null) {
156 NbBundle
.getMessage(CloneAction
.class,
157 "MSG_CLONE_FROM", projName
, source
)); // NOI18N
159 NbBundle
.getMessage(CloneAction
.class,
160 "MSG_CLONE_TO", projName
, target
)); // NOI18N
163 NbBundle
.getMessage(CloneAction
.class,
164 "MSG_EXTERNAL_CLONE_FROM", source
)); // NOI18N
166 NbBundle
.getMessage(CloneAction
.class,
167 "MSG_EXTERNAL_CLONE_TO", target
)); // NOI18N
169 logger
.output(""); // NOI18N
171 doInit(repo
, source
, logger
);
172 FetchResult r
= doFetch(repo
, logger
);
173 Ref branch
= r
.getAdvertisedRef(Constants
.HEAD
);
174 if (branch
== null) {
177 doCheckout(repo
, branch
, logger
);
180 Git git
= Git
.getInstance();
181 ProjectManager projectManager
= ProjectManager
.getDefault();
182 File normalizedCloneFolder
= FileUtil
.normalizeFile(target
);
185 String name
= (projFile
!= null)
186 ? projFile
.getAbsolutePath().substring(source
.getPath().length() + 1)
187 : target
.getAbsolutePath();
188 cloneProjFile
= new File(normalizedCloneFolder
, name
);
190 cloneProjFile
= normalizedCloneFolder
;
192 openProject(cloneProjFile
, projectManager
, git
);
193 } else if (scanForProjects
) {
194 CloneCompleted cc
= new CloneCompleted(target
);
198 cc
.scanForProjects(this);
201 } catch (URISyntaxException usex
) {
202 NotifyDescriptor
.Exception e
= new NotifyDescriptor
.Exception(usex
);
203 DialogDisplayer
.getDefault().notifyLater(e
);
204 } catch (IOException ex
) {
205 NotifyDescriptor
.Exception e
= new NotifyDescriptor
.Exception(ex
);
206 DialogDisplayer
.getDefault().notifyLater(e
);
209 logger
.outputInRed(NbBundle
.getMessage(CloneAction
.class, "MSG_CLONE_DONE")); // NOI18N
210 logger
.output(""); // NOI18N
215 private void openProject(final File cloneProjFile
, final ProjectManager projectManager
, final Git git
) {
216 SwingUtilities
.invokeLater(new Runnable() {
219 // Open and set focus on the cloned project if possible
220 OutputLogger logger
= getLogger();
222 FileObject cloneProj
= FileUtil
.toFileObject(cloneProjFile
);
224 if (cloneProjFile
!= null && cloneProj
!= null) {
225 proj
= projectManager
.findProject(cloneProj
);
228 GitProjectUtils
.openProject(proj
, this, false);
229 // TODO: GitModuleConfig.getDefault().getSetMainProject()
230 git
.versionedFilesChanged();
231 git
.refreshAllAnnotations();
233 logger
.outputInRed(NbBundle
.getMessage(CloneAction
.class, "MSG_EXTERNAL_CLONE_PRJ_NOT_FOUND_CANT_SETASMAIN")); // NOI18N
235 } catch (IOException ioe
) {
236 NotifyDescriptor
.Exception e
= new NotifyDescriptor
.Exception(ioe
);
237 DialogDisplayer
.getDefault().notifyLater(e
);
239 logger
.outputInRed(NbBundle
.getMessage(CloneAction
.class, "MSG_CLONE_DONE")); // NOI18N
240 logger
.output(""); // NOI18N
247 //support.setRepositoryRoot(source);
249 return support
.start(rp
, source
.toString(), org
.openide
.util
.NbBundle
.getMessage(CloneAction
.class, "LBL_Clone_Progress", source
)); // NO
253 public static void doInit(Repository repo
, URIish uri
, OutputLogger logger
) throws IOException
, URISyntaxException
{
256 repo
.getConfig().setBoolean("core", null, "bare", false);
257 repo
.getConfig().save();
259 logger
.output("Initialized empty Git repository in " + repo
.getWorkDir().getAbsolutePath());
263 final RemoteConfig rc
= new RemoteConfig(repo
.getConfig(), "origin");
265 rc
.addFetchRefSpec(new RefSpec().setForceUpdate(true).setSourceDestination(Constants
.R_HEADS
+ "*",
266 Constants
.R_REMOTES
+ "origin" + "/*"));
267 rc
.update(repo
.getConfig());
268 repo
.getConfig().save();
271 public static FetchResult
doFetch(Repository repo
, OutputLogger logger
) throws NotSupportedException
, TransportException
, URISyntaxException
{
273 final Transport tn
= Transport
.open(repo
, "origin");
275 r
= tn
.fetch(new GitProgressMonitor(), null);
279 logger
.output("--- Fetch Completed ---");
283 public static void doCheckout(Repository repo
, Ref branch
, OutputLogger logger
) throws IOException
{
285 final GitIndex index
= new GitIndex(repo
);
286 final Commit mapCommit
= repo
.mapCommit(branch
.getObjectId());
287 final Tree tree
= mapCommit
.getTree();
289 final WorkDirCheckout co
;
291 u
= repo
.updateRef(Constants
.HEAD
);
292 u
.setNewObjectId(mapCommit
.getCommitId());
295 // checking out files
296 co
= new WorkDirCheckout(repo
, repo
.getWorkDir(), index
, tree
);