private static VcsException createMoveTargetExistsError(@NotNull Exception e) { return new VcsException( Arrays.asList( "Target of move operation is already under version control.", "Subversion move had not been performed. ", e.getMessage())); }
private static FilePath[] sortPaths(FilePath[] files, final int sign) { Arrays.sort( files, new Comparator<FilePath>() { @Override public int compare(@NotNull FilePath o1, @NotNull FilePath o2) { return sign * o1.getPath().compareTo(o2.getPath()); } }); return files; }
public List<VirtualFile> gatherPatchFiles(final Collection<VirtualFile> files) { final List<VirtualFile> result = new ArrayList<VirtualFile>(); final LinkedList<VirtualFile> filesQueue = new LinkedList<VirtualFile>(files); while (!filesQueue.isEmpty()) { ProgressManager.checkCanceled(); final VirtualFile file = filesQueue.removeFirst(); if (file.isDirectory()) { filesQueue.addAll(Arrays.asList(file.getChildren())); continue; } if (PatchFileType.NAME.equals(file.getFileType().getName())) { result.add(file); } } return result; }
public static void showDiffForChange( final Change[] changes, int index, final Project project, @NotNull ShowDiffUIContext context) { final Change selected = index >= 0 ? changes[index] : null; /*if (isBinaryDiff(project, changes, index)) { showBinaryDiff(project, changes[index]); return; }*/ showDiffForChange( Arrays.asList(changes), new Condition<Change>() { @Override public boolean value(final Change change) { return selected == null ? false : selected.equals(change); } }, project, context); }
private static boolean checkNotifyBinaryDiff(final Change selectedChange) { final ContentRevision beforeRevision = selectedChange.getBeforeRevision(); final ContentRevision afterRevision = selectedChange.getAfterRevision(); if (beforeRevision instanceof BinaryContentRevision && afterRevision instanceof BinaryContentRevision) { try { byte[] beforeContent = ((BinaryContentRevision) beforeRevision).getBinaryContent(); byte[] afterContent = ((BinaryContentRevision) afterRevision).getBinaryContent(); if (Arrays.equals(beforeContent, afterContent)) { Messages.showInfoMessage( VcsBundle.message("message.text.binary.versions.are.identical"), VcsBundle.message("message.title.diff")); } else { Messages.showInfoMessage( VcsBundle.message("message.text.binary.versions.are.different"), VcsBundle.message("message.title.diff")); } } catch (VcsException e) { Messages.showInfoMessage(e.getMessage(), VcsBundle.message("message.title.diff")); } return true; } return false; }
@Override public List<AnAction> getAdditionalActionsForLocalChange() { return Arrays.<AnAction>asList(new ShowPropertiesDiffWithLocalAction()); }
@SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"}) public class SvnVcs extends AbstractVcs<CommittedChangeList> { private static final String KEEP_CONNECTIONS_KEY = "svn.keep.connections"; private static final Logger REFRESH_LOG = Logger.getInstance("#svn_refresh"); private static final int ourLogUsualInterval = 20 * 1000; private static final int ourLogRareInterval = 30 * 1000; private static final Set<SVNErrorCode> ourLogRarely = new HashSet<SVNErrorCode>( Arrays.asList( new SVNErrorCode[] { SVNErrorCode.WC_UNSUPPORTED_FORMAT, SVNErrorCode.WC_CORRUPT, SVNErrorCode.WC_CORRUPT_TEXT_BASE, SVNErrorCode.WC_NOT_FILE, SVNErrorCode.WC_NOT_DIRECTORY, SVNErrorCode.WC_PATH_NOT_FOUND })); private static final Logger LOG = wrapLogger(Logger.getInstance("org.jetbrains.idea.svn.SvnVcs")); @NonNls public static final String VCS_NAME = "svn"; private static final VcsKey ourKey = createKey(VCS_NAME); public static final Topic<Runnable> WC_CONVERTED = new Topic<Runnable>("WC_CONVERTED", Runnable.class); private final Map<String, Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>> myPropertyCache = new SoftHashMap<String, Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>>(); private SvnIdeaRepositoryPoolManager myPool; private final SvnConfiguration myConfiguration; private final SvnEntriesFileListener myEntriesFileListener; private CheckinEnvironment myCheckinEnvironment; private RollbackEnvironment myRollbackEnvironment; private UpdateEnvironment mySvnUpdateEnvironment; private UpdateEnvironment mySvnIntegrateEnvironment; private VcsHistoryProvider mySvnHistoryProvider; private AnnotationProvider myAnnotationProvider; private DiffProvider mySvnDiffProvider; private final VcsShowConfirmationOption myAddConfirmation; private final VcsShowConfirmationOption myDeleteConfirmation; private EditFileProvider myEditFilesProvider; private SvnCommittedChangesProvider myCommittedChangesProvider; private final VcsShowSettingOption myCheckoutOptions; private static final SSLExceptionsHelper myHelper = new SSLExceptionsHelper(); private ChangeProvider myChangeProvider; private MergeProvider myMergeProvider; private final WorkingCopiesContent myWorkingCopiesContent; @NonNls public static final String LOG_PARAMETER_NAME = "javasvn.log"; @NonNls public static final String TRACE_NATIVE_CALLS = "javasvn.log.native"; public static final String pathToEntries = SvnUtil.SVN_ADMIN_DIR_NAME + File.separatorChar + SvnUtil.ENTRIES_FILE_NAME; public static final String pathToDirProps = SvnUtil.SVN_ADMIN_DIR_NAME + File.separatorChar + SvnUtil.DIR_PROPS_FILE_NAME; private final SvnChangelistListener myChangeListListener; private SvnCopiesRefreshManager myCopiesRefreshManager; private SvnFileUrlMappingImpl myMapping; private final MyFrameStateListener myFrameStateListener; // Consumer<Boolean> public static final Topic<Consumer> ROOTS_RELOADED = new Topic<Consumer>("ROOTS_RELOADED", Consumer.class); private VcsListener myVcsListener; private SvnBranchPointsCalculator mySvnBranchPointsCalculator; private final RootsToWorkingCopies myRootsToWorkingCopies; private final SvnAuthenticationNotifier myAuthNotifier; private static RareLogger.LogFilter[] ourLogFilters; private final SvnLoadedBrachesStorage myLoadedBranchesStorage; public static final String SVNKIT_HTTP_SSL_PROTOCOLS = "svnkit.http.sslProtocols"; private static boolean ourSSLProtocolsExplicitlySet = false; private final SvnExecutableChecker myChecker; public static final Processor<Exception> ourBusyExceptionProcessor = new Processor<Exception>() { @Override public boolean process(Exception e) { if (e instanceof SVNException) { final SVNErrorCode errorCode = ((SVNException) e).getErrorMessage().getErrorCode(); if (SVNErrorCode.WC_LOCKED.equals(errorCode)) { return true; } else if (SVNErrorCode.SQLITE_ERROR.equals(errorCode)) { Throwable cause = ((SVNException) e).getErrorMessage().getCause(); if (cause instanceof SqlJetException) { return SqlJetErrorCode.BUSY.equals(((SqlJetException) cause).getErrorCode()); } } } return false; } }; public void checkCommandLineVersion() { myChecker.checkExecutableAndNotifyIfNeeded(); } static { System.setProperty("svnkit.log.native.calls", "true"); final JavaSVNDebugLogger logger = new JavaSVNDebugLogger( Boolean.getBoolean(LOG_PARAMETER_NAME), Boolean.getBoolean(TRACE_NATIVE_CALLS), LOG); SVNDebugLog.setDefaultLog(logger); SVNJNAUtil.setJNAEnabled(true); SvnHttpAuthMethodsDefaultChecker.check(); SVNAdminAreaFactory.setSelector(new SvnFormatSelector()); DAVRepositoryFactory.setup(); SVNRepositoryFactoryImpl.setup(); FSRepositoryFactory.setup(); // non-optimized writing is fast enough on Linux/MacOS, and somewhat more reliable if (SystemInfo.isWindows) { SVNAdminArea14.setOptimizedWritingEnabled(true); } if (!SVNJNAUtil.isJNAPresent()) { LOG.warn("JNA is not found by svnkit library"); } initLogFilters(); ourSSLProtocolsExplicitlySet = System.getProperty(SVNKIT_HTTP_SSL_PROTOCOLS) != null; } public static boolean isSSLProtocolExplicitlySet() { return ourSSLProtocolsExplicitlySet; } public SvnVcs( final Project project, MessageBus bus, SvnConfiguration svnConfiguration, final SvnLoadedBrachesStorage storage) { super(project, VCS_NAME); myLoadedBranchesStorage = storage; LOG.debug("ct"); myRootsToWorkingCopies = new RootsToWorkingCopies(this); myConfiguration = svnConfiguration; myAuthNotifier = new SvnAuthenticationNotifier(this); dumpFileStatus(FileStatus.ADDED); dumpFileStatus(FileStatus.DELETED); dumpFileStatus(FileStatus.MERGE); dumpFileStatus(FileStatus.MODIFIED); dumpFileStatus(FileStatus.NOT_CHANGED); dumpFileStatus(FileStatus.UNKNOWN); dumpFileStatus(SvnFileStatus.REPLACED); dumpFileStatus(SvnFileStatus.EXTERNAL); dumpFileStatus(SvnFileStatus.OBSTRUCTED); refreshSSLProperty(); final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project); myAddConfirmation = vcsManager.getStandardConfirmation(VcsConfiguration.StandardConfirmation.ADD, this); myDeleteConfirmation = vcsManager.getStandardConfirmation(VcsConfiguration.StandardConfirmation.REMOVE, this); myCheckoutOptions = vcsManager.getStandardOption(VcsConfiguration.StandardOption.CHECKOUT, this); if (myProject.isDefault()) { myChangeListListener = null; myEntriesFileListener = null; } else { myEntriesFileListener = new SvnEntriesFileListener(project); upgradeIfNeeded(bus); myChangeListListener = new SvnChangelistListener(myProject, this); myVcsListener = new VcsListener() { @Override public void directoryMappingChanged() { invokeRefreshSvnRoots(); } }; } myFrameStateListener = project.isDefault() ? null : new MyFrameStateListener( ChangeListManager.getInstance(project), VcsDirtyScopeManager.getInstance(project)); myWorkingCopiesContent = new WorkingCopiesContent(this); // remove used some time before old notification group ids correctNotificationIds(); myChecker = new SvnExecutableChecker(myProject); myConfiguration.getAuthenticationManager(this).setHelper(myHelper); } private void correctNotificationIds() { boolean notEmpty = NotificationsConfigurationImpl.getNotificationsConfigurationImpl() .isRegistered("SVN_NO_JNA") || NotificationsConfigurationImpl.getNotificationsConfigurationImpl() .isRegistered("SVN_NO_CRYPT32") || NotificationsConfigurationImpl.getNotificationsConfigurationImpl() .isRegistered("SubversionId"); if (notEmpty) { NotificationsConfigurationImpl.remove("SVN_NO_JNA", "SVN_NO_CRYPT32", "SubversionId"); NotificationsConfiguration.getNotificationsConfiguration() .register(getDisplayName(), NotificationDisplayType.BALLOON); } } public void postStartup() { if (myProject.isDefault()) return; myCopiesRefreshManager = new SvnCopiesRefreshManager((SvnFileUrlMappingImpl) getSvnFileUrlMapping()); if (!myConfiguration.isCleanupRun()) { ApplicationManager.getApplication() .invokeLater( new Runnable() { @Override public void run() { cleanup17copies(); myConfiguration.setCleanupRun(true); } }, ModalityState.NON_MODAL, myProject.getDisposed()); } else { invokeRefreshSvnRoots(); } myWorkingCopiesContent.activate(); } private void cleanup17copies() { final Runnable callCleanupWorker = new Runnable() { public void run() { new CleanupWorker( new VirtualFile[] {}, myProject, "action.Subversion.cleanup.progress.title") { @Override protected void chanceToFillRoots() { final List<WCInfo> infos = getAllWcInfos(); final LocalFileSystem lfs = LocalFileSystem.getInstance(); final List<VirtualFile> roots = new ArrayList<VirtualFile>(infos.size()); for (WCInfo info : infos) { if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(info.getFormat())) { final VirtualFile file = lfs.refreshAndFindFileByIoFile(new File(info.getPath())); if (file == null) { LOG.info("Wasn't able to find virtual file for wc root: " + info.getPath()); } else { roots.add(file); } } } myRoots = roots.toArray(new VirtualFile[roots.size()]); } }.execute(); } }; myCopiesRefreshManager.waitRefresh( new Runnable() { @Override public void run() { ApplicationManager.getApplication().invokeLater(callCleanupWorker, ModalityState.any()); } }); } public void invokeRefreshSvnRoots() { REFRESH_LOG.debug("refresh: ", new Throwable()); if (myCopiesRefreshManager != null) { myCopiesRefreshManager.asynchRequest(); } } @Override public boolean checkImmediateParentsBeforeCommit() { return true; } private void upgradeIfNeeded(final MessageBus bus) { final MessageBusConnection connection = bus.connect(); connection.subscribe( ChangeListManagerImpl.LISTS_LOADED, new LocalChangeListsLoadedListener() { @Override public void processLoadedLists(final List<LocalChangeList> lists) { if (lists.isEmpty()) return; SvnConfiguration.SvnSupportOptions supportOptions = null; try { ChangeListManager.getInstance(myProject) .setReadOnly(SvnChangeProvider.ourDefaultListName, true); supportOptions = myConfiguration.getSupportOptions(myProject); if (!supportOptions.changeListsSynchronized()) { processChangeLists(lists); } } catch (ProcessCanceledException e) { // } finally { if (supportOptions != null) { supportOptions.upgrade(); } } connection.disconnect(); } }); } public void processChangeLists(final List<LocalChangeList> lists) { final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstanceChecked(myProject); plVcsManager.startBackgroundVcsOperation(); try { final SVNChangelistClient client = createChangelistClient(); for (LocalChangeList list : lists) { if (!list.isDefault()) { final Collection<Change> changes = list.getChanges(); for (Change change : changes) { correctListForRevision( plVcsManager, change.getBeforeRevision(), client, list.getName()); correctListForRevision(plVcsManager, change.getAfterRevision(), client, list.getName()); } } } } finally { final Application appManager = ApplicationManager.getApplication(); if (appManager.isDispatchThread()) { appManager.executeOnPooledThread( new Runnable() { @Override public void run() { plVcsManager.stopBackgroundVcsOperation(); } }); } else { plVcsManager.stopBackgroundVcsOperation(); } } } private static void correctListForRevision( final ProjectLevelVcsManager plVcsManager, final ContentRevision revision, final SVNChangelistClient client, final String name) { if (revision != null) { final FilePath path = revision.getFile(); final AbstractVcs vcs = plVcsManager.getVcsFor(path); if (vcs != null && VCS_NAME.equals(vcs.getName())) { try { client.doAddToChangelist(new File[] {path.getIOFile()}, SVNDepth.EMPTY, name, null); } catch (SVNException e) { // left in default list } } } } @Override public void activate() { createPool(); final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); if (!myProject.isDefault()) { ChangeListManager.getInstance(myProject).addChangeListListener(myChangeListListener); vcsManager.addVcsListener(myVcsListener); } SvnApplicationSettings.getInstance().svnActivated(); if (myEntriesFileListener != null) { VirtualFileManager.getInstance().addVirtualFileListener(myEntriesFileListener); } // this will initialize its inner listener for committed changes upload LoadedRevisionsCache.getInstance(myProject); FrameStateManager.getInstance().addListener(myFrameStateListener); myAuthNotifier.init(); mySvnBranchPointsCalculator = new SvnBranchPointsCalculator(myProject); mySvnBranchPointsCalculator.activate(); if (SystemInfo.isWindows) { if (!SVNJNAUtil.isJNAPresent()) { Notifications.Bus.notify( new Notification( getDisplayName(), "Subversion plugin: no JNA", "A problem with JNA initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject); } else if (!SVNJNAUtil.isWinCryptEnabled()) { Notifications.Bus.notify( new Notification( getDisplayName(), "Subversion plugin: no encryption", "A problem with encryption module (Crypt32.dll) initialization for svnkit library. Encryption is not available.", NotificationType.WARNING), NotificationDisplayType.BALLOON, myProject); } } final SvnConfiguration.UseAcceleration accelerationType = SvnConfiguration.getInstance(myProject).myUseAcceleration; if (SvnConfiguration.UseAcceleration.javaHL.equals(accelerationType)) { CheckJavaHL.runtimeCheck(myProject); } else if (SvnConfiguration.UseAcceleration.commandLine.equals(accelerationType) && !ApplicationManager.getApplication().isHeadlessEnvironment()) { myChecker.checkExecutableAndNotifyIfNeeded(); } // do one time after project loaded StartupManager.getInstance(myProject) .runWhenProjectIsInitialized( new DumbAwareRunnable() { @Override public void run() { postStartup(); // for IDEA, it takes 2 minutes - and anyway this can be done in background, no // sense... // once it could be mistaken about copies for 2 minutes on start... /*if (! myMapping.getAllWcInfos().isEmpty()) { invokeRefreshSvnRoots(); return; } ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { public void run() { myCopiesRefreshManager.getCopiesRefresh().ensureInit(); } }, SvnBundle.message("refreshing.working.copies.roots.progress.text"), true, myProject);*/ } }); vcsManager.addVcsListener(myRootsToWorkingCopies); myLoadedBranchesStorage.activate(); } private static void initLogFilters() { if (ourLogFilters != null) return; ourLogFilters = new RareLogger.LogFilter[] { new RareLogger.LogFilter() { @Override public Object getKey( @NotNull org.apache.log4j.Level level, @NonNls String message, @Nullable Throwable t, @NonNls String... details) { SVNException svnExc = null; if (t instanceof SVNException) { svnExc = (SVNException) t; } else if (t instanceof VcsException && t.getCause() instanceof SVNException) { svnExc = (SVNException) t.getCause(); } if (svnExc != null) { // only filter a few cases if (ourLogRarely.contains(svnExc.getErrorMessage().getErrorCode())) { return svnExc.getErrorMessage().getErrorCode(); } } return null; } @Override @NotNull public Integer getAllowedLoggingInterval( org.apache.log4j.Level level, String message, Throwable t, String[] details) { SVNException svnExc = null; if (t instanceof SVNException) { svnExc = (SVNException) t; } else if (t instanceof VcsException && t.getCause() instanceof SVNException) { svnExc = (SVNException) t.getCause(); } if (svnExc != null) { if (ourLogRarely.contains(svnExc.getErrorMessage().getErrorCode())) { return ourLogRareInterval; } else { return ourLogUsualInterval; } } return 0; } } }; } public static Logger wrapLogger(final Logger logger) { initLogFilters(); return RareLogger.wrap(logger, Boolean.getBoolean("svn.logger.fairsynch"), ourLogFilters); } public RootsToWorkingCopies getRootsToWorkingCopies() { return myRootsToWorkingCopies; } public SvnAuthenticationNotifier getAuthNotifier() { return myAuthNotifier; } @Override public void deactivate() { FrameStateManager.getInstance().removeListener(myFrameStateListener); final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); if (myVcsListener != null) { vcsManager.removeVcsListener(myVcsListener); } if (myEntriesFileListener != null) { VirtualFileManager.getInstance().removeVirtualFileListener(myEntriesFileListener); } SvnApplicationSettings.getInstance().svnDeactivated(); if (myCommittedChangesProvider != null) { myCommittedChangesProvider.deactivate(); } if (myChangeListListener != null && !myProject.isDefault()) { ChangeListManager.getInstance(myProject).removeChangeListListener(myChangeListListener); } vcsManager.removeVcsListener(myRootsToWorkingCopies); myRootsToWorkingCopies.clear(); myAuthNotifier.stop(); myAuthNotifier.clear(); mySvnBranchPointsCalculator.deactivate(); mySvnBranchPointsCalculator = null; myWorkingCopiesContent.deactivate(); myLoadedBranchesStorage.deactivate(); myPool.dispose(); myPool = null; } public VcsShowConfirmationOption getAddConfirmation() { return myAddConfirmation; } public VcsShowConfirmationOption getDeleteConfirmation() { return myDeleteConfirmation; } public VcsShowSettingOption getCheckoutOptions() { return myCheckoutOptions; } @Override public EditFileProvider getEditFileProvider() { if (myEditFilesProvider == null) { myEditFilesProvider = new SvnEditFileProvider(this); } return myEditFilesProvider; } @Override @NotNull public ChangeProvider getChangeProvider() { if (myChangeProvider == null) { myChangeProvider = new SvnChangeProvider(this); } return myChangeProvider; } public SVNRepository createRepository(String url) throws SVNException { SVNRepository repos = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url)); repos.setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); repos.setTunnelProvider(myConfiguration.getOptions(myProject)); return repos; } public SVNRepository createRepository(SVNURL url) throws SVNException { SVNRepository repos = SVNRepositoryFactory.create(url); repos.setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); repos.setTunnelProvider(myConfiguration.getOptions(myProject)); return repos; } private void createPool() { if (myPool != null) return; final String property = System.getProperty(KEEP_CONNECTIONS_KEY); final boolean keep; boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); // pool variant by default if (StringUtil.isEmptyOrSpaces(property) || unitTestMode) { keep = !unitTestMode; // default } else { keep = Boolean.getBoolean(KEEP_CONNECTIONS_KEY); } myPool = new SvnIdeaRepositoryPoolManager( false, myConfiguration.getAuthenticationManager(this), myConfiguration.getOptions(myProject)); } @NotNull private ISVNRepositoryPool getPool() { if (myProject.isDisposed()) { throw new ProcessCanceledException(); } if (myPool == null) { createPool(); } return myPool; } public SVNUpdateClient createUpdateClient() { final SVNUpdateClient client = new SVNUpdateClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNUpdateClient createUpdateClient(@NotNull ISVNAuthenticationManager manager) { final SVNUpdateClient client = new SVNUpdateClient(getPool(), myConfiguration.getOptions(myProject)); client.getOperationsFactory().setAuthenticationManager(manager); return client; } public SVNStatusClient createStatusClient() { SVNStatusClient client = new SVNStatusClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); client.setIgnoreExternals(false); return client; } public SVNWCClient createWCClient() { final SVNWCClient client = new SVNWCClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNWCClient createWCClient(@NotNull ISVNAuthenticationManager manager) { final SVNWCClient client = new SVNWCClient(getPool(), myConfiguration.getOptions(myProject)); client.getOperationsFactory().setAuthenticationManager(manager); return client; } public SVNCopyClient createCopyClient() { final SVNCopyClient client = new SVNCopyClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNMoveClient createMoveClient() { final SVNMoveClient client = new SVNMoveClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNLogClient createLogClient() { final SVNLogClient client = new SVNLogClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNLogClient createLogClient(@NotNull ISVNAuthenticationManager manager) { final SVNLogClient client = new SVNLogClient(getPool(), myConfiguration.getOptions(myProject)); client.getOperationsFactory().setAuthenticationManager(manager); return client; } public SVNCommitClient createCommitClient() { final SVNCommitClient client = new SVNCommitClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNDiffClient createDiffClient() { final SVNDiffClient client = new SVNDiffClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public SVNChangelistClient createChangelistClient() { final SVNChangelistClient client = new SVNChangelistClient(getPool(), myConfiguration.getOptions(myProject)); client .getOperationsFactory() .setAuthenticationManager(myConfiguration.getAuthenticationManager(this)); return client; } public ISVNOptions getSvnOptions() { return myConfiguration.getOptions(myProject); } public ISVNAuthenticationManager getSvnAuthenticationManager() { return myConfiguration.getAuthenticationManager(this); } void dumpFileStatus(FileStatus fs) { if (LOG.isDebugEnabled()) { LOG.debug( "FileStatus:" + fs.getText() + " " + fs.getColor() + " " + " " + fs.getClass().getName()); } } @Override public UpdateEnvironment getIntegrateEnvironment() { if (mySvnIntegrateEnvironment == null) { mySvnIntegrateEnvironment = new SvnIntegrateEnvironment(this); } return mySvnIntegrateEnvironment; } @Override public UpdateEnvironment createUpdateEnvironment() { if (mySvnUpdateEnvironment == null) { mySvnUpdateEnvironment = new SvnUpdateEnvironment(this); } return mySvnUpdateEnvironment; } @Override public String getDisplayName() { LOG.debug("getDisplayName"); return "Subversion"; } @Override public Configurable getConfigurable() { LOG.debug("createConfigurable"); return new SvnConfigurable(myProject); } public SvnConfiguration getSvnConfiguration() { return myConfiguration; } public static SvnVcs getInstance(Project project) { return (SvnVcs) ProjectLevelVcsManager.getInstance(project).findVcsByName(VCS_NAME); } @Override @NotNull public CheckinEnvironment createCheckinEnvironment() { if (myCheckinEnvironment == null) { myCheckinEnvironment = new SvnCheckinEnvironment(this); } return myCheckinEnvironment; } @Override @NotNull public RollbackEnvironment createRollbackEnvironment() { if (myRollbackEnvironment == null) { myRollbackEnvironment = new SvnRollbackEnvironment(this); } return myRollbackEnvironment; } @Override public VcsHistoryProvider getVcsHistoryProvider() { // no heavy state, but it would be useful to have place to keep state in -> do not reuse // instance return new SvnHistoryProvider(this); } @Override public VcsHistoryProvider getVcsBlockHistoryProvider() { return getVcsHistoryProvider(); } @Override public AnnotationProvider getAnnotationProvider() { if (myAnnotationProvider == null) { myAnnotationProvider = new SvnAnnotationProvider(this); } return myAnnotationProvider; } @Override public DiffProvider getDiffProvider() { if (mySvnDiffProvider == null) { mySvnDiffProvider = new SvnDiffProvider(this); } return mySvnDiffProvider; } private static Trinity<Long, Long, Long> getTimestampForPropertiesChange( final File ioFile, final boolean isDir) { final File dir = isDir ? ioFile : ioFile.getParentFile(); final String relPath = SVNAdminUtil.getPropPath( ioFile.getName(), isDir ? SVNNodeKind.DIR : SVNNodeKind.FILE, false); final String relPathBase = SVNAdminUtil.getPropBasePath( ioFile.getName(), isDir ? SVNNodeKind.DIR : SVNNodeKind.FILE, false); final String relPathRevert = SVNAdminUtil.getPropRevertPath( ioFile.getName(), isDir ? SVNNodeKind.DIR : SVNNodeKind.FILE, false); return new Trinity<Long, Long, Long>( new File(dir, relPath).lastModified(), new File(dir, relPathBase).lastModified(), new File(dir, relPathRevert).lastModified()); } private static boolean trinitiesEqual( final Trinity<Long, Long, Long> t1, final Trinity<Long, Long, Long> t2) { if (t2.first == 0 && t2.second == 0 && t2.third == 0) return false; return t1.equals(t2); } @Nullable public SVNPropertyValue getPropertyWithCaching(final VirtualFile file, final String propName) throws SVNException { Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>> cachedMap = myPropertyCache.get(keyForVf(file)); final Pair<SVNPropertyValue, Trinity<Long, Long, Long>> cachedValue = cachedMap == null ? null : cachedMap.get(propName); final File ioFile = new File(file.getPath()); final Trinity<Long, Long, Long> tsTrinity = getTimestampForPropertiesChange(ioFile, file.isDirectory()); if (cachedValue != null) { // zero means that a file was not found if (trinitiesEqual(cachedValue.getSecond(), tsTrinity)) { return cachedValue.getFirst(); } } final SVNPropertyData value = createWCClient().doGetProperty(ioFile, propName, SVNRevision.WORKING, SVNRevision.WORKING); final SVNPropertyValue propValue = value == null ? null : value.getValue(); if (cachedMap == null) { cachedMap = new HashMap<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>(); myPropertyCache.put(keyForVf(file), cachedMap); } cachedMap.put( propName, new Pair<SVNPropertyValue, Trinity<Long, Long, Long>>(propValue, tsTrinity)); return propValue; } @Override public boolean fileExistsInVcs(FilePath path) { File file = path.getIOFile(); try { SVNStatus status = createStatusClient().doStatus(file, false); if (status != null) { if (svnStatusIs(status, SVNStatusType.STATUS_ADDED)) { return status.isCopied(); } return !(svnStatusIsUnversioned(status) || svnStatusIs(status, SVNStatusType.STATUS_IGNORED) || svnStatusIs(status, SVNStatusType.STATUS_OBSTRUCTED)); } } catch (SVNException e) { // } return false; } public static boolean svnStatusIsUnversioned(final SVNStatus status) { return svnStatusIs(status, SVNStatusType.STATUS_UNVERSIONED); } public static boolean svnStatusIs(final SVNStatus status, @NotNull final SVNStatusType value) { return value.equals(status.getNodeStatus()) || value.equals(status.getContentsStatus()); } @Override public boolean fileIsUnderVcs(FilePath path) { final ChangeListManager clManager = ChangeListManager.getInstance(myProject); final VirtualFile file = path.getVirtualFile(); if (file == null) { return false; } return !SvnStatusUtil.isIgnoredInAnySense(clManager, file) && !clManager.isUnversioned(file); } private static File getEntriesFile(File file) { return file.isDirectory() ? new File(file, pathToEntries) : new File(file.getParentFile(), pathToEntries); } private static File getDirPropsFile(File file) { return new File(file, pathToDirProps); } @Nullable public SVNInfo getInfo(final VirtualFile file) { final File ioFile = new File(file.getPath()); return getInfo(ioFile); } public SVNInfo getInfo(File ioFile) { try { SVNWCClient wcClient = createWCClient(); SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED); if (info == null || info.getRepositoryRootURL() == null) { info = wcClient.doInfo(ioFile, SVNRevision.HEAD); } return info; } catch (SVNException e) { return null; } } public void refreshSSLProperty() { if (ourSSLProtocolsExplicitlySet) return; if (SvnConfiguration.SSLProtocols.all.equals(myConfiguration.SSL_PROTOCOLS)) { System.clearProperty(SVNKIT_HTTP_SSL_PROTOCOLS); } else if (SvnConfiguration.SSLProtocols.sslv3.equals(myConfiguration.SSL_PROTOCOLS)) { System.setProperty(SVNKIT_HTTP_SSL_PROTOCOLS, "SSLv3"); } else if (SvnConfiguration.SSLProtocols.tlsv1.equals(myConfiguration.SSL_PROTOCOLS)) { System.setProperty(SVNKIT_HTTP_SSL_PROTOCOLS, "TLSv1"); } } private static class JavaSVNDebugLogger extends SVNDebugLogAdapter { private final boolean myLoggingEnabled; private final boolean myLogNative; private final Logger myLog; private static final long ourMaxFrequency = 10000; private long myPreviousTime = 0; public JavaSVNDebugLogger(boolean loggingEnabled, boolean logNative, Logger log) { myLoggingEnabled = loggingEnabled; myLogNative = logNative; myLog = log; } private boolean shouldLog(final SVNLogType logType) { return myLoggingEnabled || myLogNative && SVNLogType.NATIVE_CALL.equals(logType); } @Override public void log(final SVNLogType logType, final Throwable th, final Level logLevel) { if (th instanceof SSLHandshakeException) { final long time = System.currentTimeMillis(); if ((time - myPreviousTime) > ourMaxFrequency) { myPreviousTime = time; String info = myHelper.getAddInfo(); info = info == null ? "" : " (" + info + ") "; if (th.getCause() instanceof CertificateException) { PopupUtil.showBalloonForActiveComponent( "Subversion: " + info + th.getCause().getMessage(), MessageType.ERROR); } else { final String postMessage = "\nPlease check Subversion SSL settings (Settings | Version Control | Subversion | Network)"; PopupUtil.showBalloonForActiveComponent( "Subversion: " + info + th.getMessage() + postMessage, MessageType.ERROR); } } } if (shouldLog(logType)) { myLog.info(th); } } @Override public void log(final SVNLogType logType, final String message, final Level logLevel) { if (SVNLogType.NATIVE_CALL.equals(logType)) { logNative(message); } if (shouldLog(logType)) { myLog.info(message); } } private static void logNative(String message) { if (message == null) return; final NativeLogReader.CallInfo callInfo = SvnNativeLogParser.parse(message); if (callInfo == null) return; NativeLogReader.putInfo(callInfo); } @Override public void log(final SVNLogType logType, final String message, final byte[] data) { if (shouldLog(logType)) { if (data != null) { try { myLog.info(message + "\n" + new String(data, "UTF-8")); } catch (UnsupportedEncodingException e) { myLog.info(message + "\n" + new String(data)); } } else { myLog.info(message); } } } } @Override public FileStatus[] getProvidedStatuses() { return new FileStatus[] { SvnFileStatus.EXTERNAL, SvnFileStatus.OBSTRUCTED, SvnFileStatus.REPLACED }; } @Override @NotNull public CommittedChangesProvider<SvnChangeList, ChangeBrowserSettings> getCommittedChangesProvider() { if (myCommittedChangesProvider == null) { myCommittedChangesProvider = new SvnCommittedChangesProvider(myProject); } return myCommittedChangesProvider; } @Nullable @Override public VcsRevisionNumber parseRevisionNumber(final String revisionNumberString) { final SVNRevision revision = SVNRevision.parse(revisionNumberString); if (revision.equals(SVNRevision.UNDEFINED)) { return null; } return new SvnRevisionNumber(revision); } @Override public String getRevisionPattern() { return ourIntegerPattern; } @Override public boolean isVersionedDirectory(final VirtualFile dir) { return SvnUtil.seemsLikeVersionedDir(dir); } @NotNull public SvnFileUrlMapping getSvnFileUrlMapping() { if (myMapping == null) { myMapping = SvnFileUrlMappingImpl.getInstance(myProject); } return myMapping; } /** * Returns real working copies roots - if there is <Project Root> -> Subversion setting, and there * is one working copy, will return one root */ public List<WCInfo> getAllWcInfos() { final SvnFileUrlMapping urlMapping = getSvnFileUrlMapping(); final List<RootUrlInfo> infoList = urlMapping.getAllWcInfos(); final List<WCInfo> infos = new ArrayList<WCInfo>(); for (RootUrlInfo info : infoList) { final File file = info.getIoFile(); infos.add( new WCInfo( file.getAbsolutePath(), info.getAbsoluteUrlAsUrl(), info.getFormat(), info.getRepositoryUrl(), SvnUtil.isWorkingCopyRoot(file), info.getType(), SvnUtil.getDepth(this, file))); } return infos; } @Override public RootsConvertor getCustomConvertor() { if (myProject.isDefault()) return null; return getSvnFileUrlMapping(); } @Override public MergeProvider getMergeProvider() { if (myMergeProvider == null) { myMergeProvider = new SvnMergeProvider(myProject); } return myMergeProvider; } @Override public List<AnAction> getAdditionalActionsForLocalChange() { return Arrays.<AnAction>asList(new ShowPropertiesDiffWithLocalAction()); } private static String keyForVf(final VirtualFile vf) { return vf.getUrl(); } @Override public boolean allowsNestedRoots() { return true; } @Override public <S> List<S> filterUniqueRoots( final List<S> in, final Convertor<S, VirtualFile> convertor) { if (in.size() <= 1) return in; final List<MyPair<S>> infos = new ArrayList<MyPair<S>>(in.size()); final SvnFileUrlMappingImpl mapping = (SvnFileUrlMappingImpl) getSvnFileUrlMapping(); final List<S> notMatched = new LinkedList<S>(); for (S s : in) { final VirtualFile vf = convertor.convert(s); if (vf == null) continue; final File ioFile = new File(vf.getPath()); SVNURL url = mapping.getUrlForFile(ioFile); if (url == null) { url = SvnUtil.getUrl(this, ioFile); if (url == null) { notMatched.add(s); continue; } } infos.add(new MyPair<S>(vf, url.toString(), s)); } final List<MyPair<S>> filtered = new ArrayList<MyPair<S>>(infos.size()); ForNestedRootChecker.filterOutSuperfluousChildren(this, infos, filtered); final List<S> converted = ObjectsConvertor.convert( filtered, new Convertor<MyPair<S>, S>() { @Override public S convert(final MyPair<S> o) { return o.getSrc(); } }); if (!notMatched.isEmpty()) { // potential bug is here: order is not kept. but seems it only occurs for cases where result // is sorted after filtering so ok converted.addAll(notMatched); } return converted; } private static class MyPair<T> implements RootUrlPair { private final VirtualFile myFile; private final String myUrl; private final T mySrc; private MyPair(VirtualFile file, String url, T src) { myFile = file; myUrl = url; mySrc = src; } public T getSrc() { return mySrc; } @Override public VirtualFile getVirtualFile() { return myFile; } @Override public String getUrl() { return myUrl; } } private static class MyFrameStateListener extends FrameStateListener.Adapter { private final ChangeListManager myClManager; private final VcsDirtyScopeManager myDirtyScopeManager; private MyFrameStateListener( ChangeListManager clManager, VcsDirtyScopeManager dirtyScopeManager) { myClManager = clManager; myDirtyScopeManager = dirtyScopeManager; } @Override public void onFrameActivated() { final List<VirtualFile> folders = ((ChangeListManagerImpl) myClManager).getLockedFolders(); if (!folders.isEmpty()) { myDirtyScopeManager.filesDirty(null, folders); } } } public static VcsKey getKey() { return ourKey; } @Override public boolean isVcsBackgroundOperationsAllowed(VirtualFile root) { return ThreeState.YES.equals(myAuthNotifier.isAuthenticatedFor(root)); } public SvnBranchPointsCalculator getSvnBranchPointsCalculator() { return mySvnBranchPointsCalculator; } @Override public boolean areDirectoriesVersionedItems() { return true; } }