SVN auth
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / SvnConfiguration.java
blob272cd962f912980a9841991e07d1f30450cf6a47
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 package org.jetbrains.idea.svn;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.application.ModalityState;
22 import com.intellij.openapi.components.ProjectComponent;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.progress.ProcessCanceledException;
25 import com.intellij.openapi.progress.ProgressIndicator;
26 import com.intellij.openapi.progress.ProgressManager;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.*;
29 import com.intellij.openapi.util.io.FileUtil;
30 import com.intellij.openapi.vcs.annotate.AnnotationListener;
31 import org.jdom.Attribute;
32 import org.jdom.DataConversionException;
33 import org.jdom.Element;
34 import org.jetbrains.idea.svn.dialogs.SvnAuthenticationProvider;
35 import org.jetbrains.idea.svn.dialogs.SvnInteractiveAuthenticationProvider;
36 import org.jetbrains.idea.svn.update.MergeRootInfo;
37 import org.jetbrains.idea.svn.update.UpdateRootInfo;
38 import org.tmatesoft.svn.core.SVNDepth;
39 import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
40 import org.tmatesoft.svn.core.internal.wc.ISVNAuthenticationStorage;
41 import org.tmatesoft.svn.core.internal.wc.SVNConfigFile;
42 import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
43 import org.tmatesoft.svn.core.wc.ISVNOptions;
44 import org.tmatesoft.svn.core.wc.SVNWCUtil;
46 import java.io.File;
47 import java.io.FilenameFilter;
48 import java.util.*;
50 public class SvnConfiguration implements ProjectComponent, JDOMExternalizable {
51 private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.SvnConfiguration");
53 private final static String SERVERS_FILE_NAME = "servers";
55 public static final String UPGRADE_AUTO = "auto";
56 public static final String UPGRADE_AUTO_15 = "auto1.5";
57 public static final String UPGRADE_AUTO_16 = "auto1.6";
58 public static final String UPGRADE_NONE = "none";
60 public String USER = "";
61 public String PASSWORD = "";
62 public String[] ADD_PATHS = null;
64 private String myConfigurationDirectory;
65 private boolean myIsUseDefaultConfiguration;
66 private boolean myIsUseDefaultProxy;
67 private ISVNOptions myOptions;
68 private boolean myIsKeepLocks;
69 private boolean myRemoteStatus;
70 private final Project myProject;
71 private SvnAuthenticationManager myAuthManager;
72 private SvnAuthenticationManager myPassiveAuthManager;
73 private SvnAuthenticationManager myInteractiveManager;
74 private String myUpgradeMode;
75 private SvnSupportOptions mySupportOptions;
77 public static final AuthStorage RUNTIME_AUTH_CACHE = new AuthStorage();
78 public String LAST_MERGED_REVISION = null;
79 public boolean UPDATE_RUN_STATUS = false;
80 public SVNDepth UPDATE_DEPTH = SVNDepth.INFINITY;
82 public boolean MERGE_DRY_RUN = false;
83 public boolean MERGE_DIFF_USE_ANCESTRY = true;
84 public boolean UPDATE_LOCK_ON_DEMAND = false;
85 public boolean IGNORE_SPACES_IN_MERGE = false;
86 public boolean DETECT_NESTED_COPIES = false;
87 public boolean IGNORE_SPACES_IN_ANNOTATE = true;
88 public boolean SHOW_MERGE_SOURCES_IN_ANNOTATE = true;
90 private final Map<File, MergeRootInfo> myMergeRootInfos = new HashMap<File, MergeRootInfo>();
91 private final Map<File, UpdateRootInfo> myUpdateRootInfos = new HashMap<File, UpdateRootInfo>();
92 private final List<AnnotationListener> myAnnotationListeners;
94 public static SvnConfiguration getInstance(Project project) {
95 return project.getComponent(SvnConfiguration.class);
98 public static SvnConfiguration getInstanceChecked(final Project project) {
99 return ApplicationManager.getApplication().runReadAction(new Computable<SvnConfiguration>() {
100 public SvnConfiguration compute() {
101 if (project.isDisposed()) throw new ProcessCanceledException();
102 return project.getComponent(SvnConfiguration.class);
107 public SvnConfiguration(final Project project) {
108 myProject = project;
109 myAnnotationListeners = new ArrayList<AnnotationListener>();
112 // accessed on AWT
113 public void addAnnotationListener(final AnnotationListener listener) {
114 myAnnotationListeners.add(listener);
117 public void removeAnnotationListener(final AnnotationListener listener) {
118 myAnnotationListeners.remove(listener);
121 public void setIgnoreSpacesInAnnotate(final boolean value) {
122 final boolean changed = IGNORE_SPACES_IN_ANNOTATE != value;
123 IGNORE_SPACES_IN_ANNOTATE = value;
124 if (changed) {
125 fireForAnnotationListeners();
129 private void fireForAnnotationListeners() {
130 final AnnotationListener[] listeners = myAnnotationListeners.toArray(new AnnotationListener[myAnnotationListeners.size()]);
131 ApplicationManager.getApplication().invokeLater(new Runnable() {
132 public void run() {
133 for (int i = 0; i < listeners.length; i++) {
134 final AnnotationListener listener = listeners[i];
135 listener.onAnnotationChanged();
138 }, ModalityState.NON_MODAL);
141 public class SvnSupportOptions {
143 * version of "support SVN in IDEA". for features tracking. should grow
145 private Long myVersion;
147 public SvnSupportOptions(final Long version) {
148 myVersion = version;
149 // will be set to SvnSupportOptions.CHANGELIST_SUPPORT after sync
150 if (myVersion == null || myVersion.longValue() < SvnSupportOptions.CHANGELIST_SUPPORT) {
151 myVersion = SvnSupportOptions.UPGRADE_TO_15_VERSION_ASKED;
155 private final static long UPGRADE_TO_15_VERSION_ASKED = 123;
156 private final static long CHANGELIST_SUPPORT = 124;
157 private final static long UPGRADE_TO_16_VERSION_ASKED = 125;
159 public boolean upgradeTo16Asked() {
160 return (myVersion != null) && (UPGRADE_TO_16_VERSION_ASKED <= myVersion);
163 public boolean changeListsSynchronized() {
164 return (myVersion != null) && (CHANGELIST_SUPPORT <= myVersion);
167 public void upgrade() {
168 myVersion = UPGRADE_TO_16_VERSION_ASKED;
172 public SvnSupportOptions getSupportOptions() {
173 if (mySupportOptions == null) {
174 // used to be kept in SvnBranchConfigurationManager
175 mySupportOptions = new SvnSupportOptions(SvnBranchConfigurationManager.getInstance(myProject).getSupportValue());
177 return mySupportOptions;
180 public String getConfigurationDirectory() {
181 if (myConfigurationDirectory == null || isUseDefaultConfiguation()) {
182 myConfigurationDirectory = SVNWCUtil.getDefaultConfigurationDirectory().getAbsolutePath();
184 return myConfigurationDirectory;
187 public boolean isUseDefaultConfiguation() {
188 return myIsUseDefaultConfiguration;
191 public void setConfigurationDirectory(String path) {
192 myConfigurationDirectory = path;
193 File dir = path == null ? SVNWCUtil.getDefaultConfigurationDirectory() : new File(path);
194 SVNConfigFile.createDefaultConfiguration(dir);
196 myOptions = null;
197 myAuthManager = null;
198 RUNTIME_AUTH_CACHE.clear();
201 public void setUseDefaultConfiguation(boolean useDefault) {
202 myIsUseDefaultConfiguration = useDefault;
203 myOptions = null;
204 myAuthManager = null;
205 RUNTIME_AUTH_CACHE.clear();
208 public ISVNOptions getOptions(Project project) {
209 if (myOptions == null) {
210 File path = new File(getConfigurationDirectory());
211 myOptions = SVNWCUtil.createDefaultOptions(path.getAbsoluteFile(), true);
213 return myOptions;
216 public ISVNAuthenticationManager getAuthenticationManager(final SvnVcs svnVcs) {
217 if (myAuthManager == null) {
218 // reloaded when configuration directory changes
219 myAuthManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
220 myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs));
221 myAuthManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
223 return myAuthManager;
226 public ISVNAuthenticationManager getPassiveAuthenticationManager() {
227 if (myPassiveAuthManager == null) {
228 myPassiveAuthManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
229 myPassiveAuthManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
231 return myPassiveAuthManager;
234 public ISVNAuthenticationManager getInteractiveManager(final SvnVcs svnVcs) {
235 if (myInteractiveManager == null) {
236 myInteractiveManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory()));
237 myInteractiveManager.setRuntimeStorage(RUNTIME_AUTH_CACHE);
238 myInteractiveManager.setAuthenticationProvider(new SvnInteractiveAuthenticationProvider(svnVcs));
240 return myInteractiveManager;
243 public void getServerFilesManagers(final Ref<SvnServerFileManager> systemManager, final Ref<SvnServerFileManager> userManager) {
244 // created only if does not exist
245 SVNConfigFile.createDefaultConfiguration(new File(getConfigurationDirectory()));
247 systemManager.set(new SvnServerFileManagerImpl(new IdeaSVNConfigFile(new File(SVNFileUtil.getSystemConfigurationDirectory(), SERVERS_FILE_NAME))));
248 userManager.set(new SvnServerFileManagerImpl(new IdeaSVNConfigFile(new File(getConfigurationDirectory(), SERVERS_FILE_NAME))));
251 public String getUpgradeMode() {
252 return myUpgradeMode;
255 public void setUpgradeMode(String upgradeMode) {
256 myUpgradeMode = upgradeMode;
259 @SuppressWarnings({"HardCodedStringLiteral"})
260 public void readExternal(Element element) throws InvalidDataException {
261 DefaultJDOMExternalizer.readExternal(this, element);
262 List elems = element.getChildren("addpath");
263 LOG.debug(elems.toString());
264 ADD_PATHS = new String[elems.size()];
265 for (int i = 0; i < elems.size(); i++) {
266 Element elem = (Element)elems.get(i);
267 ADD_PATHS[i] = elem.getAttributeValue("path");
269 Element configurationDirectory = element.getChild("configuration");
270 if (configurationDirectory != null) {
271 myConfigurationDirectory = configurationDirectory.getText();
272 Attribute defaultAttr = configurationDirectory.getAttribute("useDefault");
273 try {
274 myIsUseDefaultConfiguration = defaultAttr != null && defaultAttr.getBooleanValue();
276 catch (DataConversionException e) {
277 myIsUseDefaultConfiguration = false;
280 else {
281 myIsUseDefaultConfiguration = true;
283 // compatibility: this setting was moved from .iws to global settings
284 List urls = element.getChildren("checkoutURL");
285 for (Object url1 : urls) {
286 Element child = (Element)url1;
287 String url = child.getText();
288 if (url != null) {
289 SvnApplicationSettings.getInstance().addCheckoutURL(url);
292 myIsKeepLocks = element.getChild("keepLocks") != null;
293 myRemoteStatus = element.getChild("remoteStatus") != null;
294 myUpgradeMode = element.getChild("upgradeMode") != null ? element.getChild("upgradeMode").getText() : null;
295 final Element useProxy = element.getChild("myIsUseDefaultProxy");
296 if (useProxy == null) {
297 myIsUseDefaultProxy = false;
298 } else {
299 myIsUseDefaultProxy = Boolean.parseBoolean(useProxy.getText());
301 final Element supportedVersion = element.getChild("supportedVersion");
302 if (supportedVersion != null) {
303 mySupportOptions = new SvnSupportOptions(Long.parseLong(supportedVersion.getText()));
307 @SuppressWarnings({"HardCodedStringLiteral"})
308 public void writeExternal(Element element) throws WriteExternalException {
309 DefaultJDOMExternalizer.writeExternal(this, element);
310 if (ADD_PATHS != null) {
311 for (String aADD_PATHS : ADD_PATHS) {
312 Element elem = new Element("addpath");
313 elem.setAttribute("path", aADD_PATHS);
314 element.addContent(elem);
317 if (myConfigurationDirectory != null) {
318 Element configurationDirectory = new Element("configuration");
319 configurationDirectory.setText(myConfigurationDirectory);
320 configurationDirectory.setAttribute("useDefault", myIsUseDefaultConfiguration ? "true" : "false");
321 element.addContent(configurationDirectory);
323 if (myIsKeepLocks) {
324 element.addContent(new Element("keepLocks"));
326 if (myRemoteStatus) {
327 element.addContent(new Element("remoteStatus"));
329 if (myUpgradeMode != null) {
330 element.addContent(new Element("upgradeMode").setText(myUpgradeMode));
332 element.addContent(new Element("myIsUseDefaultProxy").setText(myIsUseDefaultProxy ? "true" : "false"));
333 if (mySupportOptions != null) {
334 element.addContent(new Element("supportedVersion").setText("" + mySupportOptions.myVersion));
338 public void projectOpened() {
341 public void projectClosed() {
344 public String getComponentName() {
345 return "SvnConfiguration";
348 public void initComponent() {
351 public void disposeComponent() {
354 public boolean isKeepLocks() {
355 return myIsKeepLocks;
358 public void setKeepLocks(boolean keepLocks) {
359 myIsKeepLocks = keepLocks;
362 public boolean isRemoteStatus() {
363 return myRemoteStatus;
366 public void setRemoteStatus(boolean remote) {
367 myRemoteStatus = remote;
370 public boolean isIsUseDefaultProxy() {
371 return myIsUseDefaultProxy;
374 public void setIsUseDefaultProxy(final boolean isUseDefaultProxy) {
375 myIsUseDefaultProxy = isUseDefaultProxy;
378 public static class AuthStorage implements ISVNAuthenticationStorage {
380 private final Map<String, Object> myStorage = new Hashtable<String, Object>();
382 public void clear() {
383 myStorage.clear();
386 public void putData(String kind, String realm, Object data) {
387 if (data == null) {
388 myStorage.remove(kind + "$" + realm);
389 } else {
390 myStorage.put(kind + "$" + realm, data);
394 public Object getData(String kind, String realm) {
395 return myStorage.get(kind + "$" + realm);
399 public MergeRootInfo getMergeRootInfo(final File file, final SvnVcs svnVcs) {
400 if (!myMergeRootInfos.containsKey(file)) {
401 myMergeRootInfos.put(file, new MergeRootInfo(file, svnVcs));
403 return myMergeRootInfos.get(file);
406 public UpdateRootInfo getUpdateRootInfo(File file, final SvnVcs svnVcs) {
407 if (!myUpdateRootInfos.containsKey(file)) {
408 myUpdateRootInfos.put(file, new UpdateRootInfo(file, svnVcs));
410 return myUpdateRootInfos.get(file);
413 public Map<File, UpdateRootInfo> getUpdateInfosMap() {
414 return Collections.unmodifiableMap(myUpdateRootInfos);
417 private static final List<String> ourAuthKinds = Arrays.asList(ISVNAuthenticationManager.PASSWORD, ISVNAuthenticationManager.SSH,
418 ISVNAuthenticationManager.SSL, ISVNAuthenticationManager.USERNAME, "svn.ssl.server");
420 public void clearAuthenticationDirectory() {
421 final File authDir = new File(getConfigurationDirectory(), "auth");
422 if (authDir.exists()) {
423 ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
424 public void run() {
425 final ProgressIndicator ind = ProgressManager.getInstance().getProgressIndicator();
426 if (ind != null) {
427 ind.setIndeterminate(true);
428 ind.setText("Clearing stored credentials in " + authDir.getAbsolutePath());
430 final File[] files = authDir.listFiles(new FilenameFilter() {
431 public boolean accept(File dir, String name) {
432 return ourAuthKinds.contains(name);
436 for (File dir : files) {
437 if (ind != null) {
438 ind.setText("Deleting " + dir.getAbsolutePath());
440 FileUtil.delete(dir);
443 }, "button.text.clear.authentication.cache", false, myProject);
447 public boolean haveCredentialsFor(final String kind, final String realm) {
448 return RUNTIME_AUTH_CACHE.getData(kind, realm) != null;
451 public void acknowledge(final String kind, final String realm, final Object object) {
452 RUNTIME_AUTH_CACHE.putData(kind, realm, object);
455 public void clearCredentials(final String kind, final String realm) {
456 RUNTIME_AUTH_CACHE.putData(kind, realm, null);