| /* |
| * Copyright 2000-2011 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.cvsoperations.common; |
| |
| import com.intellij.CvsBundle; |
| import com.intellij.cvsSupport2.CvsUtil; |
| import com.intellij.cvsSupport2.application.CvsEntriesManager; |
| import com.intellij.cvsSupport2.config.CvsApplicationLevelConfiguration; |
| import com.intellij.cvsSupport2.connections.CvsEnvironment; |
| import com.intellij.cvsSupport2.connections.CvsRootProvider; |
| import com.intellij.cvsSupport2.connections.pserver.PServerCvsSettings; |
| import com.intellij.cvsSupport2.cvsIgnore.IgnoreFileFilterBasedOnCvsEntriesManager; |
| import com.intellij.cvsSupport2.cvsoperations.cvsMessages.CvsMessagesListener; |
| import com.intellij.cvsSupport2.cvsoperations.cvsMessages.CvsMessagesTranslator; |
| import com.intellij.cvsSupport2.cvsoperations.cvsMessages.FileMessage; |
| import com.intellij.cvsSupport2.cvsoperations.javacvsSpecificImpls.AdminReaderOnCache; |
| import com.intellij.cvsSupport2.cvsoperations.javacvsSpecificImpls.AdminWriterOnCache; |
| import com.intellij.cvsSupport2.errorHandling.CannotFindCvsRootException; |
| import com.intellij.cvsSupport2.errorHandling.CvsException; |
| import com.intellij.cvsSupport2.javacvsImpl.FileReadOnlyHandler; |
| import com.intellij.cvsSupport2.javacvsImpl.ProjectContentInfoProvider; |
| import com.intellij.cvsSupport2.javacvsImpl.io.*; |
| import com.intellij.cvsSupport2.util.CvsVfsUtil; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.ProgressManager; |
| import com.intellij.openapi.vcs.VcsException; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.netbeans.lib.cvsclient.ClientEnvironment; |
| import org.netbeans.lib.cvsclient.IClientEnvironment; |
| import org.netbeans.lib.cvsclient.IRequestProcessor; |
| import org.netbeans.lib.cvsclient.RequestProcessor; |
| import org.netbeans.lib.cvsclient.admin.Entry; |
| import org.netbeans.lib.cvsclient.admin.IAdminReader; |
| import org.netbeans.lib.cvsclient.admin.IAdminWriter; |
| import org.netbeans.lib.cvsclient.command.*; |
| import org.netbeans.lib.cvsclient.command.update.UpdateFileInfo; |
| import org.netbeans.lib.cvsclient.connection.AuthenticationException; |
| import org.netbeans.lib.cvsclient.connection.IConnection; |
| import org.netbeans.lib.cvsclient.event.*; |
| import org.netbeans.lib.cvsclient.file.FileObject; |
| import org.netbeans.lib.cvsclient.file.IFileSystem; |
| import org.netbeans.lib.cvsclient.file.ILocalFileReader; |
| import org.netbeans.lib.cvsclient.file.ILocalFileWriter; |
| import org.netbeans.lib.cvsclient.progress.IProgressViewer; |
| import org.netbeans.lib.cvsclient.progress.RangeProgressViewer; |
| import org.netbeans.lib.cvsclient.util.IIgnoreFileFilter; |
| |
| import java.io.File; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| public abstract class CvsCommandOperation extends CvsOperation implements IFileInfoListener, |
| IMessageListener, |
| IEntryListener, |
| IModuleExpansionListener, |
| ProjectContentInfoProvider { |
| |
| private static final IAdminReader DEFAULT_ADMIN_READER = new AdminReaderOnCache(); |
| |
| protected final IAdminReader myAdminReader; |
| protected final IAdminWriter myAdminWriter; |
| |
| protected static final Logger LOG = Logger.getInstance("#com.intellij.cvsSupport2.cvsoperations.common.CvsCommandOperation"); |
| private String myLastProcessedCvsRoot; |
| private final UpdatedFilesManager myUpdatedFilesManager = new UpdatedFilesManager(); |
| |
| protected CvsCommandOperation() { |
| this(DEFAULT_ADMIN_READER); |
| } |
| |
| protected CvsCommandOperation(IAdminReader adminReader, IAdminWriter adminWriter) { |
| myAdminReader = adminReader; |
| myAdminWriter = adminWriter; |
| } |
| |
| protected CvsCommandOperation(IAdminReader adminReader) { |
| myAdminReader = adminReader; |
| myAdminWriter = new AdminWriterOnCache(myUpdatedFilesManager, this); |
| } |
| |
| abstract protected Command createCommand(CvsRootProvider root, |
| CvsExecutionEnvironment cvsExecutionEnvironment); |
| |
| @Override |
| public void execute(CvsExecutionEnvironment executionEnvironment, boolean underReadAction) throws VcsException, CommandAbortedException { |
| if (runInExclusiveLock()) { |
| synchronized (CvsOperation.class) { |
| doExecute(executionEnvironment, underReadAction); |
| } |
| } |
| else { |
| doExecute(executionEnvironment, underReadAction); |
| } |
| } |
| |
| @Override |
| public void appendSelfCvsRootProvider(@NotNull Collection<CvsEnvironment> roots) throws CannotFindCvsRootException { |
| roots.addAll(getAllCvsRoots()); |
| } |
| |
| private void doExecute(final CvsExecutionEnvironment executionEnvironment, boolean underReadAction) throws VcsException { |
| final VcsException[] exc = new VcsException[1]; |
| final Runnable action = new Runnable() { |
| @Override |
| public void run() { |
| try { |
| final ReadWriteStatistics statistics = executionEnvironment.getReadWriteStatistics(); |
| final Collection<CvsRootProvider> allCvsRoots; |
| try { |
| allCvsRoots = getAllCvsRoots(); |
| } |
| catch (CannotFindCvsRootException e) { |
| throw createVcsExceptionOn(e, null); |
| } |
| |
| final IProgressViewer progressViewer = new IProgressViewer() { |
| |
| @Override |
| public void setProgress(double value) { |
| final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); |
| if (progressIndicator != null) progressIndicator.setFraction(value); |
| } |
| }; |
| int count = 0; |
| final double step = 1.0 / allCvsRoots.size(); |
| for (CvsRootProvider cvsRootProvider : allCvsRoots) { |
| try { |
| final double lowerBound = step * count; |
| final RangeProgressViewer partialProgress = new RangeProgressViewer(progressViewer, lowerBound, lowerBound + step); |
| myLastProcessedCvsRoot = cvsRootProvider.getCvsRootAsString(); |
| execute(cvsRootProvider, executionEnvironment, statistics, partialProgress); |
| count++; |
| } |
| catch (IOCommandException e) { |
| LOG.info(e); |
| throw createVcsExceptionOn(e.getIOException(), cvsRootProvider.getCvsRootAsString()); |
| } |
| catch (CommandException e) { |
| LOG.info(e); |
| final Exception underlyingException = e.getUnderlyingException(); |
| if (underlyingException != null) { |
| LOG.info(underlyingException); |
| } |
| throw createVcsExceptionOn(underlyingException == null ? e : underlyingException, cvsRootProvider.getCvsRootAsString()); |
| } |
| } |
| } |
| catch (VcsException e) { |
| exc[0] = e; |
| } |
| } |
| }; |
| if (underReadAction) { |
| ApplicationManager.getApplication().runReadAction(action); |
| } else { |
| action.run(); |
| } |
| if (exc[0] != null) throw exc[0]; |
| } |
| |
| private static VcsException createVcsExceptionOn(Exception e, String cvsRoot) { |
| LOG.debug(e); |
| final String message = getMessageFrom(null, e); |
| if (message == null) { |
| return new CvsException(CvsBundle.message("exception.text.unknown.error"), e, cvsRoot); |
| } |
| return new CvsException(message, e, cvsRoot); |
| } |
| |
| |
| private static String getMessageFrom(String initialMessage, Throwable e) { |
| if (e == null) return initialMessage; |
| String result = initialMessage; |
| if (result != null && !result.isEmpty()) return result; |
| result = e.getLocalizedMessage(); |
| if (result == null || result.isEmpty()) result = e.getMessage(); |
| return getMessageFrom(result, e.getCause()); |
| } |
| |
| protected abstract Collection<CvsRootProvider> getAllCvsRoots() throws CannotFindCvsRootException; |
| |
| protected void execute(CvsRootProvider root, |
| final CvsExecutionEnvironment executionEnvironment, |
| ReadWriteStatistics statistics, IProgressViewer progressViewer) |
| throws CommandException, VcsException { |
| final IConnection connection = root.createConnection(statistics); |
| execute(root, executionEnvironment, connection, progressViewer); |
| } |
| |
| public void execute(final CvsRootProvider root, |
| final CvsExecutionEnvironment executionEnvironment, |
| IConnection connection, IProgressViewer progressViewer) throws CommandException { |
| final Command command = createCommand(root, executionEnvironment); |
| |
| if (command == null) return; |
| |
| LOG.assertTrue(connection != null, root.getCvsRootAsString()); |
| |
| final CvsMessagesListener cvsMessagesListener = executionEnvironment.getCvsMessagesListener(); |
| final long start = System.currentTimeMillis(); |
| |
| try { |
| final IClientEnvironment clientEnvironment = createEnvironment(connection, root, |
| myUpdatedFilesManager, |
| executionEnvironment); |
| |
| myUpdatedFilesManager.setCvsFileSystem(clientEnvironment.getCvsFileSystem()); |
| final EventManager eventManager = new EventManager(CvsApplicationLevelConfiguration.getCharset()); |
| final IGlobalOptions globalOptions = command.getGlobalOptions(); |
| |
| |
| final IRequestProcessor requestProcessor = new RequestProcessor(clientEnvironment, |
| globalOptions, |
| eventManager, |
| new StreamLogger(), |
| executionEnvironment.getCvsCommandStopper(), |
| PServerCvsSettings.getTimeoutMillis()); |
| |
| eventManager.addFileInfoListener(this); |
| eventManager.addEntryListener(this); |
| eventManager.addMessageListener(this); |
| eventManager.addModuleExpansionListener(this); |
| |
| |
| final CvsMessagesTranslator cvsMessagesTranslator = new CvsMessagesTranslator(cvsMessagesListener, |
| clientEnvironment.getCvsFileSystem(), |
| myUpdatedFilesManager, |
| root.getCvsRootAsString()); |
| cvsMessagesTranslator.registerTo(eventManager); |
| final CvsEntriesManager cvsEntriesManager = CvsEntriesManager.getInstance(); |
| if (shouldMakeChangesOnTheLocalFileSystem()) { |
| eventManager.addEntryListener(new MergeSupportingEntryListener(clientEnvironment, cvsEntriesManager, myUpdatedFilesManager)); |
| eventManager.addMessageListener(myUpdatedFilesManager); |
| } |
| |
| |
| modifyOptions(command.getGlobalOptions()); |
| final String commandString = composeCommandString(root, command); |
| cvsMessagesListener.commandStarted(commandString); |
| setProgressText(CvsBundle.message("progress.text.command.running.for.file", getOperationName(), root.getCvsRootAsString())); |
| try { |
| command.execute(requestProcessor, eventManager, eventManager, clientEnvironment, progressViewer); |
| } |
| catch (AuthenticationException e) { |
| throw root.processException(new CommandException(e, "Authentication problem")); |
| } |
| cvsMessagesTranslator.operationCompleted(); |
| } |
| catch (CommandException t) { |
| throw root.processException(t); |
| } |
| finally { |
| cvsMessagesListener.commandFinished(composeCommandString(root, command), |
| System.currentTimeMillis() - start); |
| executeFinishActions(); |
| } |
| } |
| |
| @NonNls protected abstract String getOperationName(); |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| private static String composeCommandString(CvsRootProvider root, Command command) { |
| final StringBuilder result = new StringBuilder(); |
| result.append(root.getLocalRoot()); |
| result.append(" cvs "); |
| final GlobalOptions globalOptions = command.getGlobalOptions(); |
| if (globalOptions.isCheckedOutFilesReadOnly()) result.append("-r "); |
| if (globalOptions.isDoNoChanges()) result.append("-n "); |
| if (globalOptions.isNoHistoryLogging()) result.append("-l "); |
| if (globalOptions.isSomeQuiet()) result.append("-q "); |
| result.append(command.getCvsCommandLine()); |
| return result.toString(); |
| } |
| |
| protected boolean shouldMakeChangesOnTheLocalFileSystem() { |
| return true; |
| } |
| |
| protected boolean runInExclusiveLock() { |
| return true; |
| } |
| |
| private static void setProgressText(String text) { |
| final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); |
| if (progressIndicator != null) progressIndicator.setText(text); |
| } |
| |
| private IClientEnvironment createEnvironment(IConnection connection, |
| final CvsRootProvider root, |
| UpdatedFilesManager mergedFilesCollector, |
| CvsExecutionEnvironment cvsExecutionEnv) { |
| final File localRoot = getLocalRootFor(root); |
| final File adminRoot = getAdminRootFor(root); |
| |
| LOG.assertTrue(localRoot != null, getClass().getName()); |
| LOG.assertTrue(adminRoot != null, getClass().getName()); |
| |
| return new ClientEnvironment(connection, |
| localRoot, adminRoot, root.getCvsRoot(), |
| createLocalFileReader(), |
| createLocalFileWriter(root.getCvsRootAsString(), |
| mergedFilesCollector, |
| cvsExecutionEnv), |
| myAdminReader, myAdminWriter, |
| getIgnoreFileFilter(), new FileReadOnlyHandler(), |
| CvsApplicationLevelConfiguration.getCharset()); |
| } |
| |
| protected ILocalFileWriter createLocalFileWriter(String cvsRoot, |
| UpdatedFilesManager mergedFilesCollector, |
| CvsExecutionEnvironment cvsExecutionEnvironment) { |
| return new StoringLineSeparatorsLocalFileWriter(new ReceiveTextFilePreprocessor(createReceivedFileProcessor(mergedFilesCollector, |
| cvsExecutionEnvironment.getPostCvsActivity())), |
| cvsExecutionEnvironment.getErrorProcessor(), |
| myUpdatedFilesManager, |
| cvsRoot, |
| this); |
| } |
| |
| protected ReceivedFileProcessor createReceivedFileProcessor(UpdatedFilesManager mergedFilesCollector, PostCvsActivity postCvsActivity) { |
| return ReceivedFileProcessor.DEFAULT; |
| } |
| |
| protected ILocalFileReader createLocalFileReader() { |
| return new LocalFileReaderBasedOnVFS(new SendTextFilePreprocessor(), this); |
| } |
| |
| protected IIgnoreFileFilter getIgnoreFileFilter() { |
| return new IgnoreFileFilterBasedOnCvsEntriesManager(); |
| } |
| |
| protected File getAdminRootFor(CvsRootProvider root) { |
| return root.getAdminRoot(); |
| } |
| |
| protected File getLocalRootFor(CvsRootProvider root) { |
| return root.getLocalRoot(); |
| } |
| |
| @Override |
| public void fileInfoGenerated(Object info) { |
| if (info instanceof UpdateFileInfo) { |
| final UpdateFileInfo updateFileInfo = ((UpdateFileInfo)info); |
| if (FileMessage.CONFLICT.equals(updateFileInfo.getType())) { |
| CvsUtil.addConflict(updateFileInfo.getFile()); |
| } |
| } |
| } |
| |
| @Override |
| public void gotEntry(FileObject fileObject, Entry entry) { |
| } |
| |
| @Override |
| public void messageSent(String message, final byte[] byteMessage, boolean error, boolean tagged) { |
| } |
| |
| @Override |
| public void moduleExpanded(String module) { |
| |
| } |
| |
| @Override |
| public boolean fileIsUnderProject(final VirtualFile file) { |
| return true; |
| } |
| |
| @Override |
| public boolean fileIsUnderProject(File file) { |
| return true; |
| } |
| |
| @Override |
| public String getLastProcessedCvsRoot() { |
| return myLastProcessedCvsRoot; |
| } |
| |
| private static class MergeSupportingEntryListener implements IEntryListener { |
| private final IClientEnvironment myClientEnvironment; |
| private final CvsEntriesManager myCvsEntriesManager; |
| private final UpdatedFilesManager myUpdatedFilesManager; |
| private final Map<File, Entry> myFileToPreviousEntryMap = new HashMap<File, Entry>(); |
| |
| public MergeSupportingEntryListener(IClientEnvironment clientEnvironment, |
| CvsEntriesManager cvsEntriesManager, |
| UpdatedFilesManager mergedFilesCollector) { |
| myClientEnvironment = clientEnvironment; |
| myCvsEntriesManager = cvsEntriesManager; |
| myUpdatedFilesManager = mergedFilesCollector; |
| } |
| |
| @Override |
| public void gotEntry(FileObject fileObject, Entry entry) { |
| final IFileSystem localFileSystem = myClientEnvironment.getCvsFileSystem().getLocalFileSystem(); |
| final File file = localFileSystem.getFile(fileObject); |
| if (myUpdatedFilesManager.fileIsNotUpdated(file)) { |
| return; |
| } |
| final File parent = file.getParentFile(); |
| final VirtualFile virtualParent = CvsVfsUtil.findFileByIoFile(parent); |
| if (entry != null) { |
| final Entry previousEntry = myFileToPreviousEntryMap.containsKey(file) |
| ? |
| myFileToPreviousEntryMap.get(file) |
| : CvsEntriesManager.getInstance().getCachedEntry(virtualParent, entry.getFileName()); |
| if (previousEntry != null) { |
| myFileToPreviousEntryMap.put(file, previousEntry); |
| if (entry.isResultOfMerge()) { |
| final UpdatedFilesManager.CurrentMergedFileInfo info = myUpdatedFilesManager.getInfo(file); |
| info.registerNewRevision(previousEntry); |
| CvsUtil.saveRevisionForMergedFile(virtualParent, |
| info.getOriginalEntry(), |
| info.getRevisions()); |
| } |
| } |
| } |
| else { |
| myCvsEntriesManager.removeEntryForFile(parent, fileObject.getName()); |
| } |
| if (entry != null) { |
| myCvsEntriesManager.setEntryForFile(virtualParent, entry); |
| } |
| |
| if (entry == null || !entry.isResultOfMerge()) { |
| CvsUtil.removeConflict(file); |
| } |
| } |
| } |
| |
| @Override |
| public void binaryMessageSent(final byte[] bytes) { |
| } |
| } |