blob: bb3e68332e8580229321880e2c2f4a3de771db5a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.easyant.tasks;
import java.io.File;
import org.apache.easyant.core.EasyAntMagicNames;
import org.apache.ivy.core.LogOptions;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.report.ArtifactDownloadReport;
import org.apache.ivy.core.report.ResolveReport;
import org.apache.ivy.core.resolve.ResolveOptions;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.ImportTask;
import org.apache.tools.ant.types.Path;
/**
* This abstract task is used to include / import modules.
*
* The include mechanism is similar to the current import task, excepts that it automatically prefix all targets of the
* used build module (=ant script). The prefix used by default is the name of the imported project, but it can be
* overriden when calling "include".
*
* Include is useful to use features provided by a build module, while preserving a namespace isolation to avoid names
* collisions.
*
* While possible, overriding a target defined in a included module is not recommended. To do so, the import mechanism
* is preferred.
*
*/
public abstract class AbstractImport extends AbstractEasyAntTask {
private String as;
private String mode;
private boolean mandatory;
private String buildConfigurations;
private String mainConf = "default";
private String providedConf = "provided";
private boolean changing = false;
public AbstractImport() {
super();
}
/**
* Import a module
*
* @param moduleRevisionId
* {@link ModuleRevisionId} of main artifact
* @param report
* a resolved report of the module to import
*/
protected void importModule(ModuleRevisionId moduleRevisionId, ResolveReport report) {
// Check dependency on core
checkCoreCompliance(report, providedConf);
Path path = createModulePath(moduleRevisionId.getModuleId());
File antFile = null;
for (int j = 0; j < report.getConfigurationReport(mainConf).getAllArtifactsReports().length; j++) {
ArtifactDownloadReport artifact = report.getConfigurationReport(mainConf).getAllArtifactsReports()[j];
if ("ant".equals(artifact.getType())) {
antFile = artifact.getLocalFile();
} else if (shouldBeAddedToClasspath(artifact)) {
path.createPathElement().setLocation(artifact.getLocalFile());
} else {
handleOtherResourceFile(moduleRevisionId, artifact.getName(), artifact.getExt(),
artifact.getLocalFile());
}
}
// effective import should be executed AFTER any other resource files has been handled
if (antFile != null && antFile.exists()) {
doEffectiveImport(antFile);
}
}
public boolean shouldBeAddedToClasspath(ArtifactDownloadReport artifact) {
String[] types;
if (getProject().getProperty(EasyAntMagicNames.IMPORT_CLASSPATH_TYPES) != null) {
types = getProject().getProperty(EasyAntMagicNames.IMPORT_CLASSPATH_TYPES).split(",");
} else {
types = new String[] { "jar", "bundle" };
}
for (String type : types) {
if (artifact.getType().equals(type)) {
return true;
}
}
return false;
}
/**
* Do effective import of a given ant file
*
* @param antFile
* a given ant file
*/
protected void doEffectiveImport(File antFile) {
ImportTask importTask = new ImportTask();
importTask.setFile(antFile.getAbsolutePath());
if (as != null) {
importTask.setAs(as);
importTask.setPrefixSeparator("");
}
if (mode != null && "include".equals(mode)) {
importTask.setTaskType(getMode());
}
initTask(importTask).execute();
}
/**
* <p>
* Register all location of other resource file in properties.
* </p>
* <p>
* Properties are composed with the following syntax : [organisation].[module].[artifact].[type].file
* </p>
* <p>
* The '.artifact' is optional when module name and artifact name are the same. [organisation].[module].[type].file
* </p>
*
* @param moduleRevisionId
* a {@link ModuleRevisionId} of the main artifact
* @param artifactName
* artifact name
* @param artifactExtension
* artifact extension name
* @param localResourceFile
*/
protected void handleOtherResourceFile(ModuleRevisionId moduleRevisionId, String artifactName,
String artifactExtension, File localResourceFile) {
if (localResourceFile == null) {
getProject().log(
"Can't find artifact " + artifactName + " ext" + artifactExtension
+ ". See resolution report to have details", Project.MSG_WARN);
} else {
StringBuilder sb = new StringBuilder();
sb.append(moduleRevisionId.getOrganisation());
sb.append("#");
sb.append(moduleRevisionId.getName());
sb.append(".");
if (!moduleRevisionId.getName().equals(artifactName)) {
sb.append(artifactName);
sb.append(".");
}
sb.append(artifactExtension);
sb.append(".file");
getProject().log(
"registering location of artifact " + artifactName + " ext" + artifactExtension + " on "
+ sb.toString(), Project.MSG_DEBUG);
getProject().setNewProperty(sb.toString(), localResourceFile.getAbsolutePath());
}
}
/**
* creates a classpath specific for each module, this classpath will contains all the required dependency .jars. The
* classpath is named [organisation]#[module].classpath
*
* @param moduleId
* @return
*/
protected Path createModulePath(ModuleId moduleId) {
Path path = new Path(getProject());
getProject().addReference(moduleId.toString() + ".classpath", path);
return path;
}
/**
* Configures resolve options
*
* @return configured resolveOptions
*/
protected ResolveOptions configureResolveOptions() {
// Here we do not specify explicit configuration to resolve as
// we want to check multiple configurations.
// If we make specify explicitly configurations to resolve, the
// resolution could through exceptions when configuration does
// not exist in resolved modules.
// resolveOptions.setConfs(new String[] { mainConf,providedConf });
// By default we consider that main conf is default.
// To verify core compliance we can have a dependency on
// easyant-core in a specific configuration.
// By default this configuration is provided.
// An error can be thrown if module contains non-public configurations.
ResolveOptions resolveOptions = new ResolveOptions();
resolveOptions.setLog(getResolveLog());
Boolean offline = Boolean.valueOf(getProject().getProperty(EasyAntMagicNames.EASYANT_OFFLINE));
resolveOptions.setUseCacheOnly(offline);
return resolveOptions;
}
/**
* Check dependency on easyant core with a given configuration. If dependency is found we'll check compliance with
* current core version. It uses {@link CoreRevisionCheckerTask} internally.
*
* @param report
* a {@link ResolveReport}
* @param confToCheck
* configuration to check
*/
protected void checkCoreCompliance(ResolveReport report, String confToCheck) {
if (report.getConfigurationReport(confToCheck) != null) {
log("checking module's provided dependencies ...", Project.MSG_DEBUG);
for (Object o : report.getConfigurationReport(confToCheck).getModuleRevisionIds()) {
ModuleRevisionId currentmrid = (ModuleRevisionId) o;
log("checking " + currentmrid.toString(), Project.MSG_DEBUG);
if (currentmrid.getOrganisation().equals("org.apache.easyant")
&& currentmrid.getName().equals("easyant-core")) {
CoreRevisionCheckerTask checker = new CoreRevisionCheckerTask();
checker.setRequiredRevision(currentmrid.getRevision());
initTask(checker).execute();
}
}
}
}
public void setDynamicAttribute(String attributeName, String value) throws BuildException {
PropertyTask property = new PropertyTask();
property.setName(attributeName);
property.setValue(value);
initTask(property).execute();
}
/**
* Get resolve log settings
*
* @return a string representing the log strategy
*/
protected String getResolveLog() {
String downloadLog = getProject().getProperty(EasyAntMagicNames.MODULE_DOWNLOAD_LOG);
return downloadLog != null ? downloadLog : LogOptions.LOG_DOWNLOAD_ONLY;
}
/**
* Get the alias name
*
* @return a string that represents the alias name
*/
public String getAs() {
return as;
}
/**
* Set the alias name
*
* @param as
* a string that represents the alias name
*/
public void setAs(String as) {
this.as = as;
}
/**
* Get the import mode
*
* @return a string that represents the import mode (e.g. import / include)
*/
public String getMode() {
return mode;
}
/**
* Set the import mode
*
* @param mode
* a string that represents the import mode (e.g. import / include)
*/
public void setMode(String mode) {
this.mode = mode;
}
public String getBuildConfigurations() {
return buildConfigurations;
}
public void setBuildConfigurations(String conf) {
this.buildConfigurations = conf;
}
public void setConf(String conf) {
this.buildConfigurations = conf;
}
/**
* Get the main configuration where plugin are resolved
*
* @return a string representing the main configuration
*/
public String getMainConf() {
return mainConf;
}
/**
* Set the main configuration where plugin are resolved
*
* @param mainConf
* a string representing the main configuration
*/
public void setMainConf(String mainConf) {
this.mainConf = mainConf;
}
/**
* Get the configuration that may contain dependency on easyant-core. This configuration is used to check core
* compliance at resolve time. It should not affect the plugin classpath
*
* @return provided configuration
*/
public String getProvidedConf() {
return providedConf;
}
/**
* Set the configuration that may contain dependency on easyant-core. This configuration is used to check core
* compliance at resolve time. It should not affect the plugin classpath
*
* @return provided configuration
*/
public void setProvidedConf(String providedConf) {
this.providedConf = providedConf;
}
/**
* Can we skip the load of this module?
*
* return true if the module can't be skipped
*/
public boolean isMandatory() {
return mandatory;
}
/**
* Can we skip the load of this module?
*
* @param mandatory
* true if the module can't be skipped
*/
public void setMandatory(boolean mandatory) {
this.mandatory = mandatory;
}
public boolean isChanging() {
return changing;
}
public void setChanging(boolean changing) {
this.changing = changing;
}
}