blob: e2d08b10202eec6160b3c43407721c389c7f8fe3 [file] [log] [blame]
/*
* Copyright 2000-2012 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 com.intellij.cvsSupport2.cvshandlers;
import com.intellij.CvsBundle;
import com.intellij.cvsSupport2.CvsUtil;
import com.intellij.cvsSupport2.actions.cvsContext.CvsLightweightFile;
import com.intellij.cvsSupport2.actions.update.UpdateSettings;
import com.intellij.cvsSupport2.application.CvsEntriesManager;
import com.intellij.cvsSupport2.config.CvsConfiguration;
import com.intellij.cvsSupport2.connections.CvsEnvironment;
import com.intellij.cvsSupport2.cvsExecution.ModalityContext;
import com.intellij.cvsSupport2.cvsoperations.common.*;
import com.intellij.cvsSupport2.cvsoperations.cvsAdd.AddFilesOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsAdd.AddedFileInfo;
import com.intellij.cvsSupport2.cvsoperations.cvsCheckOut.CheckoutFileOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsCheckOut.CheckoutFilesOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsCheckOut.CheckoutProjectOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsCommit.CommitFilesOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsEdit.EditOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsEdit.UneditOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsImport.ImportDetails;
import com.intellij.cvsSupport2.cvsoperations.cvsImport.ImportOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsRemove.RemoveFilesOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsTagOrBranch.BranchOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsTagOrBranch.TagOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsUpdate.UpdateOperation;
import com.intellij.cvsSupport2.cvsoperations.dateOrRevision.RevisionOrDateImpl;
import com.intellij.cvsSupport2.cvsoperations.dateOrRevision.SimpleRevision;
import com.intellij.cvsSupport2.errorHandling.CannotFindCvsRootException;
import com.intellij.cvsSupport2.errorHandling.CvsException;
import com.intellij.cvsSupport2.errorHandling.CvsProcessException;
import com.intellij.cvsSupport2.errorHandling.InvalidModuleDescriptionException;
import com.intellij.cvsSupport2.util.CvsVfsUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.netbeans.lib.cvsclient.admin.Entry;
import org.netbeans.lib.cvsclient.admin.InvalidEntryFormatException;
import org.netbeans.lib.cvsclient.command.CommandAbortedException;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author lesya
*/
public class CommandCvsHandler extends CvsHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.cvsSupport2.cvshandlers.CommandCvsHandler");
protected final CvsOperation myCvsOperation;
private final List<CvsOperation> myPostActivities = new ArrayList<CvsOperation>();
private final boolean myCanBeCanceled;
protected boolean myIsCanceled = false;
private PerformInBackgroundOption myBackgroundOption;
public CommandCvsHandler(String title, CvsOperation cvsOperation, boolean canBeCanceled) {
this(title, cvsOperation, FileSetToBeUpdated.EMPTY, canBeCanceled);
}
public CommandCvsHandler(String title, CvsOperation cvsOperation, FileSetToBeUpdated files, boolean canBeCanceled) {
super(title, files);
myCvsOperation = cvsOperation;
myCanBeCanceled = canBeCanceled;
}
public CommandCvsHandler(String title, CvsOperation cvsOperation, FileSetToBeUpdated files) {
this(title, cvsOperation, files, true);
}
public CommandCvsHandler(String title, CvsOperation cvsOperation) {
this(title, cvsOperation, FileSetToBeUpdated.EMPTY);
}
public CommandCvsHandler(final String title,
final CvsOperation operation,
final FileSetToBeUpdated files,
final PerformInBackgroundOption backgroundOption) {
this(title, operation, files);
myBackgroundOption = backgroundOption;
}
@Override
public boolean login(Project project) {
return loginAll(project);
}
@Override
public boolean canBeCanceled() {
return myCanBeCanceled;
}
@Override
public PerformInBackgroundOption getBackgroundOption(final Project project) {
return myBackgroundOption;
}
@Override protected boolean runInReadThread() {
return myCvsOperation.runInReadThread();
}
public static CvsHandler createCheckoutFileHandler(FilePath[] files,
CvsConfiguration configuration,
@Nullable PerformInBackgroundOption option) {
return new CommandCvsHandler(CvsBundle.message("operation.name.check.out.files"), new CheckoutFilesOperation(files, configuration),
FileSetToBeUpdated.selectedFiles(files),
(option == null) ? PerformInBackgroundOption.DEAF : option);
}
public static CvsHandler createCheckoutHandler(CvsEnvironment environment,
String[] checkoutPath,
final File target,
boolean useAltCheckoutDir,
boolean makeNewFilesReadOnly, final PerformInBackgroundOption option) {
final CheckoutProjectOperation checkoutOperation = CheckoutProjectOperation.create(environment, checkoutPath, target,
useAltCheckoutDir, makeNewFilesReadOnly);
return new CommandCvsHandler(CvsBundle.message("operation.name.check.out.project"), checkoutOperation, FileSetToBeUpdated.allFiles(),
(option == null) ? PerformInBackgroundOption.DEAF : option) {
@Override
public void finish() {
CvsEntriesManager.getInstance().clearAll();
}
};
}
public static CvsHandler createImportHandler(ImportDetails details) {
return new CommandCvsHandler(CvsBundle.message("operation.name.import"), new ImportOperation(details), FileSetToBeUpdated.EMPTY);
}
public static UpdateHandler createUpdateHandler(final FilePath[] files,
UpdateSettings updateSettings,
Project project,
@NotNull UpdatedFiles updatedFiles) {
return new UpdateHandler(files, updateSettings, project, updatedFiles);
}
public static CvsHandler createTagHandler(FilePath[] selectedFiles, String tagName, boolean switchToThisTag,
boolean overrideExisting, boolean makeNewFilesReadOnly, Project project) {
final CompositeOperation operation = new CompositeOperation();
operation.addOperation(new TagOperation(selectedFiles, tagName, false, overrideExisting));
if (switchToThisTag) {
operation.addOperation(new UpdateOperation(selectedFiles, tagName, makeNewFilesReadOnly, project));
}
return new CommandCvsHandler(CvsBundle.message("operation.name.create.tag"), operation,
FileSetToBeUpdated.selectedFiles(selectedFiles));
}
public static CvsHandler createBranchHandler(FilePath[] selectedFiles, String branchName, boolean switchToThisBranch,
boolean overrideExisting, boolean makeNewFilesReadOnly, Project project) {
final CompositeOperation operation = new CompositeOperation();
operation.addOperation(new BranchOperation(selectedFiles, branchName, overrideExisting));
if (switchToThisBranch) {
operation.addOperation(new UpdateOperation(selectedFiles, branchName, makeNewFilesReadOnly, project));
}
return new CommandCvsHandler(CvsBundle.message("operation.name.create.branch"), operation,
FileSetToBeUpdated.selectedFiles(selectedFiles));
}
public static CvsHandler createCommitHandler(FilePath[] selectedFiles,
String commitMessage,
String title,
boolean makeNewFilesReadOnly,
Project project,
final boolean tagFilesAfterCommit,
final String tagName,
@NotNull final List<File> dirsToPrune) {
final CommitFilesOperation operation = new CommitFilesOperation(commitMessage, makeNewFilesReadOnly);
if (selectedFiles != null) {
for (FilePath selectedFile : selectedFiles) {
operation.addFile(selectedFile.getIOFile());
}
}
if (!dirsToPrune.isEmpty()) {
operation.addFinishAction(new Runnable() {
@Override
public void run() {
final IOFilesBasedDirectoryPruner pruner = new IOFilesBasedDirectoryPruner(null);
for(File dir: dirsToPrune) {
pruner.addFile(dir);
}
pruner.execute();
}
});
}
final CommandCvsHandler result = new CommandCvsHandler(title, operation, FileSetToBeUpdated.selectedFiles(selectedFiles));
if (tagFilesAfterCommit) {
result.addOperation(new TagOperation(selectedFiles, tagName, false,
CvsConfiguration.getInstance(project).OVERRIDE_EXISTING_TAG_FOR_PROJECT));
}
return result;
}
public static CvsHandler createAddFilesHandler(final Project project, Collection<AddedFileInfo> addedRoots) {
final AddFilesOperation operation = new AddFilesOperation();
final ArrayList<AddedFileInfo> addedFileInfo = new ArrayList<AddedFileInfo>();
for (final AddedFileInfo info : addedRoots) {
info.clearAllCvsAdminDirectoriesInIncludedDirectories();
addedFileInfo.addAll(info.collectAllIncludedFiles());
}
final ArrayList<VirtualFile> addedFiles = new ArrayList<VirtualFile>();
for (AddedFileInfo info : addedFileInfo) {
addedFiles.add(info.getFile());
operation.addFile(info.getFile(), info.getKeywordSubstitution());
}
return new CommandCvsHandler(CvsBundle.message("action.name.add"), operation,
FileSetToBeUpdated.selectedFiles(VfsUtilCore.toVirtualFileArray(addedFiles)),
VcsConfiguration.getInstance(project).getAddRemoveOption());
}
public static CvsHandler createRemoveFilesHandler(Project project, Collection<File> files) {
final RemoveFilesOperation operation = new RemoveFilesOperation();
for (final File file : files) {
operation.addFile(file.getPath());
}
return new CommandCvsHandler(CvsBundle.message("action.name.remove"), operation,
FileSetToBeUpdated.selectedFiles(getAdminDirectoriesFor(files)),
VcsConfiguration.getInstance(project).getAddRemoveOption());
}
private static VirtualFile[] getAdminDirectoriesFor(Collection<File> files) {
final Collection<VirtualFile> result = new HashSet<VirtualFile>();
for (File file : files) {
final File parentFile = file.getParentFile();
final VirtualFile cvsAdminDirectory = CvsVfsUtil.findFileByIoFile(new File(parentFile, CvsUtil.CVS));
if (cvsAdminDirectory != null) result.add(cvsAdminDirectory);
}
return VfsUtilCore.toVirtualFileArray(result);
}
public static CvsHandler createRestoreFileHandler(final VirtualFile parent,
String name,
boolean makeNewFilesReadOnly) {
final File ioFile = new File(VfsUtilCore.virtualToIoFile(parent), name);
final Entry entry = CvsEntriesManager.getInstance().getEntryFor(parent, name);
final String revision = getRevision(entry);
final CheckoutFileOperation operation =
new CheckoutFileOperation(parent, new SimpleRevision(revision), name, makeNewFilesReadOnly);
final CommandCvsHandler cvsHandler =
new CommandCvsHandler(CvsBundle.message("operation.name.restore"), operation, FileSetToBeUpdated.EMPTY);
operation.addFinishAction(new Runnable() {
@Override
public void run() {
final List<VcsException> errors = cvsHandler.getErrors();
if (errors != null && !errors.isEmpty()) return;
if (entry != null) {
entry.setRevision(revision);
entry.setConflict(CvsUtil.formatDate(new Date(ioFile.lastModified())));
try {
CvsUtil.saveEntryForFile(ioFile, entry);
}
catch (IOException e) {
LOG.error(e);
}
CvsEntriesManager.getInstance().clearCachedEntriesFor(parent);
}
}
});
return cvsHandler;
}
public static CvsHandler createEditHandler(VirtualFile[] selectedFiles, boolean isReservedEdit) {
final EditOperation operation = new EditOperation(isReservedEdit);
operation.addFiles(selectedFiles);
return new CommandCvsHandler(CvsBundle.message("action.name.edit"), operation, FileSetToBeUpdated.selectedFiles(selectedFiles));
}
public static CvsHandler createUneditHandler(VirtualFile[] selectedFiles, boolean makeNewFilesReadOnly) {
final UneditOperation operation = new UneditOperation(makeNewFilesReadOnly);
operation.addFiles(selectedFiles);
return new CommandCvsHandler(CvsBundle.message("operation.name.unedit"), operation, FileSetToBeUpdated.selectedFiles(selectedFiles));
}
public static CvsHandler createRemoveTagAction(FilePath[] selectedFiles, String tagName) {
return new CommandCvsHandler(CvsBundle.message("action.name.delete.tag"), new TagOperation(selectedFiles, tagName, true, false),
FileSetToBeUpdated.EMPTY);
}
@Nullable
private static String getRevision(final Entry entry) {
if (entry == null) {
return null;
}
final String result = entry.getRevision();
if (result == null) return null;
if (StringUtil.startsWithChar(result, '-')) return result.substring(1);
return result;
}
@Override
public boolean isCanceled() {
return myIsCanceled;
}
private boolean loginAll(Project project) {
final Set<CvsEnvironment> allRoots = new HashSet<CvsEnvironment>();
try {
myCvsOperation.appendSelfCvsRootProvider(allRoots);
for (CvsOperation postActivity : myPostActivities) {
postActivity.appendSelfCvsRootProvider(allRoots);
}
}
catch (CannotFindCvsRootException e) {
myErrors.add(new VcsException(e));
return false;
}
final LoginPerformer performer = new LoginPerformer(project, allRoots, new Consumer<VcsException>() {
@Override
public void consume(VcsException e) {
myErrorMessageProcessor.addError(e);
}
});
performer.setForceCheck(true);
return performer.loginAll();
}
@Override
public void internalRun(Project project, final ModalityContext executor, final boolean runInReadAction) {
if (! login(project)) return;
final CvsExecutionEnvironment executionEnvironment = new CvsExecutionEnvironment(myCompositeListener,
getProgressListener(),
myErrorMessageProcessor,
getPostActivityHandler(),
project);
if (! runOperation(executionEnvironment, runInReadAction, myCvsOperation)) return;
onOperationFinished(executor);
while (!myPostActivities.isEmpty()) {
final CvsOperation cvsOperation = myPostActivities.get(0);
if (! runOperation(executionEnvironment, runInReadAction, cvsOperation)) return;
myPostActivities.remove(cvsOperation);
}
}
private boolean runOperation(final CvsExecutionEnvironment executionEnvironment,
final boolean runInReadAction,
final CvsOperation cvsOperation) {
try {
cvsOperation.execute(executionEnvironment, runInReadAction);
return true;
}
catch (VcsException e) {
myErrors.add(e);
}
catch (InvalidModuleDescriptionException ex) {
myErrors.add(new CvsException(ex, ex.getCvsRoot()));
}
catch (InvalidEntryFormatException e) {
myErrors.add(new VcsException(CvsBundle.message("exception.text.entries.file.is.corrupted", e.getEntriesFile())));
}
catch (CvsProcessException ex) {
myErrors.add(new CvsException(ex, cvsOperation.getLastProcessedCvsRoot()));
}
catch (CommandAbortedException ex) {
LOG.error(ex);
myErrors.add(new CvsException(ex, cvsOperation.getLastProcessedCvsRoot()));
}
catch(ProcessCanceledException ex) {
myIsCanceled = true;
}
catch (Exception ex) {
LOG.error(ex);
myErrors.add(new CvsException(ex, myCvsOperation.getLastProcessedCvsRoot()));
}
return false;
}
protected void onOperationFinished(ModalityContext modalityContext) {}
protected void addFileToCheckout(VirtualFile file) {
addOperation(new CheckoutFileOperation(file.getParent(), RevisionOrDateImpl.createOn(file), file.getName(), false));
}
protected void addOperation(CvsOperation operation) {
myPostActivities.add(operation);
}
protected PostCvsActivity getPostActivityHandler() {
return PostCvsActivity.DEAF;
}
@Override
protected int getFilesToProcessCount() {
return myCvsOperation.getFilesToProcessCount();
}
public static CvsHandler createGetFileFromRepositoryHandler(CvsLightweightFile[] cvsLightweightFiles, boolean makeNewFilesReadOnly) {
final CompositeOperation compositeOperation = new CompositeOperation();
final CvsEntriesManager entriesManager = CvsEntriesManager.getInstance();
for (CvsLightweightFile cvsLightweightFile : cvsLightweightFiles) {
final File root = cvsLightweightFile.getRoot();
File workingDirectory = root;
if (workingDirectory == null) continue;
if (cvsLightweightFile.getLocalFile().getParentFile().equals(workingDirectory)) {
workingDirectory = workingDirectory.getParentFile();
}
final String alternativeCheckoutPath = getAlternativeCheckoutPath(cvsLightweightFile, workingDirectory);
final CheckoutProjectOperation checkoutFileOperation = new CheckoutProjectOperation(new String[]{cvsLightweightFile.getModuleName()},
entriesManager.getCvsConnectionSettingsFor(root),
makeNewFilesReadOnly,
workingDirectory,
alternativeCheckoutPath,
true,
null);
compositeOperation.addOperation(checkoutFileOperation);
}
return new CommandCvsHandler(CvsBundle.message("action.name.get.file.from.repository"),
compositeOperation, FileSetToBeUpdated.allFiles(), true);
}
private static String getAlternativeCheckoutPath(CvsLightweightFile cvsLightweightFile, File workingDirectory) {
final File parent = cvsLightweightFile.getLocalFile().getParentFile();
return parent.getAbsolutePath().substring(workingDirectory.getAbsolutePath().length());
}
}