SVN: checkout: little improvement
[idea/community.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / checkout / SvnCheckoutProvider.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.idea.svn.checkout;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.progress.ProgressIndicator;
20 import com.intellij.openapi.progress.ProgressManager;
21 import com.intellij.openapi.progress.Task;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.ui.Messages;
24 import com.intellij.openapi.util.Ref;
25 import com.intellij.openapi.util.io.FileUtil;
26 import com.intellij.openapi.vcs.CheckoutProvider;
27 import com.intellij.openapi.vcs.VcsConfiguration;
28 import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
29 import com.intellij.openapi.vcs.impl.ExcludedFileIndex;
30 import com.intellij.openapi.vcs.update.RefreshVFsSynchronously;
31 import com.intellij.openapi.vfs.LocalFileSystem;
32 import com.intellij.openapi.vfs.VirtualFile;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
35 import org.jetbrains.idea.svn.*;
36 import org.jetbrains.idea.svn.actions.ExclusiveBackgroundVcsAction;
37 import org.jetbrains.idea.svn.actions.SvnExcludingIgnoredOperation;
38 import org.jetbrains.idea.svn.dialogs.CheckoutDialog;
39 import org.tmatesoft.svn.core.SVNCancelException;
40 import org.tmatesoft.svn.core.SVNDepth;
41 import org.tmatesoft.svn.core.SVNException;
42 import org.tmatesoft.svn.core.SVNURL;
43 import org.tmatesoft.svn.core.wc.*;
44
45 import java.io.File;
46 import java.io.IOException;
47
48 public class SvnCheckoutProvider implements CheckoutProvider {
49
50   public void doCheckout(@NotNull final Project project, Listener listener) {
51     CheckoutDialog dialog = new CheckoutDialog(project, listener);
52     dialog.show();
53   }
54
55   public static void doCheckout(final Project project, final File target, final String url, final SVNRevision revision,
56                                 final SVNDepth depth, final boolean ignoreExternals, @Nullable final Listener listener) {
57     final Ref<Boolean> checkoutSuccessful = new Ref<Boolean>();
58
59     if (! target.exists()) {
60       target.mkdirs();
61     }
62     final SVNException[] exception = new SVNException[1];
63
64     final Task.Backgroundable checkoutBackgroundTask = new Task.Backgroundable(project,
65                      SvnBundle.message("message.title.check.out"), true, VcsConfiguration.getInstance(project).getCheckoutOption()) {
66       public void run(@NotNull final ProgressIndicator indicator) {
67         final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
68         final SVNUpdateClient client = SvnVcs.getInstance(project).createUpdateClient();
69         client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), false, progressIndicator));
70         client.setIgnoreExternals(ignoreExternals);
71         try {
72           progressIndicator.setText(SvnBundle.message("progress.text.checking.out", target.getAbsolutePath()));
73           client.doCheckout(SVNURL.parseURIEncoded(url), target, SVNRevision.UNDEFINED, revision, depth, true);
74           progressIndicator.checkCanceled();
75           checkoutSuccessful.set(Boolean.TRUE);
76         }
77         catch (SVNCancelException ignore) {
78         }
79         catch (SVNException e) {
80           exception[0] = e;
81         }
82         finally {
83           client.setIgnoreExternals(false);
84           client.setEventHandler(null);
85           SvnWorkingCopyFormatHolder.setPresetFormat(null);
86         }
87       }
88
89       public void onCancel() {
90         onSuccess();
91       }
92
93       public void onSuccess() {
94         if (exception[0] != null) {
95           Messages.showErrorDialog(SvnBundle.message("message.text.cannot.checkout", exception[0].getMessage()), SvnBundle.message("message.title.check.out"));
96         }
97
98         final VirtualFile vf = RefreshVFsSynchronously.findCreatedFile(target);
99         if (vf != null) {
100           vf.refresh(true, true, new Runnable() {
101             public void run() {
102               ApplicationManager.getApplication().invokeLater(new Runnable() {
103                 public void run() {
104                   notifyListener();
105                 }
106               });
107             }
108           });
109         }
110         else {
111           notifyListener();
112         }
113       }
114
115       private void notifyListener() {
116         notifyRootManagerIfUnderProject(project, target);
117         if (listener != null) {
118           if (!checkoutSuccessful.isNull()) {
119             listener.directoryCheckedOut(target);
120           }
121           listener.checkoutCompleted();
122         }
123       }
124     };
125
126     // allow to select working copy format
127     if (! promptForWCopyFormat(target, project)) {
128       // cancelled
129       SvnWorkingCopyFormatHolder.setPresetFormat(null);
130       return;
131     }
132     ProgressManager.getInstance().run(checkoutBackgroundTask);
133   }
134
135   private static void notifyRootManagerIfUnderProject(final Project project, final File directory) {
136     if (project.isDefault()) return;
137     final ProjectLevelVcsManagerEx plVcsManager = ProjectLevelVcsManagerEx.getInstanceChecked(project);
138     final SvnVcs vcs = (SvnVcs) plVcsManager.findVcsByName(SvnVcs.VCS_NAME);
139
140     final VirtualFile[] files = vcs.getSvnFileUrlMapping().getNotFilteredRoots();
141     for (VirtualFile file : files) {
142       try {
143         if (FileUtil.isAncestor(new File(file.getPath()), directory, false)) {
144           // todo: should be done like auto detection
145           plVcsManager.fireDirectoryMappingsChanged();
146           return;
147         }
148       }
149       catch (IOException e) {
150         //
151       }
152     }
153   }
154
155   public static boolean promptForWCopyFormat(final File target, final Project project) {
156     String formatMode = null;
157     final Ref<Boolean> wasOk = new Ref<Boolean>();
158     while ((formatMode == null) && (! Boolean.FALSE.equals(wasOk.get()))) {
159       formatMode = SvnFormatSelector.showUpgradeDialog(target, project, true, SvnConfiguration.UPGRADE_AUTO_16, wasOk);
160       SvnWorkingCopyFormatHolder.setPresetFormat(WorkingCopyFormat.getInstance(formatMode));
161     }
162     return Boolean.TRUE.equals(wasOk.get());
163   }
164
165   public static void doExport(final Project project, final File target, final String url, final SVNDepth depth,
166                               final boolean ignoreExternals, final boolean force, final String eolStyle) {
167     try {
168       final SVNException[] exception = new SVNException[1];
169       final SVNUpdateClient client = SvnVcs.getInstance(project).createUpdateClient();
170
171       ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
172         public void run() {
173           ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
174           client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), true, progressIndicator));
175           client.setIgnoreExternals(ignoreExternals);
176           try {
177             progressIndicator.setText(SvnBundle.message("progress.text.export", target.getAbsolutePath()));
178             client.doExport(SVNURL.parseURIEncoded(url), target, SVNRevision.UNDEFINED, SVNRevision.HEAD, eolStyle, force, depth);
179           }
180           catch (SVNException e) {
181             exception[0] = e;
182           }
183           finally {
184             client.setIgnoreExternals(false);
185             client.setEventHandler(null);
186           }
187         }
188       }, SvnBundle.message("message.title.export"), true, project);
189       if (exception[0] != null) {
190         throw exception[0];
191       }
192     }
193     catch (SVNException e1) {
194       Messages.showErrorDialog(SvnBundle.message("message.text.cannot.export", e1.getMessage()), SvnBundle.message("message.title.export"));
195     }
196   }
197
198   public static void doImport(final Project project, final File target, final SVNURL url, final SVNDepth depth,
199                               final boolean includeIgnored, final String message) {
200     final Ref<String> errorMessage = new Ref<String>();
201     final SVNCommitClient client = SvnVcs.getInstance(project).createCommitClient();
202     final String targetPath = FileUtil.toSystemIndependentName(target.getAbsolutePath());
203
204     ExclusiveBackgroundVcsAction.run(project, new Runnable() {
205       public void run() {
206         ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
207           public void run() {
208             ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
209             client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), true, progressIndicator));
210             try {
211               progressIndicator.setText(SvnBundle.message("progress.text.import", target.getAbsolutePath()));
212
213               final VirtualFile targetVf = SvnUtil.getVirtualFile(targetPath);
214               if (targetVf == null) {
215                 errorMessage.set("Can not find file: " + targetPath);
216               } else if (! ExcludedFileIndex.getInstance(project).isInContent(targetVf)) {
217                 // do not pay attention to ignored/excluded settings
218                 client.doImport(target, url, message, null, !includeIgnored, false, depth);
219               } else {
220                 client.setCommitHandler(new MyFilter(LocalFileSystem.getInstance(), new SvnExcludingIgnoredOperation.Filter(project)));
221                 client.doImport(target, url, message, null, !includeIgnored, false, depth);
222               }
223             }
224             catch (SVNException e) {
225               errorMessage.set(e.getMessage());
226             }
227             finally {
228               client.setIgnoreExternals(false);
229               client.setEventHandler(null);
230             }
231           }
232         }, SvnBundle.message("message.title.import"), true, project);
233       }
234     });
235     
236     if (! errorMessage.isNull()) {
237       Messages.showErrorDialog(SvnBundle.message("message.text.cannot.import", errorMessage.get()), SvnBundle.message("message.title.import"));
238     }
239   }
240
241   private static class MyFilter extends DefaultSVNCommitHandler implements ISVNFileFilter {
242     private final LocalFileSystem myLfs;
243     private final SvnExcludingIgnoredOperation.Filter myFilter;
244
245     private MyFilter(LocalFileSystem lfs, SvnExcludingIgnoredOperation.Filter filter) {
246       myLfs = lfs;
247       myFilter = filter;
248     }
249
250     public boolean accept(final File file) throws SVNException {
251       final VirtualFile vf = myLfs.findFileByIoFile(file);
252       return vf != null && myFilter.accept(vf);
253     }
254   }
255
256   public String getVcsName() {
257     return "_Subversion";
258   }
259
260 }
261
262