2 * Copyright 2000-2009 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
.checkin
;
18 import com
.intellij
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.diff
.impl
.patch
.formove
.FilePathComparator
;
21 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
22 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
23 import com
.intellij
.openapi
.progress
.ProgressManager
;
24 import com
.intellij
.openapi
.ui
.MessageType
;
25 import com
.intellij
.openapi
.util
.Computable
;
26 import com
.intellij
.openapi
.util
.io
.FileUtil
;
27 import com
.intellij
.openapi
.vcs
.CheckinProjectPanel
;
28 import com
.intellij
.openapi
.vcs
.FilePath
;
29 import com
.intellij
.openapi
.vcs
.VcsException
;
30 import com
.intellij
.openapi
.vcs
.changes
.Change
;
31 import com
.intellij
.openapi
.vcs
.changes
.ChangeList
;
32 import com
.intellij
.openapi
.vcs
.changes
.ChangesUtil
;
33 import com
.intellij
.openapi
.vcs
.changes
.ContentRevision
;
34 import com
.intellij
.openapi
.vcs
.changes
.ui
.ChangesViewBalloonProblemNotifier
;
35 import com
.intellij
.openapi
.vcs
.checkin
.CheckinEnvironment
;
36 import com
.intellij
.openapi
.vcs
.ui
.Refreshable
;
37 import com
.intellij
.openapi
.vcs
.ui
.RefreshableOnComponent
;
38 import com
.intellij
.openapi
.vfs
.VirtualFile
;
39 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
40 import org
.jetbrains
.annotations
.NonNls
;
41 import org
.jetbrains
.annotations
.Nullable
;
42 import org
.jetbrains
.idea
.svn
.SvnBundle
;
43 import org
.jetbrains
.idea
.svn
.SvnConfiguration
;
44 import org
.jetbrains
.idea
.svn
.SvnUtil
;
45 import org
.jetbrains
.idea
.svn
.SvnVcs
;
46 import org
.tmatesoft
.svn
.core
.SVNCancelException
;
47 import org
.tmatesoft
.svn
.core
.SVNCommitInfo
;
48 import org
.tmatesoft
.svn
.core
.SVNException
;
49 import org
.tmatesoft
.svn
.core
.wc
.*;
55 import java
.util
.List
;
57 public class SvnCheckinEnvironment
implements CheckinEnvironment
{
58 private static final Logger LOG
= Logger
.getInstance("#org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment");
59 private final SvnVcs mySvnVcs
;
61 public SvnCheckinEnvironment(SvnVcs svnVcs
) {
65 public RefreshableOnComponent
createAdditionalOptionsPanel(CheckinProjectPanel panel
) {
66 return new KeepLocksComponent(panel
);
70 public String
getDefaultMessageFor(FilePath
[] filesToCheckin
) {
75 public String
getHelpId() {
80 private List
<VcsException
> commitInt(List
<File
> paths
, final String comment
, final boolean force
, final boolean recursive
) {
81 final List
<VcsException
> exception
= new ArrayList
<VcsException
>();
82 final Collection
<File
> committables
= getCommitables(paths
);
84 final SVNCommitClient committer
= mySvnVcs
.createCommitClient();
86 final ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
87 final Collection
<VirtualFile
> deletedFiles
= new ArrayList
<VirtualFile
>();
88 if (progress
!= null) {
89 committer
.setEventHandler(new ISVNEventHandler() {
90 public void handleEvent(final SVNEvent event
, double p
) {
91 final String path
= SvnUtil
.getPathForProgress(event
);
95 if (event
.getAction() == SVNEventAction
.COMMIT_ADDED
) {
96 progress
.setText2(SvnBundle
.message("progress.text2.adding", path
));
98 else if (event
.getAction() == SVNEventAction
.COMMIT_DELETED
) {
99 @NonNls final String filePath
= "file://" + event
.getFile().getAbsolutePath().replace(File
.separatorChar
, '/');
100 VirtualFile vf
= ApplicationManager
.getApplication().runReadAction(new Computable
<VirtualFile
>() {
101 @Nullable public VirtualFile
compute() {
102 return VirtualFileManager
.getInstance().findFileByUrl(filePath
);
106 deletedFiles
.add(vf
);
108 progress
.setText2(SvnBundle
.message("progress.text2.deleting", path
));
110 else if (event
.getAction() == SVNEventAction
.COMMIT_MODIFIED
) {
111 progress
.setText2(SvnBundle
.message("progress.text2.sending", path
));
113 else if (event
.getAction() == SVNEventAction
.COMMIT_REPLACED
) {
114 progress
.setText2(SvnBundle
.message("progress.text2.replacing", path
));
116 else if (event
.getAction() == SVNEventAction
.COMMIT_DELTA_SENT
) {
117 progress
.setText2(SvnBundle
.message("progress.text2.transmitting.delta", path
));
119 // do not need COMMIT_COMPLETED: same info is get another way
122 public void checkCancelled() throws SVNCancelException
{
124 progress
.checkCanceled();
126 catch(ProcessCanceledException ex
) {
127 throw new SVNCancelException();
133 if (progress
!= null) {
134 doCommit(committables
, progress
, committer
, comment
, force
, recursive
, exception
);
136 else if (ApplicationManager
.getApplication().isDispatchThread()) {
137 ProgressManager
.getInstance().runProcessWithProgressSynchronously(new Runnable() {
139 ProgressIndicator p
= ProgressManager
.getInstance().getProgressIndicator();
140 doCommit(committables
, p
, committer
, comment
, force
, recursive
, exception
);
142 }, SvnBundle
.message("progress.title.commit"), false, mySvnVcs
.getProject());
145 doCommit(committables
, progress
, committer
, comment
, force
, recursive
, exception
);
148 for(VirtualFile f
: deletedFiles
) {
149 f
.putUserData(VirtualFile
.REQUESTOR_MARKER
, this);
154 private void doCommit(Collection
<File
> committables
,
155 ProgressIndicator progress
,
156 SVNCommitClient committer
,
160 List
<VcsException
> exception
) {
161 if (committables
.isEmpty()) {
164 File
[] pathsToCommit
= (File
[])committables
.toArray(new File
[committables
.size()]);
165 boolean keepLocks
= SvnConfiguration
.getInstanceChecked(mySvnVcs
.getProject()).isKeepLocks();
166 SVNCommitPacket
[] commitPackets
= null;
167 SVNCommitInfo
[] results
;
169 commitPackets
= committer
.doCollectCommitItems(pathsToCommit
, keepLocks
, force
, recursive
, true);
170 results
= committer
.doCommit(commitPackets
, keepLocks
, comment
);
171 commitPackets
= null;
173 catch (SVNException e
) {
174 // exception on collecting commitables.
175 exception
.add(new VcsException(e
));
180 if (commitPackets
!= null) {
181 for (int i
= 0; i
< commitPackets
.length
; i
++) {
182 SVNCommitPacket commitPacket
= commitPackets
[i
];
184 commitPacket
.dispose();
186 catch (SVNException e
) {
192 final StringBuffer committedRevisions
= new StringBuffer();
193 for (SVNCommitInfo result
: results
) {
194 if (result
.getErrorMessage() != null) {
195 exception
.add(new VcsException(result
.getErrorMessage().getFullMessage()));
197 else if (result
!= SVNCommitInfo
.NULL
&& result
.getNewRevision() > 0) {
198 if (committedRevisions
.length() > 0) {
199 committedRevisions
.append(", ");
201 committedRevisions
.append(result
.getNewRevision());
204 if (committedRevisions
.length() > 0) {
205 ApplicationManager
.getApplication().invokeLater(new Runnable() {
207 new ChangesViewBalloonProblemNotifier(mySvnVcs
.getProject(),
208 SvnBundle
.message("status.text.comitted.revision", committedRevisions
),
209 MessageType
.INFO
).run();
215 private static class Adder
{
216 private final Collection
<File
> myResult
= new ArrayList
<File
>();
217 private final Set
<String
> myDuplicatesControlSet
= new HashSet
<String
>();
219 public void add(final File file
) {
220 final String path
= file
.getAbsolutePath();
221 if (! myDuplicatesControlSet
.contains(path
)) {
223 myDuplicatesControlSet
.add(path
);
227 public Collection
<File
> getResult() {
232 private Collection
<File
> getCommitables(List
<File
> paths
) {
233 final Adder adder
= new Adder();
235 SVNStatusClient statusClient
= mySvnVcs
.createStatusClient();
236 for (File path
: paths
) {
237 File file
= path
.getAbsoluteFile();
239 if (file
.getParentFile() != null) {
240 addParents(statusClient
, file
.getParentFile(), adder
);
243 return adder
.getResult();
246 private static void addParents(SVNStatusClient statusClient
, File file
, final Adder adder
) {
249 status
= statusClient
.doStatus(file
, false);
251 catch (SVNException e
) {
254 if (status
!= null &&
255 (status
.getContentsStatus() == SVNStatusType
.STATUS_ADDED
||
256 status
.getContentsStatus() == SVNStatusType
.STATUS_REPLACED
)) {
257 // file should be added
259 file
= file
.getParentFile();
261 addParents(statusClient
, file
, adder
);
266 private static List
<File
> collectPaths(final List
<Change
> changes
) {
268 ArrayList
<File
> result
= new ArrayList
<File
>();
270 final Set
<String
> pathesSet
= new HashSet
<String
>();
271 for (Change change
: changes
) {
272 final ContentRevision beforeRevision
= change
.getBeforeRevision();
273 final ContentRevision afterRevision
= change
.getAfterRevision();
274 if (beforeRevision
!= null) {
275 pathesSet
.add(beforeRevision
.getFile().getIOFile().getAbsolutePath());
277 if (afterRevision
!= null) {
278 pathesSet
.add(afterRevision
.getFile().getIOFile().getAbsolutePath());
282 for (String s
: pathesSet
) {
283 result
.add(new File(s
));
288 public String
getCheckinOperationName() {
289 return SvnBundle
.message("checkin.operation.name");
292 public List
<VcsException
> commit(List
<Change
> changes
, String preparedComment
) {
293 return commitInt(collectPaths(changes
), preparedComment
, true, false);
296 public List
<VcsException
> commit(List
<Change
> changes
, String preparedComment
, Object parameters
) {
297 return commit(changes
, preparedComment
);
300 public List
<VcsException
> scheduleMissingFileForDeletion(List
<FilePath
> filePaths
) {
301 List
<VcsException
> exceptions
= new ArrayList
<VcsException
>();
302 final SVNWCClient wcClient
= mySvnVcs
.createWCClient();
304 List
<File
> files
= ChangesUtil
.filePathsToFiles(filePaths
);
305 for (File file
: files
) {
307 wcClient
.doDelete(file
, true, false);
309 catch (SVNException e
) {
310 exceptions
.add(new VcsException(e
));
317 public List
<VcsException
> scheduleUnversionedFilesForAddition(List
<VirtualFile
> files
) {
318 final List
<VcsException
> result
= new ArrayList
<VcsException
>();
319 final SVNWCClient wcClient
= mySvnVcs
.createWCClient();
321 final List
<SVNException
> exceptionList
= scheduleUnversionedFilesForAddition(wcClient
, files
);
322 for (SVNException svnException
: exceptionList
) {
323 result
.add(new VcsException(svnException
));
328 public static List
<SVNException
> scheduleUnversionedFilesForAddition(SVNWCClient wcClient
, List
<VirtualFile
> files
) {
329 return scheduleUnversionedFilesForAddition(wcClient
, files
, false);
332 public static List
<SVNException
> scheduleUnversionedFilesForAddition(SVNWCClient wcClient
, List
<VirtualFile
> files
, final boolean recursive
) {
333 List
<SVNException
> exceptions
= new ArrayList
<SVNException
>();
335 Collections
.sort(files
, FilePathComparator
.getInstance());
337 for (VirtualFile file
: files
) {
339 wcClient
.doAdd(new File(FileUtil
.toSystemDependentName(file
.getPath())), true, false, true, recursive
);
341 catch (SVNException e
) {
349 public boolean keepChangeListAfterCommit(ChangeList changeList
) {
353 private class KeepLocksComponent
implements RefreshableOnComponent
{
354 private final JCheckBox myKeepLocksBox
;
355 private boolean myIsKeepLocks
;
356 private final JPanel myPanel
;
358 public KeepLocksComponent(final Refreshable panel
) {
360 myPanel
= new JPanel(new BorderLayout());
361 myKeepLocksBox
= new JCheckBox(SvnBundle
.message("checkbox.chckin.keep.files.locked"));
362 myKeepLocksBox
.setSelected(myIsKeepLocks
);
364 myPanel
.add(myKeepLocksBox
, BorderLayout
.CENTER
);
367 public JComponent
getComponent() {
371 public boolean isKeepLocks() {
372 return myKeepLocksBox
!= null && myKeepLocksBox
.isSelected();
375 public void refresh() {
378 public void saveState() {
379 mySvnVcs
.getSvnConfiguration().setKeepLocks(isKeepLocks());
382 public void restoreState() {
383 myIsKeepLocks
= mySvnVcs
.getSvnConfiguration().isKeepLocks();