All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.common.config.Repositories Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
package com.redhat.ceylon.common.config;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.redhat.ceylon.common.Constants;
import com.redhat.ceylon.common.FileUtil;

/**
 * Repositories is a wrapper around a CeylonConfig object providing easy access to
 * repository related configuration information. 
 * 
 * Ceylon uses a set of local and remote repositories for its modules.
 * The order and significance of the lookup (which is fixed) is:
 * 
 *   system - Essential system modules
 *   cache  - A cache of modules that were previously downloaded from remote repositories
 *   output - Where the compiler stores newly created modules
 *   lookup - User-defined local repositories
 *   global - Predefined non-remote repositories
 *   remote - User defined remote repositories
 *   other  - Predefined remote repositories (like Herd)
 *   
 * The "system" section by default contains a reference to the system global repository,
 * which by default is +SYSTEM (see below). Do not override.
 * 
 * The "cache" section is where modules downloaded from remote repositories are kept so they
 * don't have to be downloaded each time. By default this is +CACHE (see below).
 * 
 * The "output" section is where newly compiled modules are stored. By default this is "./modules".
 *  
 * The "lookup" section is for modules local to the project and other user-defined
 * repositories. By default this is +LOCAL (see below).
 *  
 * The "global" section is meant for predefined, essential, non-remote repositories.
 * By default this is +USER (see below). It's normally not advisable to override this.
 *  
 * The "remote" section is meant for user-defined remote repositories. By default this is empty.
 * 
 * The "other" section is meant for predefined, essential, remote repositories. By default
 * this is +REMOTE (see below). It's normally not advisable to override this.
 *  
 * The [repositories] section in a configuration file can be used to override the default
 * values for those entries thereby changing or extending the lookup order. Take a look at
 * the following example:
 * 
 *   [repositories]
 *   output=./output # Store new modules in the local `output` folder
 *   cache=/huge-disk/tom/ceylon/repocache # Store the cached modules on a bigger disk
 *   lookup=./modules
 *   lookup=./extra-modules
 *   lookup=/usr/local/ceylon/even-more-modules
 *   remote=http://ceylon.example.com # An external site with Ceylon modules
 *
 * First of all, the values for output and cache (as well as system, but you should normally
 * never try overriding it) can only be specified once, while the others (lookup, global and
 * remote) can be specified multiple times, Ceylon will try them one by one in the order you
 * specify in this list.
 * 
 * NB: When we say "in the order you specify" we refer to the ones with the same key name,
 * so if you add several remote repositories they will be tried in the order you specify,
 * but you cannot change the main ordering: lookup repositories will always be tried before
 * global, which will always be tried before remote.
 * 
 * The remote entry doesn't have any default value, so it can be easily used without having to
 * worry about preexisting values. It's specifically meant to add extra (normally remote)
 * repositories that will be tried after all other options have been exhausted.
 * 
 * It's also possible to define single repositories in their own named sections. Either so
 * you can easily refer to them by name or because you need to specify credentials in case
 * of repositories that need authentication. For example:
 * 
 *   [repository "Test"]
 *   url=https://modules.ceylon-lang.org/repo/1
 *   user=john
 *   password=secret
 *   
 * You can then refer to that from with the [repositories] section like this (see the + sign):
 * 
 *   [repositories]
 *   output=+Test
 *   
 * Or from the command line:
 * 
 *   ceylon compile --out +Test com.example.helloworld
 *   
 * There are several predefined repositories like this that have default values but that can
 * be overridden by explicitly redefining them in the configuration file. These repositories are:
 * 
 *   SYSTEM - Which normally is something like "%CEYLONHOME%/repo". Do not override.
 *   
 *   LOCAL -  By default this is "./modules".
 *   
 *   CACHE -  By default this points to "%USER_HOME%/.ceylon/cache".
 *   
 *   USER -   By default this is "%USER_HOME%/.ceylon/repo". It's normally not advisable to override this.
 *   
 *   REMOTE - By default this is points to the official Ceylon Herd repository. It's normally not advisable
 *            to override this.
 * 
 * @author Tako Schotanus ([email protected])
 */
public class Repositories {
    private CeylonConfig config;
    
    private static final String SECTION_REPOSITORY = "repository";
    private static final String SECTION_REPOSITORIES = "repositories";

    public static final String REPO_TYPE_SYSTEM = "system";
    public static final String REPO_TYPE_OUTPUT = "output";
    public static final String REPO_TYPE_CACHE = "cache";
    public static final String REPO_TYPE_LOCAL_LOOKUP = "lookup";
    public static final String REPO_TYPE_GLOBAL_LOOKUP = "global";
    public static final String REPO_TYPE_REMOTE_LOOKUP = "remote";
    public static final String REPO_TYPE_OTHER_LOOKUP = "other";
    
    private static final String REPO_NAME_SYSTEM = "SYSTEM";
    private static final String REPO_NAME_LOCAL = "LOCAL";
    private static final String REPO_NAME_CACHE = "CACHE";
    private static final String REPO_NAME_USER = "USER";
    private static final String REPO_NAME_REMOTE = "REMOTE";
    private static final String REPO_NAME_MAVEN = "MAVEN";
    private static final String REPO_NAME_NPM = "NPM";
    
    private static final String ITEM_PASSWORD = "password";
    private static final String ITEM_PASSWORD_KS = "password-keystore";
    private static final String ITEM_PASSWORD_KS_ALIAS = "password-alias";
    private static final String ITEM_USER = "user";
    private static final String ITEM_URL = "url";
    
    private static Repositories instance;
    
    public static Repositories get() {
        if (instance == null) {
            instance = new Repositories();
        }
        return instance;
    }
    
    public static void set(Repositories repos) {
        instance = repos;
    }
    
    public static Repositories withConfig(CeylonConfig config) {
        return new Repositories(config);
    }
    
    public interface Repository {
        public String getName();
        public String getUrl();
        public Credentials getCredentials();
    }
    
    public static class SimpleRepository implements Repository {

        private final String name;
        private final String url;
        private final Credentials credentials;
        
        public String getName() {
            return name;
        }
        
        public String getUrl() {
            return url;
        }
        
        public Credentials getCredentials() {
            return credentials;
        }

        public SimpleRepository(String name, String url, Credentials credentials) {
            this.name = name;
            if (url.startsWith("~/") || url.startsWith("~\\")) {
                url = new File(System.getProperty("user.home"), url.substring(2)).getPath();
            }
            this.url = url;
            this.credentials = credentials;
        }
    }
    
    public static class RepositoryRef implements Repository {
        private final Repository ref;
        
        public String getName() {
            return ref.getName();
        }
        
        public String getUrl() {
            return ref.getUrl();
        }
        
        public Credentials getCredentials() {
            return ref.getCredentials();
        }

        public RepositoryRef(Repository ref) {
            this.ref= ref;
        }
    }
    
    private Repositories() {
        this(CeylonConfig.get());
    }
    
    private Repositories(CeylonConfig config) {
        this.config = config;
    }
    
    private String repoKey(String repoName, String itemName) {
        return SECTION_REPOSITORY + "." + repoName + "." + itemName;
    }
    
    public Repository getRepository(String repoName) {
        String url = config.getOption(repoKey(repoName, ITEM_URL));
        if (url != null) {
            String user = config.getOption(repoKey(repoName, ITEM_USER));
            String password = config.getOption(repoKey(repoName, ITEM_PASSWORD));
            final String alias = config.getOption(repoKey(repoName, ITEM_PASSWORD_KS_ALIAS));
            String keystore = config.getOption(repoKey(repoName, ITEM_PASSWORD_KS));
            String prompt = ConfigMessages.msg("repository.password.prompt", user, url);
            Credentials credentials = Credentials.create(user, password, keystore, alias, prompt);
            return new SimpleRepository(repoName, url, credentials);
        } else {
            if (REPO_NAME_SYSTEM.equals(repoName)) {
                File dir = getSystemRepoDir();
                if (dir != null) {
                    // $INSTALLDIR/repo
                    return new SimpleRepository(REPO_NAME_SYSTEM, dir.getAbsolutePath(), null);
                }
            } else if (REPO_NAME_LOCAL.equals(repoName)) {
                // ./modules
                File dir = new File(".", Constants.DEFAULT_MODULE_DIR);
                return new SimpleRepository(REPO_NAME_LOCAL, dir.getPath(), null);
            } else if (REPO_NAME_CACHE.equals(repoName)) {
                // $HOME/.ceylon/cache
                File dir = getCacheRepoDir();
                return new SimpleRepository(REPO_NAME_CACHE, dir.getAbsolutePath(), null);
            } else if (REPO_NAME_USER.equals(repoName)) {
                // $HOME/.ceylon/repo
                File userRepoDir = getUserRepoDir();
                return new SimpleRepository(REPO_NAME_USER, userRepoDir.getAbsolutePath(), null);
            } else if (REPO_NAME_REMOTE.equals(repoName)) {
                // https://modules.ceylon-lang.org
                return new SimpleRepository(REPO_NAME_REMOTE, Constants.REPO_URL_CEYLON, null);
            } else if (REPO_NAME_MAVEN.equals(repoName)) {
                // aether:
                return new SimpleRepository(REPO_NAME_MAVEN, "aether:", null);
            } else if (REPO_NAME_NPM.equals(repoName)) {
                // npm:
                return new SimpleRepository(REPO_NAME_NPM, "npm:", null);
            }
            return null;
        }
    }
    
    private String reposTypeKey(String repoType) {
        return SECTION_REPOSITORIES + "." + repoType;
    }
    
    public Repository[] getRepositoriesByType(String repoType) {
        String urls[] = config.getOptionValues(reposTypeKey(repoType));
        if (urls != null) {
            ArrayList repos = new ArrayList(urls.length);
            for (int i = 0; i < urls.length; i++) {
                String url = urls[i];
                Repository repo;
                if (url.startsWith("+")) {
                    String name = url.substring(1);
                    repo = new RepositoryRef(getRepository(name));
                } else {
                    String name = "%" + repoType + "-" + (i + 1);
                    repo = new SimpleRepository(name, url, null);
                }
                if (repo != null) {
                    repos.add(repo);
                }
            }
            if (!repos.isEmpty()) {
                Repository[] result = new Repository[repos.size()];
                return repos.toArray(result);
            }
        }
        return null;
    }
    
    public Repository[] getRepositoriesByTypeWithDefaults(String repoType) {
        if (repoType.equals(REPO_TYPE_SYSTEM)) {
            return new Repository[] { getSystemRepository() };
        } else if (repoType.equals(REPO_TYPE_OUTPUT)) {
            return new Repository[] { getOutputRepository() };
        } else if (repoType.equals(REPO_TYPE_CACHE)) {
            return new Repository[] { getCacheRepository() };
        }  else if (repoType.equals(REPO_TYPE_LOCAL_LOOKUP)) {
            return getLocalLookupRepositories();
        }  else if (repoType.equals(REPO_TYPE_GLOBAL_LOOKUP)) {
            return getGlobalLookupRepositories();
        }  else if (repoType.equals(REPO_TYPE_REMOTE_LOOKUP)) {
            return getRemoteLookupRepositories();
        }  else if (repoType.equals(REPO_TYPE_OTHER_LOOKUP)) {
            return getOtherLookupRepositories();
        } else {
            return getRepositoriesByType(repoType);
        }
    }
    
    public Repository getRepositoryByType(String repoType) {
        Repository[] repos = getRepositoriesByType(repoType);
        if (repos != null) {
            return repos[0];
        } else {
            return null;
        }
    }
    
    public Repository getRepositoryByTypeWithDefaults(String repoType) {
        Repository[] repos = getRepositoriesByTypeWithDefaults(repoType);
        if (repos != null) {
            return repos[0];
        } else {
            return null;
        }
    }
    
    public void setRepositoriesByType(String repoType, Repository[] repos) {
        String key = reposTypeKey(repoType);
        if (repos != null) {
            ArrayList urls = new ArrayList(repos.length);
            for (Repository repo : repos) {
                String url;
                if (repo instanceof RepositoryRef) {
                    url = "+" + repo.getName();
                } else {
                    url = repo.getUrl();
                }
                urls.add(url);
            }
            if (!urls.isEmpty()) {
                String[] values = new String[urls.size()];
                config.setOptionValues(key, urls.toArray(values));
            } else {
                config.removeOption(key);
            }
        } else {
            config.removeOption(key);
        }
    }
    
    public Map getRepositories() {
        HashMap repos = new HashMap();
        repos.put(REPO_TYPE_SYSTEM, getRepositoriesByType(REPO_TYPE_SYSTEM));
        repos.put(REPO_TYPE_OUTPUT, getRepositoriesByType(REPO_TYPE_OUTPUT));
        repos.put(REPO_TYPE_CACHE, getRepositoriesByType(REPO_TYPE_CACHE));
        repos.put(REPO_TYPE_LOCAL_LOOKUP, getRepositoriesByType(REPO_TYPE_LOCAL_LOOKUP));
        repos.put(REPO_TYPE_GLOBAL_LOOKUP, getRepositoriesByType(REPO_TYPE_GLOBAL_LOOKUP));
        repos.put(REPO_TYPE_REMOTE_LOOKUP, getRepositoriesByType(REPO_TYPE_REMOTE_LOOKUP));
        repos.put(REPO_TYPE_OTHER_LOOKUP, getRepositoriesByType(REPO_TYPE_OTHER_LOOKUP));
        return repos;
    }
    
    public void setRepositories(Map repos) {
        setRepositoriesByType(REPO_TYPE_SYSTEM, repos.get(REPO_TYPE_SYSTEM));
        setRepositoriesByType(REPO_TYPE_OUTPUT, repos.get(REPO_TYPE_OUTPUT));
        setRepositoriesByType(REPO_TYPE_CACHE, repos.get(REPO_TYPE_CACHE));
        setRepositoriesByType(REPO_TYPE_LOCAL_LOOKUP, repos.get(REPO_TYPE_LOCAL_LOOKUP));
        setRepositoriesByType(REPO_TYPE_GLOBAL_LOOKUP, repos.get(REPO_TYPE_GLOBAL_LOOKUP));
        setRepositoriesByType(REPO_TYPE_REMOTE_LOOKUP, repos.get(REPO_TYPE_REMOTE_LOOKUP));
        setRepositoriesByType(REPO_TYPE_OTHER_LOOKUP, repos.get(REPO_TYPE_OTHER_LOOKUP));
    }
    
    public File getSystemRepoDir() {
        String ceylonSystemRepo = System.getProperty(Constants.PROP_CEYLON_SYSTEM_REPO);
        if (ceylonSystemRepo != null) {
            return new File(ceylonSystemRepo);
        } else {
            File userDir = FileUtil.getInstallDir();
            if (userDir != null) {
                return new File(userDir, "repo");
            }
        }
        return null;
    }
    
    public File getUserRepoDir() {
        String ceylonUserRepo = System.getProperty(Constants.PROP_CEYLON_USER_REPO);
        if (ceylonUserRepo != null) {
            return new File(ceylonUserRepo);
        } else {
            File userDir = FileUtil.getUserDir();
            return new File(userDir, "repo");
        }
    }
    
    public File getCacheRepoDir() {
        String ceylonUserRepo = System.getProperty(Constants.PROP_CEYLON_CACHE_REPO);
        if (ceylonUserRepo != null) {
            return new File(ceylonUserRepo);
        } else {
            File userDir = FileUtil.getUserDir();
            return new File(userDir, "cache");
        }
    }
    
    public Repository getSystemRepository() {
        Repository repo = getRepositoryByType(REPO_TYPE_SYSTEM);
        if (repo == null) {
            repo = getRepository(REPO_NAME_SYSTEM);
        }
        return repo;
    }
    
    public Repository getOutputRepository() {
        Repository repo = getRepositoryByType(REPO_TYPE_OUTPUT);
        if (repo == null) {
            repo = getRepository(REPO_NAME_LOCAL);
        }
        return repo;
    }
    
    public Repository getCacheRepository() {
        Repository repo = getRepositoryByType(REPO_TYPE_CACHE);
        if (repo == null) {
            repo = getRepository(REPO_NAME_CACHE);
        }
        return repo;
    }
    
    public Repository[] getLocalLookupRepositories() {
        Repository[] repos = getRepositoriesByType(REPO_TYPE_LOCAL_LOOKUP);
        if (repos == null) {
            repos = new Repository[1];
            // By default "./modules"
            repos[0] = getRepository(REPO_NAME_LOCAL);
        }
        return repos;
    }
    
    public Repository[] getGlobalLookupRepositories() {
        Repository[] repos = getRepositoriesByType(REPO_TYPE_GLOBAL_LOOKUP);
        if (repos == null) {
            repos = new Repository[1];
            // By default "$HOME/.ceylon/repo"
            repos[0] = getRepository(REPO_NAME_USER);
        }
        return repos;
    }
    
    public Repository[] getRemoteLookupRepositories() {
        Repository[] repos = getRepositoriesByType(REPO_TYPE_REMOTE_LOOKUP);
        if (repos == null) {
            repos = new Repository[0];
        }
        return repos;
    }
    
    public Repository[] getOtherLookupRepositories() {
        Repository[] repos = getRepositoriesByType(REPO_TYPE_OTHER_LOOKUP);
        if (repos == null) {
            repos = new Repository[3];
            // By default "https://modules.ceylon-lang.org" and "aether:"
            repos[0] = getRepository(REPO_NAME_REMOTE);
            repos[1] = getRepository(REPO_NAME_MAVEN);
            repos[2] = getRepository(REPO_NAME_NPM);
        }
        return repos;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy