blob: b262e55c7f3ffe786bacdcdaf2370660df015391 [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
*
* https://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.ivy.plugins.resolver.packager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.apache.ivy.core.IvyPatternHelper;
import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.repository.Resource;
import org.apache.ivy.plugins.resolver.util.ResolvedResource;
import org.apache.ivy.util.FileUtil;
import org.apache.ivy.util.Message;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
/**
* Represents one entry in the cache of a {@link PackagerResolver}.
*/
public class PackagerCacheEntry {
private final ModuleRevisionId mr;
private final File dir;
private final File resourceCache;
private final String resourceURL;
private final boolean validate;
private final boolean preserve;
private final boolean restricted;
private final boolean verbose;
private final boolean quiet;
private boolean built;
// CheckStyle:ParameterNumber OFF
public PackagerCacheEntry(ModuleRevisionId mr, File rootDir, File resourceCache,
String resourceURL, boolean validate, boolean preserve, boolean restricted,
boolean verbose, boolean quiet) {
this.mr = mr;
this.dir = getSubdir(rootDir, this.mr);
this.resourceCache = resourceCache;
this.resourceURL = resourceURL;
this.validate = validate;
this.preserve = preserve;
this.restricted = restricted;
this.verbose = verbose;
this.quiet = quiet;
}
// CheckStyle:ParameterNumber ON
/**
* Attempt to build this entry.
*
* @param packagerResource
* packager metadata resource
* @param properties
* a map of properties to pass to the child Ant build responsible for dependency
* packaging
*
* @throws IOException
* if this entry has already been built
*/
public synchronized void build(Resource packagerResource, Map<String, String> properties) throws IOException {
// Sanity check
if (this.built) {
throw new IllegalStateException("build in directory `" + this.dir
+ "' already completed");
}
// Remove work directory if it exists (e.g. left over from last time)
if (this.dir.exists()) {
if (!cleanup()) {
throw new IOException("can't remove directory `" + this.dir + "'");
}
}
// Create work directory
if (!this.dir.mkdirs()) {
throw new IOException("can't create directory `" + this.dir + "'");
}
// Write out packager XML
InputStream packagerXML = packagerResource.openStream();
saveFile("packager.xml", packagerXML);
// Write packager XSLT
saveFile("packager.xsl");
// Write packager XSD
saveFile("packager-1.0.xsd");
// Write master Ant build file
saveFile("build.xml");
// Execute the Ant build file
Project project = new Project();
project.init();
project.setUserProperty("ant.file", new File(dir, "build.xml").getAbsolutePath());
ProjectHelper.configureProject(project, new File(dir, "build.xml"));
project.setBaseDir(dir);
// Configure logging verbosity
BuildLogger logger = new DefaultLogger();
logger.setMessageOutputLevel(this.verbose ? Project.MSG_VERBOSE
: this.quiet ? Project.MSG_WARN : Project.MSG_INFO);
logger.setOutputPrintStream(System.out);
logger.setErrorPrintStream(System.err);
project.addBuildListener(logger);
// Set properties
project.setUserProperty("ivy.packager.organisation", ""
+ this.mr.getModuleId().getOrganisation());
project.setUserProperty("ivy.packager.module", "" + this.mr.getModuleId().getName());
project.setUserProperty("ivy.packager.revision", "" + this.mr.getRevision());
project.setUserProperty("ivy.packager.branch", "" + this.mr.getBranch());
if (this.resourceCache != null) {
project.setUserProperty("ivy.packager.resourceCache",
"" + this.resourceCache.getCanonicalPath());
}
if (this.resourceURL != null) {
project.setUserProperty("ivy.packager.resourceURL", "" + getResourceURL());
}
if (this.validate) {
project.setUserProperty("ivy.packager.validate", "true");
}
project.setUserProperty("ivy.packager.restricted", "" + this.restricted);
project.setUserProperty("ivy.packager.quiet", String.valueOf(quiet));
if (properties != null) {
for (Map.Entry<String, String> entry : properties.entrySet()) {
project.setUserProperty(entry.getKey(), entry.getValue());
}
}
// Execute task
Message.verbose("performing packager resolver build in " + this.dir);
try {
project.executeTarget("build");
this.built = true;
} catch (BuildException e) {
Message.verbose("packager resolver build failed: " + e);
throw e;
}
}
/**
* Has this entry been successfully built?
*
* @return boolean
*/
public synchronized boolean isBuilt() {
return this.built;
}
/**
* Get a built artifact.
*
* @param artifact ditto
* @return ResolvedResource
* @throws IllegalStateException
* if this entry's built has not (yet) completed successfully
*/
public ResolvedResource getBuiltArtifact(Artifact artifact) {
if (!this.built) {
throw new IllegalStateException("build in directory `" + this.dir
+ "' has not yet successfully completed");
}
return new ResolvedResource(new BuiltFileResource(this.dir, artifact),
this.mr.getRevision());
}
public synchronized boolean cleanup() {
this.built = false;
return FileUtil.forceDelete(this.dir);
}
protected void saveFile(String name, InputStream input) throws IOException {
FileUtil.copy(input, new File(this.dir, name), null);
}
protected void saveFile(String name) throws IOException {
InputStream input = getClass().getResourceAsStream(name);
if (input == null) {
throw new IOException("can't find resource `" + name + "'");
}
saveFile(name, input);
}
// @Override
protected void finalize() throws Throwable {
try {
if (!this.preserve) {
cleanup();
}
} finally {
super.finalize();
}
}
private String getResourceURL() {
String baseURL = IvyPatternHelper.substitute(resourceURL, mr.getOrganisation(),
mr.getName(), mr.getRevision(), null, null, null, null,
mr.getQualifiedExtraAttributes(), null);
int slash = baseURL.lastIndexOf('/');
if (slash != -1) {
baseURL = baseURL.substring(0, slash + 1);
}
return baseURL;
}
private static File getSubdir(File rootDir, ModuleRevisionId mr) {
return new File(rootDir, mr.getOrganisation() + File.separatorChar + mr.getName()
+ File.separatorChar + mr.getRevision());
}
}