/*
* Copyright 2012 James Moger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.moxie;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.moxie.Constants.MavenCacheStrategy;
import org.moxie.maxml.MaxmlException;
import org.moxie.maxml.MaxmlMap;
import org.moxie.utils.Base64;
import org.moxie.utils.StringUtils;
/**
* Represents the effective build configuration (build.moxie, settings.moxie).
*/
public class BuildConfig {
private final Set<Proxy> proxies;
private final Set<Repository> repositories;
private final Map<String, Dependency> aliases;
private final ToolkitConfig toolkitConfig;
private final ToolkitConfig projectConfig;
private final File moxieRoot;
private final File projectConfigFile;
private final File projectDirectory;
private boolean verbose;
public BuildConfig(File configFile, File basedir) throws MaxmlException, IOException {
this.projectConfigFile = configFile;
if (basedir == null) {
this.projectDirectory = configFile.getAbsoluteFile().getParentFile();
} else {
this.projectDirectory = basedir;
}
// allow specifying Moxie root folder
this.moxieRoot = Toolkit.getMxRoot();
this.moxieRoot.mkdirs();
this.toolkitConfig = new ToolkitConfig(new File(moxieRoot, Toolkit.MOXIE_SETTINGS), projectDirectory, Toolkit.MOXIE_SETTINGS);
this.projectConfig = new ToolkitConfig(configFile, projectDirectory, Toolkit.MOXIE_DEFAULTS);
this.proxies = new LinkedHashSet<Proxy>();
this.repositories = new LinkedHashSet<Repository>();
this.aliases = new HashMap<String, Dependency>();
determineProxies();
determineRepositories();
determineAliases();
}
@Override
public int hashCode() {
return 11 + projectConfigFile.hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof BuildConfig) {
return projectConfigFile.equals(((BuildConfig) o).projectConfigFile);
}
return false;
}
public boolean isColor() {
String mxColor = System.getenv("MX_COLOR");
mxColor = System.getProperty(Toolkit.MX_COLOR, mxColor);
if (StringUtils.isEmpty(mxColor)) {
// unspecified
return false;
} else {
// use system property to determine color
return Boolean.parseBoolean(mxColor);
}
}
public boolean isDebug() {
String mxDebug = System.getenv("MX_DEBUG");
mxDebug = System.getProperty(Toolkit.MX_DEBUG, mxDebug);
if (StringUtils.isEmpty(mxDebug)) {
// unspecified
return false;
} else {
// use system property to determine debug
return Boolean.parseBoolean(mxDebug);
}
}
public boolean isVerbose() {
String mxVerbose = System.getenv("MX_VERBOSE");
mxVerbose = System.getProperty(Toolkit.MX_VERBOSE, mxVerbose);
if (StringUtils.isEmpty(mxVerbose)) {
// unspecified
return verbose;
} else {
// use system property to determine verbose
return Boolean.parseBoolean(mxVerbose);
}
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public boolean isParallelDownloads() {
return toolkitConfig.parallelDownloads;
}
public boolean isFailFastOnArtifactResolution() {
return toolkitConfig.failFastOnArtifactResolution;
}
public UpdatePolicy getUpdatePolicy() {
return toolkitConfig.updatePolicy;
}
public PurgePolicy getPurgePolicy() {
return toolkitConfig.getPurgePolicy();
}
public MavenCacheStrategy getMavenCacheStrategy() {
if (toolkitConfig.mavenCacheStrategy != null) {
return toolkitConfig.mavenCacheStrategy;
}
return MavenCacheStrategy.IGNORE;
}
private void determineProxies() {
proxies.addAll(projectConfig.getActiveProxies());
proxies.addAll(toolkitConfig.getActiveProxies());
// add M2 defined proxies last since they can only define host exclusions
File m2Settings = new File(System.getProperty("user.home"), "/.m2/settings.xml");
if (m2Settings.exists()) {
Settings settings = SettingsReader.readSettings(m2Settings);
proxies.addAll(settings.getActiveProxies());
}
}
private void determineRepositories() {
List<RemoteRepository> registrations = new ArrayList<RemoteRepository>();
registrations.addAll(projectConfig.registeredRepositories);
registrations.addAll(toolkitConfig.registeredRepositories);
for (String url : projectConfig.repositories) {
if (url.equalsIgnoreCase(GoogleCode.ID)) {
// GoogleCode-sourced artifact
repositories.add(new GoogleCode());
continue;
}
boolean added = false;
for (RemoteRepository definition : registrations) {
if (definition.url.equalsIgnoreCase(url) || definition.id.equalsIgnoreCase(url)) {
repositories.add(new Repository(definition));
added = true;
break;
}
}
if (!added) {
// just add url and use hostname as name
String name = url.substring(url.indexOf("://") + 3);
if (name.indexOf('/') > -1) {
name = name.substring(0, name.lastIndexOf('/'));
}
repositories.add(new Repository(name, url));
}
}
}
private void determineAliases() {
aliases.clear();
aliases.putAll(toolkitConfig.dependencyAliases);
aliases.putAll(projectConfig.dependencyAliases);
}
public File getMoxieRoot() {
return moxieRoot;
}
public ToolkitConfig getMoxieConfig() {
return toolkitConfig;
}
public ToolkitConfig getProjectConfig() {
return projectConfig;
}
public Pom getPom() {
return projectConfig.pom;
}
public MaxmlMap getTaskAttributes(String taskname) {
return projectConfig.tasks.getMap(taskname);
}
public Map<String, String> getExternalProperties() {
return projectConfig.externalProperties;
}
public Map<String, Dependency> getAliases() {
return aliases;
}
public List<SourceDirectory> getSourceDirectories() {
return projectConfig.sourceDirectories;
}
public List<File> getSourceDirectories(Scope scope) {
return getSourceDirectories(scope, null);
}
public List<File> getSourceDirectories(Scope scope, String tag) {
return getDirectories(scope, tag, projectConfig.sourceDirectories);
}
public List<SourceDirectory> getResourceDirectories() {
return projectConfig.resourceDirectories;
}
public List<File> getResourceDirectories(Scope scope) {
return getResourceDirectories(scope, null);
}
public List<File> getResourceDirectories(Scope scope, String tag) {
return getDirectories(scope, tag, projectConfig.resourceDirectories);
}
private List<File> getDirectories(Scope scope, String tag, List<SourceDirectory> directories) {
List<File> dirs = new ArrayList<File>();
for (SourceDirectory sourceFolder : directories) {
if (scope == null || sourceFolder.scope.equals(scope)) {
if (StringUtils.isEmpty(tag) || sourceFolder.tags.contains(tag.toLowerCase())) {
dirs.add(sourceFolder.getSources());
}
}
}
return dirs;
}
public List<Module> getModules() {
return projectConfig.modules;
}
public Collection<Repository> getRepositories() {
return new ArrayList<Repository>(repositories);
}
public Collection<RemoteRepository> getRepositoryDefinitions() {
List<RemoteRepository> list = new ArrayList<RemoteRepository>();
for (Repository repository : repositories) {
list.add(repository.getDefinition());
}
return list;
}
public Repository getRepository(String name) {
for (Repository repository : repositories) {
if (repository.name.equalsIgnoreCase(name)) {
return repository;
}
}
return null;
}
/**
* Return a list of repositories to check for the dependency. Affinity,
* dependency origin, and the repository prefix index are all considered
* when ordering the repositories.
*
* @param dep
* @return a list of repositories
*/
public Collection<Repository> getRepositories(final Dependency dep) {
if (repositories.size() == 1) {
return repositories;
}
// origin and affinity trump the prefix index
Repository preferredRepository = null;
List<Repository> list = new ArrayList<Repository>();
for (Repository repository : repositories) {
list.add(repository);
if (preferredRepository == null) {
if (repository.hasAffinity(dep)) {
// repository affinity based on package and maybe artifact
preferredRepository = repository;
//System.out.println(repository.name + " has affinity for " + dep.getCoordinates());
} else if (!StringUtils.isEmpty(dep.origin)) {
// origin preference
if (dep.origin.equalsIgnoreCase(repository.repositoryUrl)) {
//System.out.println(repository.repositoryUrl + " " + dep.getCoordinates());
preferredRepository = repository;
}
}
}
}
// temporarily remove the preferred repository
if (preferredRepository != null) {
list.remove(preferredRepository);
}
// Sort the repositories based on the prefix indexes. This boosts
// a repository if it indicates that it has a matching prefix of the
// dependency's groupId. This does not guarantee that the repository
// has the artifact.
Collections.sort(list, new Comparator<Repository>() {
@Override
public int compare(Repository r1, Repository r2) {
boolean p1 = r1.hasPrefix(dep);
boolean p2 = r2.hasPrefix(dep);
if (p1 && p2) {
// both have prefix
return 0;
} else if (p1) {
// r1 has prefix
return -1;
}
// r2 has prefix
return 1;
}
});
// inject the preferred repository at the top of the list
if (preferredRepository != null) {
list.add(0, preferredRepository);
}
//System.out.println(dep.getCoordinates() + " " + list.toString());
return list;
}
public java.net.Proxy getProxy(String repositoryId, String url) {
if (proxies.size() == 0) {
return java.net.Proxy.NO_PROXY;
}
for (Proxy proxy : proxies) {
if (proxy.active && proxy.matches(repositoryId, url)) {
return new java.net.Proxy(java.net.Proxy.Type.HTTP, proxy.getSocketAddress());
}
}
return java.net.Proxy.NO_PROXY;
}
public String getProxyAuthorization(String repositoryId, String url) {
for (Proxy proxy : proxies) {
if (proxy.active && proxy.matches(repositoryId, url)) {
return "Basic " + Base64.encodeBytes((proxy.username + ":" + proxy.password).getBytes());
}
}
return "";
}
public File getOutputDirectory(Scope scope) {
if (scope == null) {
return projectConfig.outputDirectory;
}
switch (scope) {
case test:
return new File(projectConfig.outputDirectory, "test-classes");
default:
return new File(projectConfig.outputDirectory, "classes");
}
}
public File getTargetFile() {
Pom pom = projectConfig.pom;
String name = pom.groupId + "/" + pom.artifactId + "/" + pom.version + (pom.classifier == null ? "" : ("-" + pom.classifier));
return new File(projectConfig.targetDirectory, name + ".jar");
}
public File getReportsTargetDirectory() {
return new File(projectConfig.targetDirectory, "reports");
}
public File getJavadocTargetDirectory() {
return new File(projectConfig.targetDirectory, "javadoc");
}
public File getTargetDirectory() {
return projectConfig.targetDirectory;
}
public File getProjectDirectory() {
return projectDirectory;
}
public File getSiteSourceDirectory() {
for (SourceDirectory sourceFolder : projectConfig.sourceDirectories) {
if (Scope.site.equals(sourceFolder.scope)) {
return sourceFolder.getSources();
}
}
// default site sources directory
return new File(projectDirectory, "src/site");
}
public File getSiteTargetDirectory() {
for (SourceDirectory sourceFolder : projectConfig.sourceDirectories) {
if (Scope.site.equals(sourceFolder.scope)) {
return sourceFolder.getOutputDirectory();
}
}
// default site target directory
return new File(projectConfig.targetDirectory, "site");
}
@Override
public String toString() {
return "Build (" + projectConfig.pom.toString() + ")";
}
}