2 * Copyright 2000-2005 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.jetbrains
.idea
.svn
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
20 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
21 import com
.intellij
.openapi
.progress
.ProgressManager
;
22 import com
.intellij
.openapi
.project
.Project
;
23 import com
.intellij
.openapi
.util
.Computable
;
24 import com
.intellij
.openapi
.vcs
.AbstractVcsHelper
;
25 import com
.intellij
.openapi
.vcs
.VcsException
;
26 import com
.intellij
.openapi
.vfs
.VfsUtil
;
27 import com
.intellij
.openapi
.vfs
.VirtualFile
;
28 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
29 import com
.intellij
.openapi
.wm
.WindowManager
;
30 import org
.jetbrains
.annotations
.NonNls
;
31 import org
.jetbrains
.annotations
.Nullable
;
32 import org
.jetbrains
.idea
.svn
.dialogs
.LockDialog
;
33 import org
.tmatesoft
.svn
.core
.SVNException
;
34 import org
.tmatesoft
.svn
.core
.SVNURL
;
35 import org
.tmatesoft
.svn
.core
.wc
.*;
40 public class SvnUtil
{
41 @NonNls public static final String SVN_ADMIN_DIR_NAME
= ".svn";
42 @NonNls public static final String ENTRIES_FILE_NAME
= "entries";
43 @NonNls public static final String PATH_TO_LOCK_FILE
= ".svn/lock";
44 @NonNls public static final String LOCK_FILE_NAME
= "lock";
49 public static Collection
<File
> crawlWCRoots(File path
, SvnWCRootCrawler callback
, ProgressIndicator progress
) {
50 final Collection
<File
> result
= new HashSet
<File
>();
51 File parent
= path
.isFile() || !path
.exists() ? path
.getParentFile() : path
;
52 if (SVNWCUtil
.isVersionedDirectory(parent
)) {
53 if (progress
!= null && progress
.isCanceled()) {
54 throw new ProcessCanceledException();
56 final Collection
<File
> pending
= callback
.handleWorkingCopyRoot(path
, progress
);
57 if (progress
!= null && progress
.isCanceled()) {
58 throw new ProcessCanceledException();
60 for (final File aPending
: pending
) {
61 result
.addAll(crawlWCRoots(aPending
, callback
, progress
));
65 else if (path
.isDirectory()) {
66 if (progress
!= null && progress
.isCanceled()) {
67 throw new ProcessCanceledException();
69 File
[] children
= path
.listFiles();
70 for (int i
= 0; children
!= null && i
< children
.length
; i
++) {
71 if (progress
!= null && progress
.isCanceled()) {
72 throw new ProcessCanceledException();
74 File child
= children
[i
];
75 if (child
.isDirectory()) {
76 result
.addAll(crawlWCRoots(child
, callback
, progress
));
83 public static String
[] getLocationsForModule(final SvnVcs vcs
, File path
, ProgressIndicator progress
) {
84 LocationsCrawler crawler
= new LocationsCrawler(vcs
);
85 crawlWCRoots(path
, crawler
, progress
);
86 return crawler
.getLocations();
89 public static Map
<String
, File
> getLocationInfoForModule(final SvnVcs vcs
, File path
, ProgressIndicator progress
) {
90 final LocationsCrawler crawler
= new LocationsCrawler(vcs
);
91 crawlWCRoots(path
, crawler
, progress
);
92 return crawler
.getLocationInfos();
95 public static void doLockFiles(Project project
, final SvnVcs activeVcs
, final File
[] ioFiles
) throws VcsException
{
96 final String lockMessage
;
98 // TODO[yole]: check for shift pressed
99 if (activeVcs
.getCheckoutOptions().getValue()) {
100 LockDialog dialog
= new LockDialog(project
, true, ioFiles
!= null && ioFiles
.length
> 1);
102 if (!dialog
.isOK()) {
105 lockMessage
= dialog
.getComment();
106 force
= dialog
.isForce();
113 final SVNException
[] exception
= new SVNException
[1];
114 final Collection
<String
> failedLocks
= new ArrayList
<String
>();
115 final int[] count
= new int[]{ioFiles
.length
};
116 final ISVNEventHandler eventHandler
= new ISVNEventHandler() {
117 public void handleEvent(SVNEvent event
, double progress
) {
118 if (event
.getAction() == SVNEventAction
.LOCK_FAILED
) {
119 failedLocks
.add(event
.getErrorMessage() != null ?
120 event
.getErrorMessage().getFullMessage() :
121 event
.getFile().getAbsolutePath());
126 public void checkCancelled() {
130 Runnable command
= new Runnable() {
132 ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
133 SVNWCClient wcClient
;
136 wcClient
= activeVcs
.createWCClient();
137 wcClient
.setEventHandler(eventHandler
);
138 if (progress
!= null) {
139 progress
.setText(SvnBundle
.message("progress.text.locking.files"));
141 for (File ioFile
: ioFiles
) {
142 if (progress
!= null) {
143 progress
.checkCanceled();
146 if (progress
!= null) {
147 progress
.setText2(SvnBundle
.message("progress.text2.processing.file", file
.getName()));
149 wcClient
.doLock(new File
[]{file
}, force
, lockMessage
);
152 catch (SVNException e
) {
158 ProgressManager
.getInstance().runProcessWithProgressSynchronously(command
, SvnBundle
.message("progress.title.lock.files"), false, project
);
159 if (!failedLocks
.isEmpty()) {
160 String
[] failedFiles
= failedLocks
.toArray(new String
[failedLocks
.size()]);
161 List
<VcsException
> exceptions
= new ArrayList
<VcsException
>();
163 for (String file
: failedFiles
) {
164 exceptions
.add(new VcsException(SvnBundle
.message("exception.text.locking.file.failed", file
)));
166 AbstractVcsHelper
.getInstance(project
).showErrors(exceptions
, SvnBundle
.message("message.title.lock.failures"));
169 WindowManager
.getInstance().getStatusBar(project
).setInfo(SvnBundle
.message("message.text.files.locked", count
[0]));
170 if (exception
[0] != null) {
171 throw new VcsException(exception
[0]);
175 public static void doUnlockFiles(Project project
, final SvnVcs activeVcs
, final File
[] ioFiles
) throws VcsException
{
176 final boolean force
= true;
177 final SVNException
[] exception
= new SVNException
[1];
178 final Collection
<String
> failedUnlocks
= new ArrayList
<String
>();
179 final int[] count
= new int[]{ioFiles
.length
};
180 final ISVNEventHandler eventHandler
= new ISVNEventHandler() {
181 public void handleEvent(SVNEvent event
, double progress
) {
182 if (event
.getAction() == SVNEventAction
.UNLOCK_FAILED
) {
183 failedUnlocks
.add(event
.getErrorMessage() != null ?
184 event
.getErrorMessage().getFullMessage() :
185 event
.getFile().getAbsolutePath());
190 public void checkCancelled() {
194 Runnable command
= new Runnable() {
196 ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
197 SVNWCClient wcClient
;
200 wcClient
= activeVcs
.createWCClient();
201 wcClient
.setEventHandler(eventHandler
);
202 if (progress
!= null) {
203 progress
.setText(SvnBundle
.message("progress.text.unlocking.files"));
205 for (File ioFile
: ioFiles
) {
206 if (progress
!= null) {
207 progress
.checkCanceled();
210 if (progress
!= null) {
211 progress
.setText2(SvnBundle
.message("progress.text2.processing.file", file
.getName()));
213 wcClient
.doUnlock(new File
[]{file
}, force
);
216 catch (SVNException e
) {
222 ProgressManager
.getInstance().runProcessWithProgressSynchronously(command
, SvnBundle
.message("progress.title.unlock.files"), false, project
);
223 if (!failedUnlocks
.isEmpty()) {
224 String
[] failedFiles
= failedUnlocks
.toArray(new String
[failedUnlocks
.size()]);
225 List
<VcsException
> exceptions
= new ArrayList
<VcsException
>();
227 for (String file
: failedFiles
) {
228 exceptions
.add(new VcsException(SvnBundle
.message("exception.text.failed.to.unlock.file", file
)));
230 AbstractVcsHelper
.getInstance(project
).showErrors(exceptions
, SvnBundle
.message("message.title.unlock.failures"));
233 WindowManager
.getInstance().getStatusBar(project
).setInfo(SvnBundle
.message("message.text.files.unlocked", count
[0]));
234 if (exception
[0] != null) {
235 throw new VcsException(exception
[0]);
239 private static class LocationsCrawler
implements SvnWCRootCrawler
{
240 private SvnVcs myVcs
;
241 private Map
<String
, File
> myLocations
;
243 public LocationsCrawler(SvnVcs vcs
) {
245 myLocations
= new HashMap
<String
, File
>();
248 public String
[] getLocations() {
249 final Set
<String
> set
= myLocations
.keySet();
250 return set
.toArray(new String
[set
.size()]);
253 public Map
<String
, File
> getLocationInfos() {
254 return Collections
.unmodifiableMap(myLocations
);
257 public Collection
<File
> handleWorkingCopyRoot(File root
, ProgressIndicator progress
) {
258 final Collection
<File
> result
= new HashSet
<File
>();
259 if (progress
!= null) {
260 progress
.setText(SvnBundle
.message("progress.text.discovering.location", root
.getAbsolutePath()));
263 SVNWCClient wcClient
= myVcs
.createWCClient();
264 SVNInfo info
= wcClient
.doInfo(root
, SVNRevision
.WORKING
);
265 if (info
!= null && info
.getURL() != null) {
266 myLocations
.put(info
.getURL().toString(), info
.getFile());
269 catch (SVNException e
) {
277 public static String
getRepositoryUUID(final SvnVcs vcs
, final File file
) {
278 final SVNWCClient client
= vcs
.createWCClient();
280 final SVNInfo info
= client
.doInfo(file
, SVNRevision
.WORKING
);
281 return (info
== null) ?
null : info
.getRepositoryUUID();
282 } catch (SVNException e
) {
288 public static String
getRepositoryUUID(final SvnVcs vcs
, final SVNURL url
) {
289 final SVNWCClient client
= vcs
.createWCClient();
291 final SVNInfo info
= client
.doInfo(url
, SVNRevision
.WORKING
, SVNRevision
.WORKING
);
292 return (info
== null) ?
null : info
.getRepositoryUUID();
293 } catch (SVNException e
) {
299 public static SVNURL
getRepositoryRoot(final SvnVcs vcs
, final File file
) {
300 final SVNWCClient client
= vcs
.createWCClient();
302 final SVNInfo info
= client
.doInfo(file
, SVNRevision
.WORKING
);
303 return (info
== null) ?
null : info
.getRepositoryRootURL();
304 } catch (SVNException e
) {
309 public static boolean isWorkingCopyRoot(final File file
) {
311 return SVNWCUtil
.isWorkingCopyRoot(file
);
312 } catch (SVNException e
) {
318 public static File
getWorkingCopyRoot(final File inFile
) {
320 while ((file
!= null) && (file
.isFile() || (! file
.exists()))) {
321 file
= file
.getParentFile();
329 return SVNWCUtil
.getWorkingCopyRoot(file
, true);
330 } catch (SVNException e
) {
336 public static SVNURL
getWorkingCopyUrl(final SvnVcs vcs
, final File file
) {
338 if(SVNWCUtil
.isWorkingCopyRoot(file
)) {
339 final SVNWCClient client
= vcs
.createWCClient();
340 final SVNInfo info
= client
.doInfo(file
, SVNRevision
.WORKING
);
341 return info
.getURL();
343 } catch (SVNException e
) {
349 public static File
fileFromUrl(final File baseDir
, final String baseUrl
, final String fullUrl
) throws SVNException
{
350 assert fullUrl
.startsWith(baseUrl
);
352 final String part
= fullUrl
.substring(baseUrl
.length()).replace('/', File
.separatorChar
).replace('\\', File
.separatorChar
);
353 return new File(baseDir
, part
);
356 public static VirtualFile
getVirtualFile(final String filePath
) {
357 @NonNls final String path
= VfsUtil
.pathToUrl(filePath
.replace(File
.separatorChar
, '/'));
358 return ApplicationManager
.getApplication().runReadAction(new Computable
<VirtualFile
>() {
360 public VirtualFile
compute() {
361 return VirtualFileManager
.getInstance().findFileByUrl(path
);
367 public static SVNURL
getBranchForUrl(final SvnVcs vcs
, final VirtualFile vcsRoot
, final String urlPath
) {
368 final SvnBranchConfiguration configuration
;
370 final SVNURL url
= SVNURL
.parseURIEncoded(urlPath
);
371 configuration
= SvnBranchConfigurationManager
.getInstance(vcs
.getProject()).get(vcsRoot
);
372 return configuration
.getWorkingBranch(vcs
.getProject(), url
);
374 catch (SVNException e
) {
376 } catch (VcsException e1
) {
382 public static String
getPathForProgress(final SVNEvent event
) {
383 if (event
.getFile() != null) {
384 return event
.getFile().getName();
386 if (event
.getURL() != null) {
387 return event
.getURL().toString();