blob: 012a870676a01a572770ffecc5200602c1ed6817 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.api.ClientFactory;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider;
import org.jetbrains.idea.svn.dialogs.ShareDialog;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
public class ShareProjectAction extends BasicAction {
protected String getActionName(AbstractVcs vcs) {
return SvnBundle.message("share.directory.action");
}
public void update(AnActionEvent e) {
Presentation presentation = e.getPresentation();
final DataContext dataContext = e.getDataContext();
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if ((project == null) || (ProjectLevelVcsManager.getInstance(project).isBackgroundVcsOperationRunning())) {
presentation.setEnabled(false);
presentation.setVisible(false);
return;
}
VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
if (files == null || files.length == 0) {
presentation.setEnabled(false);
presentation.setVisible(false);
return;
}
boolean enabled = false;
boolean visible = false;
if (files.length == 1 && files [0].isDirectory()) {
visible = true;
if (! SvnStatusUtil.isUnderControl(project, files[0])) {
enabled = true;
}
}
presentation.setEnabled(enabled);
presentation.setVisible(visible);
}
protected boolean isEnabled(Project project, SvnVcs vcs, VirtualFile file) {
return false;
}
protected boolean needsFiles() {
return true;
}
public static boolean share(final Project project, final VirtualFile file) throws VcsException {
return performImpl(project, SvnVcs.getInstance(project), file);
}
protected void perform(final Project project, final SvnVcs activeVcs, final VirtualFile file, DataContext context) throws VcsException {
performImpl(project, activeVcs, file);
}
private static boolean performImpl(final Project project, final SvnVcs activeVcs, final VirtualFile file) throws VcsException {
final ShareDialog shareDialog = new ShareDialog(project, file.getName());
shareDialog.show();
final String parent = shareDialog.getSelectedURL();
if (shareDialog.isOK() && parent != null) {
final Ref<Boolean> actionStarted = new Ref<Boolean>(Boolean.TRUE);
final Exception[] error = new Exception[1];
final ShareDialog.ShareTarget shareTarget = shareDialog.getShareTarget();
final ProgressManager progressManager = ProgressManager.getInstance();
if (ShareDialog.ShareTarget.useSelected.equals(shareTarget)) {
final boolean folderEmpty = checkRemoteFolder(project, activeVcs, parent, progressManager);
if (! folderEmpty) {
final int promptAnswer =
Messages.showYesNoDialog(project, "Remote folder \"" + parent + "\" is not empty.\nDo you want to continue sharing?",
"Share directory", Messages.getWarningIcon());
if (Messages.YES != promptAnswer) return false;
}
}
final WorkingCopyFormat format = SvnCheckoutProvider.promptForWCopyFormat(VfsUtilCore.virtualToIoFile(file), project);
actionStarted.set(format != WorkingCopyFormat.UNKNOWN);
// means operation cancelled
if (format == WorkingCopyFormat.UNKNOWN) {
return true;
}
ExclusiveBackgroundVcsAction.run(project, new Runnable() {
public void run() {
progressManager.runProcessWithProgressSynchronously(new Runnable() {
public void run() {
try {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final File path = new File(file.getPath());
SvnWorkingCopyFormatHolder.setPresetFormat(format);
final SVNURL parenUrl = SVNURL.parseURIEncoded(parent);
final SVNURL checkoutUrl;
final SVNRevision revision;
final String commitText = shareDialog.getCommitText();
if (ShareDialog.ShareTarget.useSelected.equals(shareTarget)) {
checkoutUrl = parenUrl;
revision = SVNRevision.HEAD;
} else if (ShareDialog.ShareTarget.useProjectName.equals(shareTarget)) {
final Pair<SVNRevision, SVNURL> pair = createRemoteFolder(activeVcs, parenUrl, file.getName(), commitText);
revision = pair.getFirst();
checkoutUrl = pair.getSecond();
} else {
final Pair<SVNRevision, SVNURL> pair = createRemoteFolder(activeVcs, parenUrl, file.getName(), commitText);
final Pair<SVNRevision, SVNURL> trunkPair = createRemoteFolder(activeVcs, pair.getSecond(), "trunk", commitText);
checkoutUrl = trunkPair.getSecond();
revision = trunkPair.getFirst();
if (shareDialog.createStandardStructure()) {
createRemoteFolder(activeVcs, pair.getSecond(), "branches", commitText);
createRemoteFolder(activeVcs, pair.getSecond(), "tags", commitText);
}
}
if (indicator != null) {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.directory.checkout.back.progress.text", checkoutUrl.toString()));
}
final ClientFactory factory = SvnCheckoutProvider.getFactory(activeVcs, format);
factory.createCheckoutClient()
.checkout(SvnTarget.fromURL(checkoutUrl), path, revision, Depth.INFINITY, false, false, format, null);
addRecursively(activeVcs, factory, file);
} catch (SVNException e) {
error[0] = e;
}
catch (VcsException e) {
error[0] = e;
} finally {
activeVcs.invokeRefreshSvnRoots();
SvnWorkingCopyFormatHolder.setPresetFormat(null);
}
}
}, SvnBundle.message("share.directory.title"), true, project);
}
});
if (Boolean.TRUE.equals(actionStarted.get())) {
if (error[0] != null) {
throw new VcsException(error[0].getMessage());
}
Messages.showInfoMessage(project, SvnBundle.message("share.directory.info.message", file.getName()),
SvnBundle.message("share.directory.title"));
}
return true;
}
return false;
}
private static boolean checkRemoteFolder(Project project,
final SvnVcs activeVcs,
final String parent,
ProgressManager progressManager) throws VcsException {
final VcsException[] exc = new VcsException[1];
final boolean[] folderEmpty = new boolean[1];
progressManager.runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
try {
folderEmpty[0] = SvnUtil.remoteFolderIsEmpty(activeVcs, parent);
}
catch (VcsException e) {
exc[0] = e;
}
}
}, "Check remote folder contents", false, project);
if (exc[0] != null) {
throw exc[0];
}
return folderEmpty[0];
}
private static Pair<SVNRevision, SVNURL> createRemoteFolder(@NotNull final SvnVcs vcs,
@NotNull final SVNURL parent,
final String folderName,
String commitText) throws VcsException, SVNException {
SVNURL url = parent.appendPath(folderName, false);
final String urlText = url.toString();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.directory.create.dir.progress.text", urlText));
}
String message =
SvnBundle.message("share.directory.commit.message", folderName, ApplicationNamesInfo.getInstance().getFullProductName(), commitText);
SvnTarget target = SvnTarget.fromURL(url);
long revision = vcs.getFactoryFromSettings().createBrowseClient().createDirectory(target, message, false);
return Pair.create(SVNRevision.create(revision), url);
}
@Override
protected void doVcsRefresh(final Project project, final VirtualFile file) {
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(file);
}
private static void addRecursively(@NotNull final SvnVcs activeVcs, @NotNull final ClientFactory factory, final VirtualFile file)
throws VcsException {
final SvnExcludingIgnoredOperation operation = new SvnExcludingIgnoredOperation(activeVcs.getProject(), new SvnExcludingIgnoredOperation.Operation() {
public void doOperation(final VirtualFile virtualFile) throws VcsException {
final File ioFile = new File(virtualFile.getPath());
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.or.import.add.progress.text", virtualFile.getPath()));
}
factory.createAddClient().add(ioFile, Depth.EMPTY, false, false, true, null);
}
}, Depth.INFINITY);
operation.execute(file);
}
protected void batchPerform(Project project, final SvnVcs activeVcs, VirtualFile[] file, DataContext context) throws VcsException {
}
protected boolean isBatchAction() {
return false;
}
}