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(); // Alexander Kitaev says it is default value (SSLv3) - since 8254 if (!SystemInfo.JAVA_RUNTIME_VERSION.startsWith("1.7") && System.getProperty(SVNKIT_HTTP_SSL_PROTOCOLS) == null) { System.setProperty(SVNKIT_HTTP_SSL_PROTOCOLS, "SSLv3"); } }
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 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 int computeLoadedFileSize() { int result = (int) PersistentFSConstants.FILE_LENGTH_TO_CACHE_THRESHOLD; final String userLimitKb = System.getProperty(MAX_VCS_LOADED_SIZE_KB); try { return userLimitKb != null ? Math.min(Integer.parseInt(userLimitKb) * 1024, result) : result; } catch (NumberFormatException ignored) { return result; } }
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)); }
@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 UpdateInfoTree showUpdateProjectInfo( UpdatedFiles updatedFiles, String displayActionName, ActionInfo actionInfo, boolean canceled) { if (!myProject.isOpen() || myProject.isDisposed()) return null; ContentManager contentManager = getContentManager(); if (contentManager == null) { return null; // content manager is made null during dispose; flag is set later } final UpdateInfoTree updateInfoTree = new UpdateInfoTree(contentManager, myProject, updatedFiles, displayActionName, actionInfo); ContentUtilEx.addTabbedContent( contentManager, updateInfoTree, "Update Info", DateFormatUtil.formatDateTime(System.currentTimeMillis()), true, updateInfoTree); ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.VCS).activate(null); updateInfoTree.expandRootChildren(); return updateInfoTree; }
public class HgVcs extends AbstractVcs<CommittedChangeList> { public static final Topic<HgUpdater> BRANCH_TOPIC = new Topic<HgUpdater>("hg4idea.branch", HgUpdater.class); public static final Topic<HgUpdater> REMOTE_TOPIC = new Topic<HgUpdater>("hg4idea.remote", HgUpdater.class); public static final Topic<HgUpdater> STATUS_TOPIC = new Topic<HgUpdater>("hg4idea.status", HgUpdater.class); public static final Topic<HgHideableWidget> INCOMING_OUTGOING_CHECK_TOPIC = new Topic<HgHideableWidget>("hg4idea.incomingcheck", HgHideableWidget.class); private static final Logger LOG = Logger.getInstance(HgVcs.class); public static final String VCS_NAME = "hg4idea"; private static final VcsKey ourKey = createKey(VCS_NAME); private static final int MAX_CONSOLE_OUTPUT_SIZE = 10000; private static final String ORIG_FILE_PATTERN = "*.orig"; @Nullable public static final String HGENCODING = System.getenv("HGENCODING"); private final HgChangeProvider changeProvider; private final HgRollbackEnvironment rollbackEnvironment; private final HgDiffProvider diffProvider; private final HgHistoryProvider historyProvider; private final HgCheckinEnvironment checkinEnvironment; private final HgAnnotationProvider annotationProvider; private final HgUpdateEnvironment updateEnvironment; private final HgCachingCommittedChangesProvider committedChangesProvider; private MessageBusConnection messageBusConnection; @NotNull private final HgGlobalSettings globalSettings; @NotNull private final HgProjectSettings projectSettings; private final ProjectLevelVcsManager myVcsManager; private HgVFSListener myVFSListener; private final HgMergeProvider myMergeProvider; private HgExecutableValidator myExecutableValidator; private final Object myExecutableValidatorLock = new Object(); private File myPromptHooksExtensionFile; private CommitExecutor myCommitAndPushExecutor; private HgRemoteStatusUpdater myHgRemoteStatusUpdater; private HgStatusWidget myStatusWidget; private HgIncomingOutgoingWidget myIncomingWidget; private HgIncomingOutgoingWidget myOutgoingWidget; @NotNull private HgVersion myVersion = HgVersion.NULL; // version of Hg which this plugin uses. public HgVcs( Project project, @NotNull HgGlobalSettings globalSettings, @NotNull HgProjectSettings projectSettings, ProjectLevelVcsManager vcsManager) { super(project, VCS_NAME); this.globalSettings = globalSettings; this.projectSettings = projectSettings; myVcsManager = vcsManager; changeProvider = new HgChangeProvider(project, getKeyInstanceMethod()); rollbackEnvironment = new HgRollbackEnvironment(project); diffProvider = new HgDiffProvider(project); historyProvider = new HgHistoryProvider(project); checkinEnvironment = new HgCheckinEnvironment(project); annotationProvider = new HgAnnotationProvider(project); updateEnvironment = new HgUpdateEnvironment(project); committedChangesProvider = new HgCachingCommittedChangesProvider(project, this); myMergeProvider = new HgMergeProvider(myProject); myCommitAndPushExecutor = new HgCommitAndPushExecutor(checkinEnvironment); } public String getDisplayName() { return HgVcsMessages.message("hg4idea.mercurial"); } public Configurable getConfigurable() { return new HgProjectConfigurable(getProject(), projectSettings); } @NotNull public HgProjectSettings getProjectSettings() { return projectSettings; } @Override public ChangeProvider getChangeProvider() { return changeProvider; } @Nullable @Override public RollbackEnvironment createRollbackEnvironment() { return rollbackEnvironment; } @Override public DiffProvider getDiffProvider() { return diffProvider; } @Override public VcsHistoryProvider getVcsHistoryProvider() { return historyProvider; } @Override public VcsHistoryProvider getVcsBlockHistoryProvider() { return getVcsHistoryProvider(); } @Nullable @Override public CheckinEnvironment createCheckinEnvironment() { return checkinEnvironment; } @Override public AnnotationProvider getAnnotationProvider() { return annotationProvider; } @Override public MergeProvider getMergeProvider() { return myMergeProvider; } @Nullable @Override public UpdateEnvironment createUpdateEnvironment() { return updateEnvironment; } @Override public UpdateEnvironment getIntegrateEnvironment() { return null; } @Override public boolean fileListenerIsSynchronous() { return false; } @Override public CommittedChangesProvider getCommittedChangesProvider() { return committedChangesProvider; } @Override public boolean allowsNestedRoots() { return true; } @Override public <S> List<S> filterUniqueRoots( final List<S> in, final Convertor<S, VirtualFile> convertor) { Collections.sort( in, new ComparatorDelegate<S, VirtualFile>(convertor, FilePathComparator.getInstance())); for (int i = 1; i < in.size(); i++) { final S sChild = in.get(i); final VirtualFile child = convertor.convert(sChild); final VirtualFile childRoot = HgUtil.getHgRootOrNull(myProject, child); if (childRoot == null) { continue; } for (int j = i - 1; j >= 0; --j) { final S sParent = in.get(j); final VirtualFile parent = convertor.convert(sParent); // if the parent is an ancestor of the child and that they share common root, the child is // removed if (VfsUtilCore.isAncestor(parent, child, false) && VfsUtilCore.isAncestor(childRoot, parent, false)) { in.remove(i); //noinspection AssignmentToForLoopParameter --i; break; } } } return in; } @Override public RootsConvertor getCustomConvertor() { return HgRootsHandler.getInstance(myProject); } @Override public boolean isVersionedDirectory(VirtualFile dir) { return HgUtil.getNearestHgRoot(dir) != null; } /** * @return the prompthooks.py extension used for capturing prompts from Mercurial and requesting * IDEA's user about authentication. */ @NotNull public File getPromptHooksExtensionFile() { if (myPromptHooksExtensionFile == null) { // check that hooks are available myPromptHooksExtensionFile = HgUtil.getTemporaryPythonFile("prompthooks"); if (myPromptHooksExtensionFile == null || !myPromptHooksExtensionFile.exists()) { LOG.error( "prompthooks.py Mercurial extension is not found. Please reinstall " + ApplicationNamesInfo.getInstance().getProductName()); } } return myPromptHooksExtensionFile; } @Override public void activate() { // validate hg executable on start and update hg version checkExecutableAndVersion(); // status bar myStatusWidget = new HgStatusWidget(this, getProject(), projectSettings); myStatusWidget.activate(); myIncomingWidget = new HgIncomingOutgoingWidget(this, getProject(), projectSettings, true); myOutgoingWidget = new HgIncomingOutgoingWidget(this, getProject(), projectSettings, false); ApplicationManager.getApplication() .invokeAndWait( new Runnable() { @Override public void run() { myIncomingWidget.activate(); myOutgoingWidget.activate(); } }, ModalityState.NON_MODAL); // updaters and listeners myHgRemoteStatusUpdater = new HgRemoteStatusUpdater( this, myIncomingWidget.getChangesetStatus(), myOutgoingWidget.getChangesetStatus(), projectSettings); myHgRemoteStatusUpdater.activate(); messageBusConnection = myProject.getMessageBus().connect(); messageBusConnection.subscribe( FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { @Override public void selectionChanged(@NotNull FileEditorManagerEvent event) { Project project = event.getManager().getProject(); project.getMessageBus().syncPublisher(BRANCH_TOPIC).update(project, null); } }); myVFSListener = new HgVFSListener(myProject, this); // ignore temporary files final String ignoredPattern = FileTypeManager.getInstance().getIgnoredFilesList(); if (!ignoredPattern.contains(ORIG_FILE_PATTERN)) { final String newPattern = ignoredPattern + (ignoredPattern.endsWith(";") ? "" : ";") + ORIG_FILE_PATTERN; HgUtil.runWriteActionLater( new Runnable() { public void run() { FileTypeManager.getInstance().setIgnoredFilesList(newPattern); } }); } // Force a branch topic update myProject.getMessageBus().syncPublisher(BRANCH_TOPIC).update(myProject, null); } private void checkExecutableAndVersion() { if (!ApplicationManager.getApplication().isUnitTestMode() && getExecutableValidator().checkExecutableAndNotifyIfNeeded()) { checkVersion(); } } @Override public void deactivate() { if (myHgRemoteStatusUpdater != null) { myHgRemoteStatusUpdater.deactivate(); myHgRemoteStatusUpdater = null; } if (myStatusWidget != null) { myStatusWidget.deactivate(); myStatusWidget = null; } if (myIncomingWidget != null) { myIncomingWidget.deactivate(); myIncomingWidget = null; } if (myOutgoingWidget != null) { myOutgoingWidget.deactivate(); myOutgoingWidget = null; } if (messageBusConnection != null) { messageBusConnection.disconnect(); } if (myVFSListener != null) { Disposer.dispose(myVFSListener); myVFSListener = null; } super.deactivate(); } @Nullable public static HgVcs getInstance(Project project) { if (project == null || project.isDisposed()) { return null; } final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project); if (vcsManager == null) { return null; } return (HgVcs) vcsManager.findVcsByName(VCS_NAME); } @NotNull public HgGlobalSettings getGlobalSettings() { return globalSettings; } public void showMessageInConsole(String message, final TextAttributes style) { if (message.length() > MAX_CONSOLE_OUTPUT_SIZE) { message = message.substring(0, MAX_CONSOLE_OUTPUT_SIZE); } myVcsManager.addMessageToConsoleWindow(message, style); } public HgExecutableValidator getExecutableValidator() { synchronized (myExecutableValidatorLock) { if (myExecutableValidator == null) { myExecutableValidator = new HgExecutableValidator(myProject, this); } return myExecutableValidator; } } @Override public boolean reportsIgnoredDirectories() { return false; } @Override public List<CommitExecutor> getCommitExecutors() { return Collections.singletonList(myCommitAndPushExecutor); } public static VcsKey getKey() { return ourKey; } @Override public VcsType getType() { return VcsType.distributed; } @Override public CheckoutProvider getCheckoutProvider() { return new HgCheckoutProvider(); } /** * Checks Hg version and updates the myVersion variable. In the case of nullable or unsupported * version reports the problem. */ public void checkVersion() { final String executable = getGlobalSettings().getHgExecutable(); HgCommandResultNotifier errorNotification = new HgCommandResultNotifier(myProject); final String SETTINGS_LINK = "settings"; final String UPDATE_LINK = "update"; NotificationListener linkAdapter = new NotificationListener.Adapter() { @Override protected void hyperlinkActivated( @NotNull Notification notification, @NotNull HyperlinkEvent e) { if (SETTINGS_LINK.equals(e.getDescription())) { ShowSettingsUtil.getInstance() .showSettingsDialog(myProject, getConfigurable().getDisplayName()); } else if (UPDATE_LINK.equals(e.getDescription())) { BrowserUtil.browse("http://mercurial.selenic.com"); } } }; try { myVersion = HgVersion.identifyVersion(executable); // if version is not supported, but have valid hg executable if (!myVersion.isSupported()) { LOG.info("Unsupported Hg version: " + myVersion); String message = String.format( "The <a href='" + SETTINGS_LINK + "'>configured</a> version of Hg is not supported: %s.<br/> " + "The minimal supported version is %s. Please <a href='" + UPDATE_LINK + "'>update</a>.", myVersion, HgVersion.MIN); errorNotification.notifyError(null, "Unsupported Hg version", message, linkAdapter); } else if (myVersion.hasUnsupportedExtensions()) { String unsupportedExtensionsAsString = myVersion.getUnsupportedExtensions().toString(); LOG.warn("Unsupported Hg extensions: " + unsupportedExtensionsAsString); String message = String.format( "Some hg extensions %s are not found or not supported by your hg version and will be ignored.\n" + "Please, update your hgrc or Mercurial.ini file", unsupportedExtensionsAsString); errorNotification.notifyWarning("Unsupported Hg version", message); } } catch (Exception e) { if (getExecutableValidator().checkExecutableAndNotifyIfNeeded()) { // sometimes not hg application has version command, but we couldn't parse an answer as // valid hg, // so parse(output) throw ParseException, but hg and git executable seems to be valid in // this case final String reason = (e.getCause() != null ? e.getCause() : e).getMessage(); String message = HgVcsMessages.message("hg4idea.unable.to.run.hg", executable); errorNotification.notifyError( null, message, String.format( reason + "<br/> Please check your hg executable path in <a href='" + SETTINGS_LINK + "'> settings </a>"), linkAdapter); } } } /** * @return the version number of Hg, which is used by IDEA. Or {@link HgVersion#NULL} if version * info is unavailable. */ @NotNull public HgVersion getVersion() { return myVersion; } }
public boolean updateStep() { final MultiMap<VcsRoot, String> dirty = new MultiMap<VcsRoot, String>(); final long oldPoint = System.currentTimeMillis() - (myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL > 0 ? myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL * 60000 : DISCRETE); synchronized (myLock) { // just copies myQueries MultiMap to dirty MultiMap for (VcsRoot root : myQueries.keySet()) { final Collection<String> collection = myQueries.get(root); for (String s : collection) { dirty.putValue(root, s); } } myQueries.clear(); // collect roots for which cache update should be performed (by timestamp) final Set<VcsRoot> roots = new HashSet<VcsRoot>(); for (Map.Entry<VcsRoot, Long> entry : myTs.entrySet()) { // ignore timestamp, as still remote changes checking is required // TODO: why not to add in roots anyway??? - as dirty is still checked when adding myChanged // files. if (!dirty.get(entry.getKey()).isEmpty()) continue; // update only if timeout expired final Long ts = entry.getValue(); if ((ts == null) || (oldPoint > ts)) { roots.add(entry.getKey()); } } // Add dirty files from those vcs roots, that // - needs to be update by timestamp criteria // - that already contain files for update through manually added requests for (Map.Entry<String, Pair<Boolean, VcsRoot>> entry : myChanged.entrySet()) { final VcsRoot vcsRoot = entry.getValue().getSecond(); if ((!dirty.get(vcsRoot).isEmpty()) || roots.contains(vcsRoot)) { dirty.putValue(vcsRoot, entry.getKey()); } } } if (dirty.isEmpty()) return false; final Map<String, Pair<Boolean, VcsRoot>> results = new HashMap<String, Pair<Boolean, VcsRoot>>(); for (VcsRoot vcsRoot : dirty.keySet()) { // todo - actually it means nothing since the only known VCS to use this scheme is Git and now // it always allow // todo - background operations. when it changes, develop more flexible behavior here if (!vcsRoot.getVcs().isVcsBackgroundOperationsAllowed(vcsRoot.getPath())) continue; final TreeDiffProvider provider = vcsRoot.getVcs().getTreeDiffProvider(); if (provider == null) continue; final Collection<String> paths = dirty.get(vcsRoot); final Collection<String> remotelyChanged = provider.getRemotelyChanged(vcsRoot.getPath(), paths); for (String path : paths) { // TODO: Contains invoked for each file - better to use Set (implementations just use List) // TODO: Why to store boolean for changed or not - why not just remove such values from // myChanged??? results.put(path, new Pair<Boolean, VcsRoot>(remotelyChanged.contains(path), vcsRoot)); } } final long curTime = System.currentTimeMillis(); synchronized (myLock) { myChanged.putAll(results); for (VcsRoot vcsRoot : dirty.keySet()) { myTs.put(vcsRoot, curTime); } } return true; }
public boolean updateStep(final AtomicSectionsAware atomicSectionsAware) { final MultiMap<VcsRoot, String> dirty = new MultiMap<VcsRoot, String>(); final long oldPoint = System.currentTimeMillis() - (myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL > 0 ? myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL * 60000 : DISCRETE); synchronized (myLock) { for (VcsRoot root : myQueries.keySet()) { final Collection<String> collection = myQueries.get(root); for (String s : collection) { dirty.putValue(root, s); } } myQueries.clear(); final Set<VcsRoot> roots = new HashSet<VcsRoot>(); for (Map.Entry<VcsRoot, Long> entry : myTs.entrySet()) { if (!dirty.get(entry.getKey()).isEmpty()) continue; final Long ts = entry.getValue(); if ((ts == null) || (oldPoint > ts)) { roots.add(entry.getKey()); } } for (Map.Entry<String, Pair<Boolean, VcsRoot>> entry : myChanged.entrySet()) { final VcsRoot vcsRoot = entry.getValue().getSecond(); if ((!dirty.get(vcsRoot).isEmpty()) || roots.contains(vcsRoot)) { dirty.putValue(vcsRoot, entry.getKey()); } } } if (dirty.isEmpty()) return false; final Map<String, Pair<Boolean, VcsRoot>> results = new HashMap<String, Pair<Boolean, VcsRoot>>(); for (VcsRoot vcsRoot : dirty.keySet()) { atomicSectionsAware.checkShouldExit(); // todo - actually it means nothing since the only known VCS to use this scheme is Git and now // it always allow // todo - background operations. when it changes, develop more flexible behavior here if (!vcsRoot.vcs.isVcsBackgroundOperationsAllowed(vcsRoot.path)) continue; final TreeDiffProvider provider = vcsRoot.vcs.getTreeDiffProvider(); if (provider == null) continue; final Collection<String> paths = dirty.get(vcsRoot); final Collection<String> remotelyChanged = provider.getRemotelyChanged(vcsRoot.path, paths); for (String path : paths) { results.put(path, new Pair<Boolean, VcsRoot>(remotelyChanged.contains(path), vcsRoot)); } } final long curTime = System.currentTimeMillis(); synchronized (myLock) { myChanged.putAll(results); for (VcsRoot vcsRoot : dirty.keySet()) { myTs.put(vcsRoot, curTime); } } return true; }