under USER_HOME, prefer storing paths relatively MODULE_DIR unless the common ancesto...
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / components / impl / BasePathMacroManager.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.openapi.components.impl;
17
18 import com.intellij.application.options.PathMacrosImpl;
19 import com.intellij.application.options.ReplacePathToMacroMap;
20 import com.intellij.openapi.application.PathManager;
21 import com.intellij.openapi.components.ExpandMacroToPathMap;
22 import com.intellij.openapi.components.PathMacroManager;
23 import com.intellij.openapi.components.PathMacroMap;
24 import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
25 import com.intellij.openapi.util.SystemInfo;
26 import com.intellij.openapi.util.text.StringUtil;
27 import com.intellij.util.SystemProperties;
28 import com.intellij.util.containers.FactoryMap;
29 import org.jdom.Element;
30 import org.jetbrains.annotations.NonNls;
31 import org.jetbrains.annotations.Nullable;
32
33 import java.io.File;
34 import java.util.*;
35
36 public class BasePathMacroManager extends PathMacroManager {
37   private PathMacrosImpl myPathMacros;
38
39   protected static void addFileHierarchyReplacements(ReplacePathToMacroMap result,
40                                                      String variableName,
41                                                      @Nullable String _path, @Nullable String stopAt) {
42     if (_path == null) {
43       return;
44     }
45
46     String macro = "$" + variableName + "$";
47     File dir = new File(_path.replace('/', File.separatorChar));
48     boolean check = false;
49     while (dir != null && dir.getParentFile() != null) {
50       @NonNls String path = PathMacroMap.quotePath(dir.getAbsolutePath());
51       String s = macro;
52
53       if (StringUtil.endsWithChar(path, '/')) s += "/";
54
55       putIfAbsent(result, "file:" + path, "file:" + s, check);
56       putIfAbsent(result, "file:/" + path, "file:/" + s, check);
57       putIfAbsent(result, "file://" + path, "file://" + s, check);
58       putIfAbsent(result, "jar:" + path, "jar:" + s, check);
59       putIfAbsent(result, "jar:/" + path, "jar:/" + s, check);
60       putIfAbsent(result, "jar://" + path, "jar://" + s, check);
61       if (!path.equalsIgnoreCase("e:/") && !path.equalsIgnoreCase("r:/") && !path.equalsIgnoreCase("p:/")) {
62         putIfAbsent(result, path, s, check);
63       }
64
65       if (dir.getPath().equals(stopAt)) {
66         break;
67       }
68
69       macro += "/..";
70       check = true;
71       dir = dir.getParentFile();
72     }
73   }
74
75   public ExpandMacroToPathMap getExpandMacroMap() {
76     ExpandMacroToPathMap result = new ExpandMacroToPathMap();
77     result.addMacroExpand(PathMacrosImpl.APPLICATION_HOME_MACRO_NAME, PathManager.getHomePath());
78     result.addMacroExpand(PathMacrosImpl.USER_HOME_MACRO_NAME, getUserHome());
79     getPathMacros().addMacroExpands(result);
80     return result;
81   }
82
83   protected static String getUserHome() {
84     return SystemProperties.getUserHome();
85   }
86
87
88   public ReplacePathToMacroMap getReplacePathMap() {
89     ReplacePathToMacroMap result = new ReplacePathToMacroMap();
90
91     result.addMacroReplacement(PathManager.getHomePath(), PathMacrosImpl.APPLICATION_HOME_MACRO_NAME);
92     result.addMacroReplacement(getUserHome(), PathMacrosImpl.USER_HOME_MACRO_NAME);
93     getPathMacros().addMacroReplacements(result);
94     return result;
95   }
96
97   public TrackingPathMacroSubstitutor createTrackingSubstitutor() {
98     return new MyTrackingPathMacroSubstitutor();
99   }
100
101   public String expandPath(final String path) {
102     return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
103   }
104
105   public String collapsePath(final String path) {
106     return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
107   }
108
109   public void collapsePathsRecursively(final Element element) {
110     getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, true);
111   }
112
113   public void expandPaths(final Element element) {
114     getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
115   }
116
117
118   public void collapsePaths(final Element element) {
119     getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
120   }
121
122   public PathMacrosImpl getPathMacros() {
123     if (myPathMacros == null) {
124       myPathMacros = PathMacrosImpl.getInstanceEx();
125     }
126
127     return myPathMacros;
128   }
129
130
131   protected static void putIfAbsent(final ReplacePathToMacroMap result, @NonNls final String pathWithPrefix, @NonNls final String substWithPrefix, final boolean check) {
132     if (check && result.get(pathWithPrefix) != null) return;
133     result.put(pathWithPrefix, substWithPrefix);
134   }
135
136   private class MyTrackingPathMacroSubstitutor implements TrackingPathMacroSubstitutor {
137     private final Map<String, Set<String>> myMacroToComponentNames = new FactoryMap<String, Set<String>>() {
138       @Override
139       protected Set<String> create(String key) {
140         return new HashSet<String>();
141       }
142     };
143
144     private final Map<String, Set<String>> myComponentNameToMacros = new FactoryMap<String, Set<String>>() {
145       @Override
146       protected Set<String> create(String key) {
147         return new HashSet<String>();
148       }
149     };
150
151     public MyTrackingPathMacroSubstitutor() {
152     }
153
154     public void reset() {
155       myMacroToComponentNames.clear();
156       myComponentNameToMacros.clear();
157     }
158
159     public String expandPath(final String path) {
160       return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
161     }
162
163     public String collapsePath(final String path) {
164       return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
165     }
166
167     public void expandPaths(final Element element) {
168       getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
169     }
170
171     public void collapsePaths(final Element element) {
172       getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
173     }
174
175     public int hashCode() {
176       return getExpandMacroMap().hashCode();
177     }
178
179     public void invalidateUnknownMacros(final Set<String> macros) {
180       for (final String macro : macros) {
181         final Set<String> components = myMacroToComponentNames.get(macro);
182         for (final String component : components) {
183           myComponentNameToMacros.remove(component);
184         }
185
186         myMacroToComponentNames.remove(macro);
187       }
188     }
189
190     public Collection<String> getComponents(final Collection<String> macros) {
191       final Set<String> result = new HashSet<String>();
192       for (String macro : myMacroToComponentNames.keySet()) {
193         if (macros.contains(macro)) {
194           result.addAll(myMacroToComponentNames.get(macro));
195         }
196       }
197
198       return result;
199     }
200
201     public Collection<String> getUnknownMacros(final String componentName) {
202       final Set<String> result = new HashSet<String>();
203       result.addAll(componentName == null ? myMacroToComponentNames.keySet() : myComponentNameToMacros.get(componentName));
204       return Collections.unmodifiableCollection(result);
205     }
206
207     public void addUnknownMacros(final String componentName, final Collection<String> unknownMacros) {
208       if (unknownMacros.isEmpty()) return;
209       
210       for (String unknownMacro : unknownMacros) {
211         final Set<String> stringList = myMacroToComponentNames.get(unknownMacro);
212         stringList.add(componentName);
213       }
214
215       myComponentNameToMacros.get(componentName).addAll(unknownMacros);
216     }
217   }
218 }