tikhomirov@74: /* tikhomirov@74: * Copyright (c) 2010-2011 TMate Software Ltd tikhomirov@74: * tikhomirov@74: * This program is free software; you can redistribute it and/or modify tikhomirov@74: * it under the terms of the GNU General Public License as published by tikhomirov@74: * the Free Software Foundation; version 2 of the License. tikhomirov@74: * tikhomirov@74: * This program is distributed in the hope that it will be useful, tikhomirov@74: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@74: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@74: * GNU General Public License for more details. tikhomirov@74: * tikhomirov@74: * For information on how to redistribute this software under tikhomirov@74: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@2: */ tikhomirov@74: package org.tmatesoft.hg.repo; tikhomirov@2: tikhomirov@2: import java.io.File; tikhomirov@148: import java.io.IOException; tikhomirov@181: import java.net.MalformedURLException; tikhomirov@170: import java.net.URL; tikhomirov@148: tikhomirov@181: import org.tmatesoft.hg.core.HgBadArgumentException; tikhomirov@423: import org.tmatesoft.hg.core.HgRepositoryNotFoundException; tikhomirov@295: import org.tmatesoft.hg.core.SessionContext; tikhomirov@295: import org.tmatesoft.hg.internal.BasicSessionContext; tikhomirov@181: import org.tmatesoft.hg.internal.ConfigFile; tikhomirov@169: import org.tmatesoft.hg.internal.DataAccessProvider; tikhomirov@2: tikhomirov@2: /** tikhomirov@148: * Utility methods to find Mercurial repository at a given location tikhomirov@74: * tikhomirov@74: * @author Artem Tikhomirov tikhomirov@74: * @author TMate Software Ltd. tikhomirov@2: */ tikhomirov@95: public class HgLookup { tikhomirov@2: tikhomirov@181: private ConfigFile globalCfg; tikhomirov@295: private SessionContext sessionContext; tikhomirov@295: tikhomirov@295: public HgLookup() { tikhomirov@295: } tikhomirov@295: tikhomirov@295: public HgLookup(SessionContext ctx) { tikhomirov@295: sessionContext = ctx; tikhomirov@295: } tikhomirov@181: tikhomirov@423: public HgRepository detectFromWorkingDir() throws HgRepositoryNotFoundException { tikhomirov@2: return detect(System.getProperty("user.dir")); tikhomirov@2: } tikhomirov@2: tikhomirov@423: public HgRepository detect(String location) throws HgRepositoryNotFoundException { tikhomirov@95: return detect(new File(location)); tikhomirov@95: } tikhomirov@95: tikhomirov@95: // look up in specified location and above tikhomirov@423: public HgRepository detect(File location) throws HgRepositoryNotFoundException { tikhomirov@423: try { tikhomirov@423: File dir = location.getAbsoluteFile(); tikhomirov@423: File repository; tikhomirov@423: do { tikhomirov@423: repository = new File(dir, ".hg"); tikhomirov@423: if (repository.exists() && repository.isDirectory()) { tikhomirov@423: break; tikhomirov@423: } tikhomirov@423: repository = null; tikhomirov@423: dir = dir.getParentFile(); tikhomirov@423: tikhomirov@423: } while(dir != null); tikhomirov@423: if (repository == null) { tikhomirov@423: throw new HgRepositoryNotFoundException(String.format("Can't locate .hg/ directory of Mercurial repository in %s nor in parent dirs", location)).setLocation(location.getPath()); tikhomirov@2: } tikhomirov@148: String repoPath = repository.getParentFile().getCanonicalPath(); tikhomirov@295: return new HgRepository(getContext(), repoPath, repository); tikhomirov@148: } catch (IOException ex) { tikhomirov@423: HgRepositoryNotFoundException t = new HgRepositoryNotFoundException("Failed to access repository"); tikhomirov@423: t.setLocation(location.getPath()).initCause(ex); tikhomirov@423: throw t; tikhomirov@148: } tikhomirov@4: } tikhomirov@169: tikhomirov@425: public HgBundle loadBundle(File location) throws HgRepositoryNotFoundException { tikhomirov@169: if (location == null || !location.canRead()) { tikhomirov@425: throw new HgRepositoryNotFoundException(String.format("Can't read file %s", location)).setLocation(String.valueOf(location)); tikhomirov@169: } tikhomirov@357: return new HgBundle(getContext(), new DataAccessProvider(getContext()), location).link(); tikhomirov@169: } tikhomirov@181: tikhomirov@181: /** tikhomirov@181: * Try to instantiate remote server. tikhomirov@181: * @param key either URL or a key from configuration file that points to remote server tikhomirov@181: * @param hgRepo NOT USED YET local repository that may have extra config, or default remote location tikhomirov@181: * @return an instance featuring access to remote repository, check {@link HgRemoteRepository#isInvalid()} before actually using it tikhomirov@181: * @throws HgBadArgumentException if anything is wrong with the remote server's URL tikhomirov@181: */ tikhomirov@181: public HgRemoteRepository detectRemote(String key, HgRepository hgRepo) throws HgBadArgumentException { tikhomirov@181: URL url; tikhomirov@181: Exception toReport; tikhomirov@181: try { tikhomirov@181: url = new URL(key); tikhomirov@181: toReport = null; tikhomirov@181: } catch (MalformedURLException ex) { tikhomirov@181: url = null; tikhomirov@181: toReport = ex; tikhomirov@181: } tikhomirov@181: if (url == null) { tikhomirov@181: String server = getGlobalConfig().getSection("paths").get(key); tikhomirov@181: if (server == null) { tikhomirov@181: throw new HgBadArgumentException(String.format("Can't find server %s specification in the config", key), toReport); tikhomirov@181: } tikhomirov@181: try { tikhomirov@181: url = new URL(server); tikhomirov@181: } catch (MalformedURLException ex) { tikhomirov@181: throw new HgBadArgumentException(String.format("Found %s server spec in the config, but failed to initialize with it", key), ex); tikhomirov@181: } tikhomirov@181: } tikhomirov@295: return new HgRemoteRepository(getContext(), url); tikhomirov@181: } tikhomirov@181: tikhomirov@295: public HgRemoteRepository detect(URL url) throws HgBadArgumentException { tikhomirov@171: if (url == null) { tikhomirov@171: throw new IllegalArgumentException(); tikhomirov@171: } tikhomirov@170: if (Boolean.FALSE.booleanValue()) { tikhomirov@170: throw HgRepository.notImplemented(); tikhomirov@170: } tikhomirov@295: return new HgRemoteRepository(getContext(), url); tikhomirov@170: } tikhomirov@181: tikhomirov@181: private ConfigFile getGlobalConfig() { tikhomirov@181: if (globalCfg == null) { tikhomirov@295: globalCfg = new ConfigFile(); tikhomirov@295: try { tikhomirov@295: globalCfg.addLocation(new File(System.getProperty("user.home"), ".hgrc")); tikhomirov@295: } catch (IOException ex) { tikhomirov@295: // XXX perhaps, makes sense to let caller/client know that we've failed to read global config? tikhomirov@295: getContext().getLog().warn(getClass(), ex, null); tikhomirov@295: } tikhomirov@181: } tikhomirov@181: return globalCfg; tikhomirov@181: } tikhomirov@295: tikhomirov@295: private SessionContext getContext() { tikhomirov@295: if (sessionContext == null) { tikhomirov@295: sessionContext = new BasicSessionContext(null, null); tikhomirov@295: } tikhomirov@295: return sessionContext; tikhomirov@295: } tikhomirov@2: }