Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/Internals.java @ 379:fa2be7a05af6
Implement discovery of mercurial installation, use it to read/write configuration files
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 09 Feb 2012 16:47:17 +0100 |
| parents | 9fb990c8a724 |
| children | 82336b7c54f4 |
comparison
equal
deleted
inserted
replaced
| 378:9fb990c8a724 | 379:fa2be7a05af6 |
|---|---|
| 20 | 20 |
| 21 import java.io.File; | 21 import java.io.File; |
| 22 import java.io.FileOutputStream; | 22 import java.io.FileOutputStream; |
| 23 import java.io.IOException; | 23 import java.io.IOException; |
| 24 import java.util.ArrayList; | 24 import java.util.ArrayList; |
| 25 import java.util.Arrays; | |
| 26 import java.util.Collections; | |
| 27 import java.util.LinkedHashSet; | |
| 25 import java.util.List; | 28 import java.util.List; |
| 29 import java.util.StringTokenizer; | |
| 26 | 30 |
| 27 import org.tmatesoft.hg.repo.HgInternals; | 31 import org.tmatesoft.hg.repo.HgInternals; |
| 28 import org.tmatesoft.hg.repo.HgRepoConfig.ExtensionsSection; | 32 import org.tmatesoft.hg.repo.HgRepoConfig.ExtensionsSection; |
| 29 import org.tmatesoft.hg.repo.HgRepository; | 33 import org.tmatesoft.hg.repo.HgRepository; |
| 30 import org.tmatesoft.hg.util.PathRewrite; | 34 import org.tmatesoft.hg.util.PathRewrite; |
| 34 * | 38 * |
| 35 * @author Artem Tikhomirov | 39 * @author Artem Tikhomirov |
| 36 * @author TMate Software Ltd. | 40 * @author TMate Software Ltd. |
| 37 */ | 41 */ |
| 38 public class Internals { | 42 public class Internals { |
| 43 | |
| 44 public static final String CFG_PROPERTY_HG_INSTALL_ROOT = "hg4j.hg.install_root"; | |
| 39 | 45 |
| 40 private int requiresFlags = 0; | 46 private int requiresFlags = 0; |
| 41 private List<Filter.Factory> filterFactories; | 47 private List<Filter.Factory> filterFactories; |
| 42 | 48 |
| 43 | 49 |
| 112 } | 118 } |
| 113 | 119 |
| 114 public static boolean runningOnWindows() { | 120 public static boolean runningOnWindows() { |
| 115 return System.getProperty("os.name").indexOf("Windows") != -1; | 121 return System.getProperty("os.name").indexOf("Windows") != -1; |
| 116 } | 122 } |
| 117 | 123 |
| 124 /** | |
| 125 * For Unix, returns installation root, which is the parent directory of the hg executable (or symlink) being run. | |
| 126 * For Windows, it's Mercurial installation directory itself | |
| 127 */ | |
| 128 private static File findHgInstallRoot() { | |
| 129 // let clients to override Hg install location | |
| 130 String p = System.getProperty(CFG_PROPERTY_HG_INSTALL_ROOT); | |
| 131 if (p != null) { | |
| 132 return new File(p); | |
| 133 } | |
| 134 StringTokenizer st = new StringTokenizer(System.getenv("PATH"), System.getProperty("path.separator"), false); | |
| 135 final boolean runsOnWin = runningOnWindows(); | |
| 136 while (st.hasMoreTokens()) { | |
| 137 String pe = st.nextToken(); | |
| 138 File execCandidate = new File(pe, runsOnWin ? "hg.exe" : "hg"); | |
| 139 if (execCandidate.exists() && execCandidate.isFile()) { | |
| 140 File execDir = execCandidate.getParentFile(); | |
| 141 // e.g. on Unix runs "/shared/tools/bin/hg", directory of interest is "/shared/tools/" | |
| 142 return runsOnWin ? execDir : execDir.getParentFile(); | |
| 143 } | |
| 144 } | |
| 145 return null; | |
| 146 } | |
| 147 | |
| 148 /** | |
| 149 * @see http://www.selenic.com/mercurial/hgrc.5.html | |
| 150 */ | |
| 118 public ConfigFile readConfiguration(HgRepository hgRepo, File repoRoot) throws IOException { | 151 public ConfigFile readConfiguration(HgRepository hgRepo, File repoRoot) throws IOException { |
| 119 ConfigFile configFile = new ConfigFile(); | 152 ConfigFile configFile = new ConfigFile(); |
| 153 File hgInstallRoot = findHgInstallRoot(); // may be null | |
| 154 // | |
| 120 if (runningOnWindows()) { | 155 if (runningOnWindows()) { |
| 121 // FIXME read install-dir | 156 if (hgInstallRoot != null) { |
| 122 // | 157 for (File f : getWindowsConfigFilesPerInstall(hgInstallRoot)) { |
| 123 // XXX perhaps, makes sense to compare getenv(USERPROFILE) and getenv(HOME) and use | 158 configFile.addLocation(f); |
| 124 // them if set (and use both if their values do not match). Only if both not set, rely to user.home? | 159 } |
| 125 // Also respect #getUserConfigurationFileToWrite() below | 160 } |
| 126 configFile.addLocation(new File(System.getProperty("user.home"), "Mercurial.ini")); | 161 LinkedHashSet<String> locations = new LinkedHashSet<String>(); |
| 162 locations.add(System.getenv("USERPROFILE")); | |
| 163 locations.add(System.getenv("HOME")); | |
| 164 locations.remove(null); | |
| 165 for (String loc : locations) { | |
| 166 File location = new File(loc); | |
| 167 configFile.addLocation(new File(location, "Mercurial.ini")); | |
| 168 configFile.addLocation(new File(location, ".hgrc")); | |
| 169 } | |
| 127 } else { | 170 } else { |
| 128 // FIXME read from install-root | 171 if (hgInstallRoot != null) { |
| 129 // | 172 File d = new File(hgInstallRoot, "etc/mercurial/hgrc.d/"); |
| 130 File d = new File("/etc/mercurial/hgrc.d/"); | 173 if (d.isDirectory() && d.canRead()) { |
| 131 if (d.isDirectory()) { | 174 for (File f : listConfigFiles(d)) { |
| 132 for (File f : d.listFiles()) { | |
| 133 // XXX in fact, need to sort in alphabetical order | |
| 134 if (f.getName().endsWith(".rc")) { | |
| 135 configFile.addLocation(f); | 175 configFile.addLocation(f); |
| 136 } | 176 } |
| 137 } | 177 } |
| 178 configFile.addLocation(new File(hgInstallRoot, "etc/mercurial/hgrc")); | |
| 179 } | |
| 180 // same, but with absolute paths | |
| 181 File d = new File("/etc/mercurial/hgrc.d/"); | |
| 182 if (d.isDirectory() && d.canRead()) { | |
| 183 for (File f : listConfigFiles(d)) { | |
| 184 configFile.addLocation(f); | |
| 185 } | |
| 138 } | 186 } |
| 139 configFile.addLocation(new File("/etc/mercurial/hgrc")); | 187 configFile.addLocation(new File("/etc/mercurial/hgrc")); |
| 140 } | 188 configFile.addLocation(new File(System.getenv("HOME"), ".hgrc")); |
| 141 configFile.addLocation(new File(System.getProperty("user.home"), ".hgrc")); | 189 } |
| 142 // last one, overrides anything else | 190 // last one, overrides anything else |
| 143 // <repo>/.hg/hgrc | 191 // <repo>/.hg/hgrc |
| 144 configFile.addLocation(new File(repoRoot, "hgrc")); | 192 configFile.addLocation(new File(repoRoot, "hgrc")); |
| 145 return configFile; | 193 return configFile; |
| 146 } | 194 } |
| 147 | 195 |
| 148 /** | 196 private static List<File> getWindowsConfigFilesPerInstall(File hgInstallDir) { |
| 149 * @return | 197 File f = new File(hgInstallDir, "Mercurial.ini"); |
| 150 */ | 198 if (f.exists()) { |
| 199 return Collections.singletonList(f); | |
| 200 } | |
| 201 f = new File(hgInstallDir, "hgrc.d/"); | |
| 202 if (f.canRead() && f.isDirectory()) { | |
| 203 return listConfigFiles(f); | |
| 204 } | |
| 205 // FIXME query registry, e.g. with | |
| 206 // Runtime.exec("reg query HKLM\Software\Mercurial") | |
| 207 // | |
| 208 f = new File("C:\\Mercurial\\Mercurial.ini"); | |
| 209 if (f.exists()) { | |
| 210 return Collections.singletonList(f); | |
| 211 } | |
| 212 return Collections.emptyList(); | |
| 213 } | |
| 214 | |
| 215 private static List<File> listConfigFiles(File dir) { | |
| 216 assert dir.canRead(); | |
| 217 assert dir.isDirectory(); | |
| 218 final File[] allFiles = dir.listFiles(); | |
| 219 // File is Comparable, lexicographically by default | |
| 220 Arrays.sort(allFiles); | |
| 221 ArrayList<File> rv = new ArrayList<File>(allFiles.length); | |
| 222 for (File f : allFiles) { | |
| 223 if (f.getName().endsWith(".rc")) { | |
| 224 rv.add(f); | |
| 225 } | |
| 226 } | |
| 227 return rv; | |
| 228 } | |
| 229 | |
| 151 public static File getInstallationConfigurationFileToWrite() { | 230 public static File getInstallationConfigurationFileToWrite() { |
| 152 // TODO Auto-generated method stub | 231 File hgInstallRoot = findHgInstallRoot(); // may be null |
| 153 // FIXME find out install-root | 232 // choice of which hgrc to pick here is according to my own pure discretion |
| 154 throw new UnsupportedOperationException(); | 233 if (hgInstallRoot != null) { |
| 155 } | 234 // use this location only if it's writable |
| 156 | 235 File cfg = new File(hgInstallRoot, runningOnWindows() ? "Mercurial.ini" : "etc/mercurial/hgrc"); |
| 157 /** | 236 if (cfg.canWrite() || cfg.getParentFile().canWrite()) { |
| 158 * @return | 237 return cfg; |
| 159 */ | 238 } |
| 239 } | |
| 240 // fallback | |
| 241 if (runningOnWindows()) { | |
| 242 if (hgInstallRoot == null) { | |
| 243 return new File("C:\\Mercurial\\Mercurial.ini"); | |
| 244 } else { | |
| 245 // yes, we tried this file already (above) and found it non-writable | |
| 246 // let caller fail with can't write | |
| 247 return new File(hgInstallRoot, "Mercurial.ini"); | |
| 248 } | |
| 249 } else { | |
| 250 return new File("/etc/mercurial/hgrc"); | |
| 251 } | |
| 252 } | |
| 253 | |
| 160 public static File getUserConfigurationFileToWrite() { | 254 public static File getUserConfigurationFileToWrite() { |
| 161 final File rv = new File(System.getProperty("user.home"), ".hgrc"); | 255 LinkedHashSet<String> locations = new LinkedHashSet<String>(); |
| 162 if (rv.exists() && rv.canWrite()) { | 256 final boolean runsOnWindows = runningOnWindows(); |
| 163 return rv; | 257 if (runsOnWindows) { |
| 164 } | 258 locations.add(System.getenv("USERPROFILE")); |
| 165 if (runningOnWindows()) { | 259 } |
| 166 // try another well-known location | 260 locations.add(System.getenv("HOME")); |
| 167 // TODO comment above regarding USERPROFILE and HOME variables applies here as well | 261 locations.remove(null); |
| 168 File f = new File(System.getProperty("user.home"), "Mercurial.ini"); | 262 for (String loc : locations) { |
| 169 if (f.exists() && f.canWrite()) { | 263 File location = new File(loc); |
| 170 return f; | 264 File rv = new File(location, ".hgrc"); |
| 171 } | 265 if (rv.exists() && rv.canWrite()) { |
| 172 } | 266 return rv; |
| 173 // fallback to default value | 267 } |
| 174 return rv; | 268 if (runsOnWindows) { |
| 269 rv = new File(location, "Mercurial.ini"); | |
| 270 if (rv.exists() && rv.canWrite()) { | |
| 271 return rv; | |
| 272 } | |
| 273 } | |
| 274 } | |
| 275 // fallback to default, let calling code fail with Exception if can't write | |
| 276 return new File(System.getProperty("user.home"), ".hgrc"); | |
| 175 } | 277 } |
| 176 } | 278 } |
