Merge branch 'master' of git.labs.intellij.net:idea/community
[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     final String[] selectedFormat = new String[1];
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         SvnWorkingCopyFormatHolder.setPresetFormat(WorkingCopyFormat.getInstance(selectedFormat[0]));
68         
69         final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
70         final SVNUpdateClient client = SvnVcs.getInstance(project).createUpdateClient();
71         client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), false, progressIndicator));
72         client.setIgnoreExternals(ignoreExternals);
73         try {
74           progressIndicator.setText(SvnBundle.message("progress.text.checking.out", target.getAbsolutePath()));
75           client.doCheckout(SVNURL.parseURIEncoded(url), target, SVNRevision.UNDEFINED, revision, depth, true);
76           progressIndicator.checkCanceled();
77           checkoutSuccessful.set(Boolean.TRUE);
78         }
79         catch (SVNCancelException ignore) {
80         }
81         catch (SVNException e) {
82           exception[0] = e;
83         }
84         finally {
85           client.setIgnoreExternals(false);
86           client.setEventHandler(null);
87           SvnWorkingCopyFormatHolder.setPresetFormat(null);
88         }
89       }
90
91       public void onCancel() {
92         onSuccess();
93       }
94
95       public void onSuccess() {
96         if (exception[0] != null) {
97           Messages.showErrorDialog(SvnBundle.message("message.text.cannot.checkout", exception[0].getMessage()), SvnBundle.message("message.title.check.out"));
98         }
99
100         final VirtualFile vf = RefreshVFsSynchronously.findCreatedFile(target);
101         if (vf != null) {
102           vf.refresh(true, true, new Runnable() {
103             public void run() {
104               ApplicationManager.getApplication().invokeLater(new Runnable() {
105                 public void run() {
106                   notifyListener();
107                 }
108               });
109             }
110           });
111         }
112         else {
113           notifyListener();
114         }
115       }
116
117       private void notifyListener() {
118         notifyRootManagerIfUnderProject(project, target);
119         if (listener != null) {
120           if (!checkoutSuccessful.isNull()) {
121             listener.directoryCheckedOut(target);
122           }
123           listener.checkoutCompleted();
124         }
125       }
126     };
127
128     // allow to select working copy format
129     selectedFormat[0] = promptForWCopyFormat(target, project);
130     if (selectedFormat == null) {
131       // cancelled
132       return;
133     }
134     ProgressManager.getInstance().run(checkoutBackgroundTask);
135   }
136
137   private static void notifyRootManagerIfUnderProject(final Project project, final File directory) {
138     if (project.isDefault()) return;
139     final ProjectLevelVcsManagerEx plVcsManager = ProjectLevelVcsManagerEx.getInstanceChecked(project);
140     final SvnVcs vcs = (SvnVcs) plVcsManager.findVcsByName(SvnVcs.VCS_NAME);
141
142     final VirtualFile[] files = vcs.getSvnFileUrlMapping().getNotFilteredRoots();
143     for (VirtualFile file : files) {
144       try {
145         if (FileUtil.isAncestor(new File(file.getPath()), directory, false)) {
146           // todo: should be done like auto detection
147           plVcsManager.fireDirectoryMappingsChanged();
148           return;
149         }
150       }
151       catch (IOException e) {
152         //
153       }
154     }
155   }
156
157   public static boolean promptForWCFormatAndSelect(final File target, final Project project) {
158     final String result = promptForWCopyFormat(target, project);
159     if (result != null) {
160       SvnWorkingCopyFormatHolder.setPresetFormat(WorkingCopyFormat.getInstance(result));
161     }
162     return result != null;
163   }
164
165   @Nullable
166   private static String promptForWCopyFormat(final File target, final Project project) {
167     String formatMode = null;
168     final Ref<Boolean> wasOk = new Ref<Boolean>();
169     while ((formatMode == null) && (! Boolean.FALSE.equals(wasOk.get()))) {
170       formatMode = SvnFormatSelector.showUpgradeDialog(target, project, true, SvnConfiguration.UPGRADE_AUTO_16, wasOk);
171     }
172     return Boolean.TRUE.equals(wasOk.get()) ? formatMode : null;
173   }
174
175   public static void doExport(final Project project, final File target, final String url, final SVNDepth depth,
176                               final boolean ignoreExternals, final boolean force, final String eolStyle) {
177     try {
178       final SVNException[] exception = new SVNException[1];
179       final SVNUpdateClient client = SvnVcs.getInstance(project).createUpdateClient();
180
181       ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
182         public void run() {
183           ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
184           client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), true, progressIndicator));
185           client.setIgnoreExternals(ignoreExternals);
186           try {
187             progressIndicator.setText(SvnBundle.message("progress.text.export", target.getAbsolutePath()));
188             client.doExport(SVNURL.parseURIEncoded(url), target, SVNRevision.UNDEFINED, SVNRevision.HEAD, eolStyle, force, depth);
189           }
190           catch (SVNException e) {
191             exception[0] = e;
192           }
193           finally {
194             client.setIgnoreExternals(false);
195             client.setEventHandler(null);
196           }
197         }
198       }, SvnBundle.message("message.title.export"), true, project);
199       if (exception[0] != null) {
200         throw exception[0];
201       }
202     }
203     catch (SVNException e1) {
204       Messages.showErrorDialog(SvnBundle.message("message.text.cannot.export", e1.getMessage()), SvnBundle.message("message.title.export"));
205     }
206   }
207
208   public static void doImport(final Project project, final File target, final SVNURL url, final SVNDepth depth,
209                               final boolean includeIgnored, final String message) {
210     final Ref<String> errorMessage = new Ref<String>();
211     final SVNCommitClient client = SvnVcs.getInstance(project).createCommitClient();
212     final String targetPath = FileUtil.toSystemIndependentName(target.getAbsolutePath());
213
214     ExclusiveBackgroundVcsAction.run(project, new Runnable() {
215       public void run() {
216         ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
217           public void run() {
218             ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
219             client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), true, progressIndicator));
220             try {
221               progressIndicator.setText(SvnBundle.message("progress.text.import", target.getAbsolutePath()));
222
223               final VirtualFile targetVf = SvnUtil.getVirtualFile(targetPath);
224               if (targetVf == null) {
225                 errorMessage.set("Can not find file: " + targetPath);
226               } else if (! ExcludedFileIndex.getInstance(project).isInContent(targetVf)) {
227                 // do not pay attention to ignored/excluded settings
228                 client.doImport(target, url, message, null, !includeIgnored, false, depth);
229               } else {
230                 client.setCommitHandler(new MyFilter(LocalFileSystem.getInstance(), new SvnExcludingIgnoredOperation.Filter(project)));
231                 client.doImport(target, url, message, null, !includeIgnored, false, depth);
232               }
233             }
234             catch (SVNException e) {
235               errorMessage.set(e.getMessage());
236             }
237             finally {
238               client.setIgnoreExternals(false);
239               client.setEventHandler(null);
240             }
241           }
242         }, SvnBundle.message("message.title.import"), true, project);
243       }
244     });
245     
246     if (! errorMessage.isNull()) {
247       Messages.showErrorDialog(SvnBundle.message("message.text.cannot.import", errorMessage.get()), SvnBundle.message("message.title.import"));
248     }
249   }
250
251   private static class MyFilter extends DefaultSVNCommitHandler implements ISVNFileFilter {
252     private final LocalFileSystem myLfs;
253     private final SvnExcludingIgnoredOperation.Filter myFilter;
254
255     private MyFilter(LocalFileSystem lfs, SvnExcludingIgnoredOperation.Filter filter) {
256       myLfs = lfs;
257       myFilter = filter;
258     }
259
260     public boolean accept(final File file) throws SVNException {
261       final VirtualFile vf = myLfs.findFileByIoFile(file);
262       return vf != null && myFilter.accept(vf);
263     }
264   }
265
266   public String getVcsName() {
267     return "_Subversion";
268   }
269
270 }
271
272