
aQute.bnd.build.ProjectBuilder Maven / Gradle / Ivy
Show all versions of biz.aQute.bndlib Show documentation
package aQute.bnd.build;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import aQute.bnd.build.Container.TYPE;
import aQute.bnd.build.api.ArtifactInfo;
import aQute.bnd.build.api.BuildInfo;
import aQute.bnd.differ.Baseline;
import aQute.bnd.differ.Baseline.BundleInfo;
import aQute.bnd.differ.Baseline.Info;
import aQute.bnd.differ.DiffPluginImpl;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.BundleId;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.bnd.osgi.EmbeddedResource;
import aQute.bnd.osgi.Instruction;
import aQute.bnd.osgi.Instructions;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Packages;
import aQute.bnd.osgi.Resource;
import aQute.bnd.osgi.Verifier;
import aQute.bnd.service.RepositoryPlugin;
import aQute.bnd.service.diff.Diff;
import aQute.bnd.service.repository.InfoRepository;
import aQute.bnd.service.repository.Phase;
import aQute.bnd.service.repository.SearchableRepository.ResourceDescriptor;
import aQute.bnd.version.Version;
import aQute.lib.collections.SortedList;
import aQute.lib.io.IO;
import aQute.lib.utf8properties.UTF8Properties;
import aQute.libg.glob.PathSet;
import aQute.libg.reporter.ReporterAdapter;
public class ProjectBuilder extends Builder {
private static final Predicate pomPropertiesFilter = new PathSet("META-INF/maven/*/*/pom.properties")
.matches();
private final static Logger logger = LoggerFactory.getLogger(ProjectBuilder.class);
private final DiffPluginImpl differ = new DiffPluginImpl();
Project project;
boolean initialized;
boolean includeTestpath = false;
BuildInfoImpl buildInfo;
static class BuildInfoImpl extends ReporterAdapter implements BuildInfo {
final List artifacts = new ArrayList<>();
final Project project;
BuildInfoImpl(Project project) throws Exception {
this.project = project;
}
@Override
public List getArtifactInfos() {
return new ArrayList<>(artifacts);
}
@Override
public Project getProject() {
return project;
}
@Override
public String toString() {
return "BuildInfo[" + project + ": " + artifacts + "]";
}
}
static class ArtifactInfoImpl extends ReporterAdapter implements ArtifactInfo {
final Manifest manifest;
final Packages exports;
final Packages imports;
final Packages contained;
final BundleId bundleId;
File file;
List errors;
Supplier indexer;
public ArtifactInfoImpl(Builder builder) throws Exception {
String bsn = builder.getBsn();
String version = builder.getVersion();
bundleId = new BundleId(bsn, version);
manifest = builder.getJar()
.getManifest();
exports = builder.getExports()
.dup();
imports = builder.getImports()
.dup();
contained = builder.getContained()
.dup();
getInfo(builder);
}
@Override
public BundleId getBundleId() {
return bundleId;
}
@Override
public Packages getExports() {
return exports;
}
@Override
public Packages getImports() {
return imports;
}
@Override
public Packages getContained() {
return contained;
}
@Override
public String toString() {
return "Artifact[" + bundleId + "]";
}
}
public ProjectBuilder(Project project) {
super(project);
this.project = project;
}
public ProjectBuilder(ProjectBuilder builder) {
super(builder);
this.project = builder.project;
}
@Override
public long lastModified() {
return Math.max(project.lastModified(), super.lastModified());
}
/**
* We put our project and our workspace on the macro path.
*/
@Override
protected Object[] getMacroDomains() {
return new Object[] {
project, project.getWorkspace()
};
}
@Override
public Builder getSubBuilder() throws Exception {
return project.getBuilder(this);
}
public Project getProject() {
return project;
}
@Override
public void init() {
try {
if (!initialized) {
initialized = true;
Parameters dependencies = (getProperty(MAVEN_DEPENDENCIES) == null) ? new Parameters() : null;
doRequireBnd();
for (Container file : project.getClasspath()) {
addClasspath(dependencies, file);
}
File output = project.getOutput();
if (output.exists()) {
Jar jar = new Jar(output);
jar.putResource(PROJECT_MARKER, new EmbeddedResource("project marker", 0L));
addClasspath(jar);
}
if (includeTestpath) {
for (Container file : project.getTestpath()) {
addClasspath(dependencies, file);
}
}
for (Container file : project.getBuildpath()) {
addClasspath(dependencies, file);
}
for (Container file : project.getBootclasspath()) {
addClasspath(file);
}
for (File file : project.getAllsourcepath()) {
addSourcepath(file);
}
if ((dependencies != null) && !dependencies.isEmpty()) {
setProperty(MAVEN_DEPENDENCIES, dependencies.toString());
}
}
} catch (Exception e) {
msgs.Unexpected_Error_("ProjectBuilder init", e);
}
}
private void addClasspath(Parameters dependencies, Container c) throws IOException {
File file = c.getFile();
if ((c.getType() == TYPE.PROJECT) && !file.exists()) {
return;
}
Jar jar = new Jar(file);
super.addClasspath(jar);
project.unreferencedClasspathEntries.put(jar.getName(), c);
Map containerAttributes = c.getAttributes();
if ((dependencies != null)
&& !Boolean.parseBoolean(containerAttributes.getOrDefault("maven-optional", "false"))) {
String depGroupId = containerAttributes.get("maven-groupId");
String depArtifactId = containerAttributes.get("maven-artifactId");
String depVersion = containerAttributes.get("maven-version");
String scope = containerAttributes.getOrDefault("maven-scope", getProperty(MAVEN_SCOPE, "compile"));
if ((depGroupId != null) && (depArtifactId != null) && (depVersion != null)) {
// the repo provided maven attributes to the container
Attrs attrs = new Attrs();
attrs.put("groupId", depGroupId);
attrs.put("artifactId", depArtifactId);
attrs.put("version", depVersion);
attrs.put("scope", scope);
StringBuilder key = new StringBuilder().append(depGroupId)
.append(':')
.append(depArtifactId)
.append(':')
.append(depVersion);
String depClassifier = containerAttributes.get("maven-classifier");
if ((depClassifier != null) && !depClassifier.isEmpty()) {
attrs.put("classifier", depClassifier);
key.append(":jar:")
.append(depClassifier);
}
dependencies.add(key.toString(), attrs);
} else {
// fall back to pom.properties in jar
jar.getResources(pomPropertiesFilter)
.forEachOrdered(r -> {
UTF8Properties pomProperties = new UTF8Properties();
try (InputStream in = r.openInputStream()) {
pomProperties.load(in);
} catch (Exception e) {
logger.debug("unable to read pom.properties resource {}", r, e);
return;
}
String pomGroupId = pomProperties.getProperty("groupId");
String pomArtifactId = pomProperties.getProperty("artifactId");
String pomVersion = pomProperties.getProperty("version");
if ((pomGroupId != null) && (pomArtifactId != null) && (pomVersion != null)) {
Attrs attrs = new Attrs();
attrs.put("groupId", pomGroupId);
attrs.put("artifactId", pomArtifactId);
attrs.put("version", pomVersion);
attrs.put("scope", scope);
String key = new StringBuilder().append(pomGroupId)
.append(':')
.append(pomArtifactId)
.append(':')
.append(pomVersion)
.toString();
dependencies.add(key, attrs);
}
});
}
}
}
public void addClasspath(Container c) throws IOException {
addClasspath(null, c);
}
@Override
public List getClasspath() {
init();
return super.getClasspath();
}
@Override
protected void changedFile(File f) {
project.getWorkspace()
.changedFile(f);
}
/**
* Compare this builder's JAR with a baseline
*
* @throws Exception
*/
@Override
public void doBaseline(Jar dot) throws Exception {
Parameters diffignore = new Parameters(project.getProperty(Constants.DIFFIGNORE), this);
logger.debug("ignore headers & paths {}", diffignore);
differ.setIgnore(diffignore);
Instructions diffpackages = new Instructions(new Parameters(project.getProperty(Constants.DIFFPACKAGES), this));
logger.debug("diffpackages {}", diffpackages);
try (Jar fromRepo = getBaselineJar()) {
if (fromRepo == null) {
logger.debug("No baseline jar {}", getProperty(Constants.BASELINE));
return;
}
Version newer = new Version(getVersion());
Version older = new Version(fromRepo.getVersion());
if (!getBsn().equals(fromRepo.getBsn())) {
error("The symbolic name of this project (%s) is not the same as the baseline: %s", getBsn(),
fromRepo.getBsn());
return;
}
//
// Check if we want to overwrite an equal version that is not
// staging
//
if (newer.getWithoutQualifier()
.equals(older.getWithoutQualifier())) {
RepositoryPlugin rr = getBaselineRepo();
if (rr instanceof InfoRepository infoRepository) {
ResourceDescriptor descriptor = infoRepository.getDescriptor(getBsn(), older);
if (descriptor != null && descriptor.phase != Phase.STAGING) {
error(
"Baselining %s against same version %s but the repository says the older repository version is not the required %s but is instead %s",
getBsn(), getVersion(), Phase.STAGING, descriptor.phase);
return;
}
}
}
logger.debug("baseline {}-{} against: {}", getBsn(), getVersion(), fromRepo.getName());
Baseline baseliner = new Baseline(this, differ);
Set infos = baseliner.baseline(dot, fromRepo, diffpackages);
if (infos.isEmpty())
logger.debug("no deltas");
StringBuffer sb = new StringBuffer();
try (Formatter f = new Formatter(sb, Locale.US)) {
for (Info info : infos) {
if (!info.mismatch) {
continue;
}
sb.setLength(0);
Diff packageDiff = info.packageDiff;
f.format(
"Baseline mismatch for package %s, %s change. Current is %s, repo is %s, suggest %s or %s%n%#S",
packageDiff.getName(), packageDiff.getDelta(), info.newerVersion,
((info.olderVersion != null) && info.olderVersion.equals(Version.LOWEST)) ? '-'
: info.olderVersion,
((info.suggestedVersion != null) && info.suggestedVersion.compareTo(info.newerVersion) <= 0)
? "ok"
: info.suggestedVersion,
(info.suggestedIfProviders == null) ? "-" : info.suggestedIfProviders, packageDiff);
SetLocation l = error("%s", f.toString());
l.header(Constants.BASELINE);
fillInLocationForPackageInfo(l.location(), packageDiff.getName());
if (l.location().file == null) {
// Default to properties file
File propertiesFile = getPropertiesFile();
if (propertiesFile == null) {
propertiesFile = project.getPropertiesFile();
}
l.file(propertiesFile.getAbsolutePath());
}
l.details(info);
}
BundleInfo binfo = baseliner.getBundleInfo();
if (binfo.mismatch) {
sb.setLength(0);
f.format("The bundle version (%s/%s) is too low, must be at least %s%n%#S", binfo.olderVersion,
binfo.newerVersion, binfo.suggestedVersion, baseliner.getDiff());
SetLocation error = error("%s", f.toString());
error.context("Baselining");
error.header(Constants.BUNDLE_VERSION);
error.details(binfo);
FileLine fl = getHeader(Pattern.compile("^" + Constants.BUNDLE_VERSION, Pattern.MULTILINE));
if (fl != null) {
error.file(fl.file.getAbsolutePath());
error.line(fl.line);
error.length(fl.length);
}
}
}
}
}
// *
private static final Pattern PATTERN_EXPORT_PACKAGE = Pattern.compile(Constants.EXPORT_PACKAGE,
Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
private static final Pattern PATTERN_EXPORT_CONTENTS = Pattern.compile(Constants.EXPORT_CONTENTS,
Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
private static final Pattern PATTERN_VERSION_ANNOTATION = Pattern
.compile("@(?:\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)*Version\\s*([^)]+)");
private static final Pattern PATTERN_VERSION_PACKAGEINFO = Pattern.compile("^\\s*version\\s.*$");
public void fillInLocationForPackageInfo(Location location, String packageName) throws Exception {
Parameters eps = getExportPackage();
Attrs attrs = eps.get(packageName);
if (attrs != null && attrs.containsKey(Constants.VERSION_ATTRIBUTE)) {
FileLine fl = getHeader(PATTERN_EXPORT_PACKAGE);
if (fl != null) {
location.file = IO.absolutePath(fl.file);
location.line = fl.line;
location.length = fl.length;
return;
}
}
Parameters ecs = getExportContents();
attrs = ecs.get(packageName);
if (attrs != null && attrs.containsKey(Constants.VERSION_ATTRIBUTE)) {
FileLine fl = getHeader(PATTERN_EXPORT_CONTENTS);
if (fl != null) {
location.file = IO.absolutePath(fl.file);
location.line = fl.line;
location.length = fl.length;
return;
}
}
String path = packageName.replace('.', '/');
for (File src : project.getSourcePath()) {
File packageDir = IO.getFile(src, path);
File pi = IO.getFile(packageDir, "package-info.java");
if (pi.isFile()) {
FileLine fl = findHeader(pi, PATTERN_VERSION_ANNOTATION);
if (fl != null) {
location.file = IO.absolutePath(fl.file);
location.line = fl.line;
location.length = fl.length;
return;
}
}
pi = IO.getFile(packageDir, "packageinfo");
if (pi.isFile()) {
FileLine fl = findHeader(pi, PATTERN_VERSION_PACKAGEINFO);
if (fl != null) {
location.file = IO.absolutePath(fl.file);
location.line = fl.line;
location.length = fl.length;
return;
}
}
}
}
public Jar getLastRevision() throws Exception {
RepositoryPlugin releaseRepo = getReleaseRepo();
SortedSet versions = releaseRepo.versions(getBsn());
if (versions.isEmpty())
return null;
Jar jar = new Jar(releaseRepo.get(getBsn(), versions.last(), null));
addClose(jar);
return jar;
}
/**
* This method attempts to find the baseline jar for the current project. It
* reads the -baseline property and treats it as instructions. These
* instructions are matched against the bsns of the jars (think sub
* builders!). If they match, the sub builder is selected.
*
* The instruction can then specify the following options:
*
*
* version :
* baseline version from repository file : a file path
*
*
* If neither is specified, the current version is used to find the highest
* version (without qualifier) that is below the current version. If a
* version is specified, we take the highest version with the same base
* version.
*
* Since baselining is expensive and easily generates errors you must enable
* it. The easiest solution is to {@code -baseline: *}. This will match all
* sub builders and will calculate the version.
*
* @return a Jar or null
*/
public Jar getBaselineJar() throws Exception {
String bl = getProperty(Constants.BASELINE);
if (bl == null || Constants.NONE.equals(bl))
return null;
Instructions baselines = new Instructions(getProperty(Constants.BASELINE));
if (baselines.isEmpty())
return null; // no baselining
RepositoryPlugin repo = getBaselineRepo();
if (repo == null)
return null; // errors reported already
String bsn = getBsn();
Version version = Version.parseVersion(getVersion());
SortedSet versions = removeStagedAndFilter(repo.versions(bsn), repo, bsn);
if (versions.isEmpty()) {
// We have a repo
// Baselining 0.x is uninteresting
// x.0.0 is a new major version so maybe there is no baseline
if ((version.getMajor() > 0) && ((version.getMinor() > 0) || (version.getMicro() > 0))) {
warning(
"There is no baseline for %s in the baseline repo %s. The build is for version %s, which is higher than %s which suggests that there should be a prior version.",
getBsn(), repo, version.getWithoutQualifier(), new Version(version.getMajor()));
}
return null;
}
//
// Loop over the instructions, first match commits.
//
for (Entry e : baselines.entrySet()) {
if (e.getKey()
.matches(bsn)) {
Attrs attrs = e.getValue();
Version target;
if (attrs.containsKey("version")) {
// Specified version!
String v = attrs.get("version");
if (!Verifier.isVersion(v)) {
error("Not a valid version in %s %s", Constants.BASELINE, v);
return null;
}
Version base = new Version(v);
SortedSet later = versions.tailSet(base);
if (later.isEmpty()) {
error("For baselineing %s-%s, specified version %s not found", bsn, version, base);
return null;
}
// First element is equal or next to the base we desire
target = later.first();
// Now, we could end up with a higher version than our
// current
// project
} else if (attrs.containsKey("file")) {
// Can be useful to specify a file
// for example when copying a bundle with a public api
File f = getProject().getFile(attrs.get("file"));
if (f != null && f.isFile()) {
Jar jar = new Jar(f);
addClose(jar);
return jar;
}
error("Specified file for baseline but could not find it %s", f);
return null;
} else {
target = versions.last();
}
// Fetch the revision
if (target.getWithoutQualifier()
.compareTo(version.getWithoutQualifier()) > 0) {
error("The baseline version %s is higher than the current version %s for %s in %s", target, version,
bsn, repo);
return null;
}
if (target.getWithoutQualifier()
.compareTo(version.getWithoutQualifier()) == 0) {
if (isPedantic()) {
warning("Baselining against jar");
}
}
File file = repo.get(bsn, target, attrs);
if (file == null || !file.isFile()) {
error("Decided on version %s-%s but cannot get file from repo %s", bsn, version, repo);
return null;
}
Jar jar = new Jar(file);
addClose(jar);
return jar;
}
}
// Ignore, nothing matched
return null;
}
/**
* Remove any staging versions that have a variant with a higher qualifier.
*
* @param versions
* @param repo
* @throws Exception
*/
private SortedSet removeStagedAndFilter(SortedSet versions, RepositoryPlugin repo, String bsn)
throws Exception {
List filtered = new ArrayList<>(versions);
Collections.reverse(filtered);
InfoRepository ir = (repo instanceof InfoRepository infoRepository) ? infoRepository : null;
//
// Filter any versions that only differ in qualifier
// The last variable is the last one added. Since we are
// sorted from high to low, we skip any earlier base versions
//
Version last = null;
for (Iterator i = filtered.iterator(); i.hasNext();) {
Version v = i.next();
// Check if same base version as last
Version current = v.getWithoutQualifier();
if (last != null && current.equals(last)) {
i.remove();
continue;
}
//
// Check if this is not a master if the repo
// has a state for each resource
// /
if (ir != null && !isMaster(ir, bsn, v))
i.remove();
last = current;
}
SortedList set = new SortedList<>(filtered);
logger.debug("filtered for only latest staged: {} from {} in range ", set, versions);
return set;
}
/**
* Check if we have a master phase.
*
* @param repo
* @param bsn
* @param v
* @throws Exception
*/
private boolean isMaster(InfoRepository repo, String bsn, Version v) throws Exception {
ResourceDescriptor descriptor = repo.getDescriptor(bsn, v);
//
// If not there, we assume that is master
//
if (descriptor == null)
return true;
return descriptor.phase == Phase.MASTER;
}
private RepositoryPlugin getReleaseRepo() {
String repoNames = getProperty(Constants.RELEASEREPO);
List releaseRepos = project.getReleaseRepos(repoNames);
if (!releaseRepos.isEmpty()) {
if (releaseRepos.size() > 1) {
warning("Found multiple release repositories [%s], so we will use the first one", repoNames);
}
return releaseRepos.get(0);
}
error("No releaserepo(s) found for %s", repoNames);
return null;
}
private RepositoryPlugin getBaselineRepo() {
String repoName = getProperty(Constants.BASELINEREPO);
if (repoName == null) {
warning("Baselining is active, but no %s is set. Will fall back to release repositories",
Constants.BASELINEREPO);
return getReleaseRepo();
}
List repos = getPlugins(RepositoryPlugin.class);
for (RepositoryPlugin r : repos) {
if (r.getName()
.equals(repoName))
return r;
}
error("Could not find -baselinerepo %s", repoName);
return null;
}
/**
* Create a report of the settings
*
* @throws Exception
*/
@Override
public void report(Map table) throws Exception {
super.report(table);
table.put("Baseline repo", getBaselineRepo());
table.put("Release repo", getReleaseRepo());
}
@Override
public String toString() {
return getBsn();
}
/**
* Return the bndrun files that need to be exported
*
* @throws Exception
*/
public List getExportedRuns() throws Exception {
Instructions runspec = new Instructions(getProperty(EXPORT));
List runs = new ArrayList<>();
Set missing = new LinkedHashSet<>();
Map> files = runspec.select(getBase(), Function.identity(), missing);
for (Entry> e : files.entrySet()) {
for (Attrs attrs : e.getValue()) {
Run run = new Run(project.getWorkspace(), getBase(), e.getKey());
attrs.forEach(run::setProperty);
runs.add(run);
}
}
return runs;
}
Map doExports(Map> entries) {
Map result = new LinkedHashMap<>();
for (Entry> e : entries.entrySet()) {
for (Attrs attrs : e.getValue()) {
File file = e.getKey();
try (Run run = Run.createRun(getProject().getWorkspace(), file)) {
//
// History made it that we had an -export instruction and
// somehow
// later export functions were added using the exporters
// that
// were not exactly aligned. I think we also had some
// separate
// function
// in bndtools.
// The code is now reconciled but we need to support the old
// mode of the -export that had some quirks in naming. If no
// options are given for the type of exporter or the name
// then we assume it must be backward compatible. Otherwise
// the -export follows the export function with the
// exporters.
//
boolean backwardCompatible = !attrs.containsKey(Constants.EXPORT_TYPE)
&& !attrs.containsKey(Constants.EXPORT_NAME);
String name = run.getName();
if (backwardCompatible) {
if (run.getProperty(BUNDLE_SYMBOLICNAME) == null)
run.setProperty(BUNDLE_SYMBOLICNAME, getBsn() + ".run");
attrs.put(Constants.EXPORT_NAME, name + Constants.DEFAULT_JAR_EXTENSION);
}
if (attrs.containsKey(Constants.EXPORT_BSN)) {
run.setProperty(BUNDLE_SYMBOLICNAME, attrs.get(Constants.EXPORT_BSN));
}
if (attrs.containsKey(Constants.EXPORT_VERSION)) {
run.setProperty(BUNDLE_VERSION, attrs.get(Constants.EXPORT_VERSION));
}
attrs.forEach(run::setProperty);
Entry export = run.export(null, attrs);
getInfo(run);
if (isOk()) {
File outputFile;
if (backwardCompatible) {
outputFile = project.getOutputFile(name, run.getBundleVersion());
} else {
name = attrs.getOrDefault(Constants.EXPORT_NAME, export.getKey());
outputFile = getFile(project.getTarget(), name);
}
Resource put = result.put(outputFile, export.getValue());
if (put != null) {
error("Duplicate file in -export %s. Input=%s, Attrs=%s, previous resource %s",
outputFile.getName(), file.getName(), attrs, put);
}
}
} catch (Exception ee) {
exception(ee, "Failed to export %s, %s", file, ee.getMessage());
}
}
}
return result;
}
/**
* Add some extra stuff to the builds() method like exporting.
*/
@Override
public Jar[] builds() throws Exception {
project.exportedPackages.clear();
project.importedPackages.clear();
project.containedPackages.clear();
buildInfo = new BuildInfoImpl(project);
return super.builds();
}
/**
* Called when we start to build a builder. We reset our map of bsn ->
* version and set the default contents of the bundle.
*/
@Override
protected void startBuild(Builder builder) throws Exception {
super.startBuild(builder);
project.versionMap.remove(builder.getBsn());
if (!project.isNoBundles() && builder.getJar() == null && project.getOutput()
.isDirectory()) {
if (!builder.isPropertySet(EXPAND_HEADERS)) {
builder.setProperty(Constants.INCLUDEPACKAGE, ALL_FROM_PROJECT);
}
}
}
/**
* Called when we're done with a builder. In this case we retrieve package
* information from builder.
*/
@Override
protected void doneBuild(Builder builder) throws Exception {
project.exportedPackages.putAll(builder.getExports());
project.importedPackages.putAll(builder.getImports());
project.containedPackages.putAll(builder.getContained());
xrefClasspath(project.unreferencedClasspathEntries, builder.getImports());
xrefClasspath(project.unreferencedClasspathEntries, builder.getContained());
//
// For the workspace repo, we maintain a map
// of bsn -> version for this project. So here
// we update this map. In the startBuild method
// we cleared the map
//
Version version = new Version(cleanupVersion(builder.getVersion()));
project.versionMap.put(builder.getBsn(), version);
super.doneBuild(builder);
ArtifactInfoImpl artifactInfo = new ArtifactInfoImpl(builder);
buildInfo.artifacts.add(artifactInfo);
}
private void xrefClasspath(Map unreferencedClasspathEntries, Packages packages) {
for (Attrs attrs : packages.values()) {
String from = attrs.get(Constants.FROM_DIRECTIVE);
if (from != null) {
unreferencedClasspathEntries.remove(from);
}
}
}
/**
* Find the source file for this type
*
* @param type
* @throws Exception
*/
@Override
public String getSourceFileFor(TypeRef type) throws Exception {
return super.getSourceFileFor(type, getSourcePath());
}
@Override
public boolean isInteractive() {
return getProject().isInteractive();
}
public ProjectBuilder includeTestpath() {
this.includeTestpath = true;
return this;
}
public BuildInfoImpl getBuildInfo() {
return buildInfo;
}
}