Initial implementation of Clone
[nbgit.git] / src / org / nbgit / ui / clone / CloneAction.java
blobd89ab09092c8c0c668a436976472b02336bb904d
1 /*
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]"
24 * Contributor(s):
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;
45 import java.io.File;
46 import java.io.IOException;
47 import java.net.MalformedURLException;
48 import java.net.URISyntaxException;
49 import java.net.URL;
50 import javax.swing.SwingUtilities;
51 import org.nbgit.Git;
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) {
89 super(name, context);
92 @Override
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
104 projIsRepos = false;
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
110 break;
113 Clone clone = new Clone(root, tmp);
114 if (!clone.showDialog()) {
115 return;
118 URIish source = null;
119 try {
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(
134 final URIish source,
135 final File target,
136 final Boolean projIsRepos,
137 final File projFile,
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);
146 @Override
147 protected void perform() {
148 String projName = (projFile != null)
149 ? GitProjectUtils.getProjectName(projFile)
150 : null;
151 OutputLogger logger = getLogger();
152 try {
154 if (projName != null) {
155 logger.outputInRed(
156 NbBundle.getMessage(CloneAction.class,
157 "MSG_CLONE_FROM", projName, source)); // NOI18N
158 logger.outputInRed(
159 NbBundle.getMessage(CloneAction.class,
160 "MSG_CLONE_TO", projName, target)); // NOI18N
161 } else {
162 logger.outputInRed(
163 NbBundle.getMessage(CloneAction.class,
164 "MSG_EXTERNAL_CLONE_FROM", source)); // NOI18N
165 logger.outputInRed(
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) {
175 this.cancel();
177 doCheckout(repo, branch, logger);
179 if (isLocalClone) {
180 Git git = Git.getInstance();
181 ProjectManager projectManager = ProjectManager.getDefault();
182 File normalizedCloneFolder = FileUtil.normalizeFile(target);
183 File cloneProjFile;
184 if (!projIsRepos) {
185 String name = (projFile != null)
186 ? projFile.getAbsolutePath().substring(source.getPath().length() + 1)
187 : target.getAbsolutePath();
188 cloneProjFile = new File(normalizedCloneFolder, name);
189 } else {
190 cloneProjFile = normalizedCloneFolder;
192 openProject(cloneProjFile, projectManager, git);
193 } else if (scanForProjects) {
194 CloneCompleted cc = new CloneCompleted(target);
195 if (isCanceled()) {
196 return;
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);
207 } finally {
208 if (!isLocalClone) {
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() {
218 public void run() {
219 // Open and set focus on the cloned project if possible
220 OutputLogger logger = getLogger();
221 try {
222 FileObject cloneProj = FileUtil.toFileObject(cloneProjFile);
223 Project proj = null;
224 if (cloneProjFile != null && cloneProj != null) {
225 proj = projectManager.findProject(cloneProj);
227 if (proj != null) {
228 GitProjectUtils.openProject(proj, this, false);
229 // TODO: GitModuleConfig.getDefault().getSetMainProject()
230 git.versionedFilesChanged();
231 git.refreshAllAnnotations();
232 } else {
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);
238 } finally {
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 {
254 repo.create();
256 repo.getConfig().setBoolean("core", null, "bare", false);
257 repo.getConfig().save();
259 logger.output("Initialized empty Git repository in " + repo.getWorkDir().getAbsolutePath());
260 logger.flushLog();
262 // save remote
263 final RemoteConfig rc = new RemoteConfig(repo.getConfig(), "origin");
264 rc.addURI(uri);
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 {
272 final FetchResult r;
273 final Transport tn = Transport.open(repo, "origin");
274 try {
275 r = tn.fetch(new GitProgressMonitor(), null);
276 } finally {
277 tn.close();
279 logger.output("--- Fetch Completed ---");
280 return r;
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();
288 final RefUpdate u;
289 final WorkDirCheckout co;
291 u = repo.updateRef(Constants.HEAD);
292 u.setNewObjectId(mapCommit.getCommitId());
293 u.forceUpdate();
295 // checking out files
296 co = new WorkDirCheckout(repo, repo.getWorkDir(), index, tree);
297 co.checkout();
298 // writing index
299 index.write();