This is an automated email from the ASF dual-hosted git repository. ggrzybek pushed a commit to branch KARAF-5376-overrides_v2 in repository https://gitbox.apache.org/repos/asf/karaf.git
commit f245b4ee418c81627e72ac8ddd941250d891121a Author: Grzegorz Grzybek <[email protected]> AuthorDate: Wed Nov 22 15:09:01 2017 +0100 [KARAF-5376] Generate/merge features processor configuration from external and Maven config, improve logging in karaf-maven-plugin:assembly --- .../org/apache/karaf/features/FeaturePattern.java | 12 +++ .../org/apache/karaf/features/LocationPattern.java | 4 + .../model/processing/FeaturesProcessing.java | 58 +++++++------ .../karaf/features/internal/service/Blacklist.java | 12 +++ .../karaf/profile/assembly/ArtifactInstaller.java | 28 ++++++ .../org/apache/karaf/profile/assembly/Builder.java | 99 ++++++++++++++-------- .../org/apache/karaf/tooling/AssemblyMojo.java | 10 +++ 7 files changed, 164 insertions(+), 59 deletions(-) diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java b/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java index 107993b..a77c4df 100644 --- a/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java +++ b/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java @@ -80,6 +80,18 @@ public class FeaturePattern { } } + public String getOriginalFeatureId() { + return originalId; + } + + public String getName() { + return nameString; + } + + public String getVersion() { + return versionString; + } + /** * Returns <code>true</code> if this feature pattern matches given feature/version * @param featureName diff --git a/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java b/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java index 428746f..e5c96eb 100644 --- a/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java +++ b/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java @@ -108,6 +108,10 @@ public class LocationPattern { } } + public String getOriginalUri() { + return originalUri; + } + /** * Converts a String with one special character (<code>*</code>) into working {@link Pattern} * @param value diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java index 8a3c7b6..3f5050b 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java @@ -142,22 +142,49 @@ public class FeaturesProcessing { } /** - * Perform <em>compilation</em> of rules declared in feature processing XML file. + * <p>Perform <em>compilation</em> of rules declared in feature processing XML file.</p> + * <p>Additional blacklist and overrides definitions will be added to this model</p> + * * @param blacklist additional {@link Blacklist} definition with lower priority * @param overrides additional overrides definition with lower priority */ public void postUnmarshall(Blacklist blacklist, Set<String> overrides) { - // compile blacklisted repository URIs - for (String repositoryURI : this.getBlacklistedRepositories()) { + // configure Blacklist tool + List<String> blacklisted = new LinkedList<>(); + + // compile blacklisted repository URIs (from XML and additional blacklist) + blacklist.getRepositoryBlacklist().stream() + .map(LocationPattern::getOriginalUri) + .forEach(uri -> getBlacklistedRepositories().add(uri)); + for (String repositoryURI : getBlacklistedRepositories()) { try { blacklistedRepositoryLocationPatterns.add(new LocationPattern(repositoryURI)); + blacklisted.add(repositoryURI + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_REPOSITORY); } catch (MalformedURLException e) { LOG.warn("Can't parse blacklisted repository location pattern: " + repositoryURI + ". Ignoring."); } } - // verify bundle override definitions - for (Iterator<BundleReplacements.OverrideBundle> iterator = this.bundleReplacements.getOverrideBundles().iterator(); iterator.hasNext(); ) { + // add external blacklisted features to this model + blacklist.getFeatureBlacklist() + .forEach(fb -> getBlacklistedFeatures().add(new BlacklistedFeature(fb.getName(), fb.getVersion()))); + blacklisted.addAll(getBlacklistedFeatures().stream() + .map(bf -> bf.getName() + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_FEATURE + (bf.getVersion() == null ? "" : ";" + FeaturePattern.RANGE + "=\"" + bf.getVersion() + "\"")) + .collect(Collectors.toList())); + + // add external blacklisted bundle URIs to this model + blacklist.getBundleBlacklist().stream() + .map(LocationPattern::getOriginalUri) + .forEach(uri -> getBlacklistedBundles().add(uri)); + blacklisted.addAll(getBlacklistedBundles().stream() + .map(bl -> bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_BUNDLE) + .collect(Collectors.toList())); + + this.blacklist = new Blacklist(blacklisted); + + // verify bundle override definitions (from XML and additional overrides) + bundleReplacements.getOverrideBundles().addAll(parseOverridesClauses(overrides)); + for (Iterator<BundleReplacements.OverrideBundle> iterator = bundleReplacements.getOverrideBundles().iterator(); iterator.hasNext(); ) { BundleReplacements.OverrideBundle overrideBundle = iterator.next(); if (overrideBundle.getOriginalUri() == null) { // we have to derive it from replacement - as with etc/overrides.properties entry @@ -180,27 +207,6 @@ public class FeaturesProcessing { iterator.remove(); } } - - // etc/blacklisted.properties - // blacklisted bundle from XML to instruction for Blacklist class - List<String> blacklisted = new LinkedList<>(); - for (String bl : this.getBlacklistedBundles()) { - blacklisted.add(bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_BUNDLE); - } - // blacklisted features - XML type to String instruction for Blacklist class - blacklisted.addAll(this.getBlacklistedFeatures().stream() - .map(bf -> bf.getName() + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_FEATURE + (bf.getVersion() == null ? "" : ";" + FeaturePattern.RANGE + "=\"" + bf.getVersion() + "\"")) - .collect(Collectors.toList())); - // blacklisted repositories - for (String bl : this.getBlacklistedRepositories()) { - blacklisted.add(bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_REPOSITORY); - } - - this.blacklist = new Blacklist(blacklisted); - this.blacklist.merge(blacklist); - - // etc/overrides.properties (mvn: URIs) - bundleReplacements.getOverrideBundles().addAll(parseOverridesClauses(overrides)); } /** diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java index dcc1a20..9792afa 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java @@ -243,4 +243,16 @@ public class Blacklist { bundleBlacklist.add(locationPattern); } + public List<LocationPattern> getRepositoryBlacklist() { + return repositoryBlacklist; + } + + public List<FeaturePattern> getFeatureBlacklist() { + return featureBlacklist; + } + + public List<LocationPattern> getBundleBlacklist() { + return bundleBlacklist; + } + } diff --git a/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java b/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java index 967a979..f068f5e 100644 --- a/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java +++ b/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java @@ -23,6 +23,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import org.apache.karaf.features.BundleInfo; import org.apache.karaf.features.internal.download.Downloader; import org.apache.karaf.features.internal.service.Blacklist; import org.apache.karaf.util.maven.Parser; @@ -48,6 +49,33 @@ public class ArtifactInstaller { this.blacklist = blacklist; } + public void installArtifact(BundleInfo bundle) throws Exception { + if (bundle.isBlacklisted()) { + LOGGER.info(" skipping blacklisted maven artifact: " + bundle.getLocation()); + return; + } + if (bundle.isOverriden()) { + LOGGER.info(" adding overriden maven artifact: " + bundle.getLocation() + " (original location: " + bundle.getOriginalLocation() + ")"); + } else { + LOGGER.info(" adding maven artifact: " + bundle.getLocation()); + } + String location = bundle.getLocation().trim(); + location = removeTrailingSlash(stripUrl(location)); + if (!location.startsWith("mvn:")) { + LOGGER.warn("Ignoring non maven artifact " + location); + return; + } + final String finalLocation = location; + downloader.download(location, provider -> { + String uri = provider.getUrl(); + Path path = pathFromProviderUrl(systemDirectory, finalLocation); + synchronized (provider) { + Files.createDirectories(path.getParent()); + Files.copy(provider.getFile().toPath(), path, StandardCopyOption.REPLACE_EXISTING); + } + }); + } + public void installArtifact(String location) throws Exception { LOGGER.info(" adding maven artifact: " + location); location = removeTrailingSlash(stripUrl(location)); diff --git a/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java b/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java index 960a067..aedc8eb 100644 --- a/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java +++ b/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java @@ -62,6 +62,7 @@ import java.util.zip.ZipInputStream; import org.apache.felix.resolver.ResolverImpl; import org.apache.felix.utils.manifest.Clause; import org.apache.felix.utils.properties.Properties; +import org.apache.karaf.features.BundleInfo; import org.apache.karaf.features.FeaturePattern; import org.apache.karaf.features.FeaturesService; import org.apache.karaf.features.Library; @@ -286,6 +287,7 @@ public class Builder { boolean ignoreDependencyFlag; int defaultStartLevel = 50; Path homeDirectory; + Path featuresProcessingLocation; boolean offline; String localRepository; String mavenRepositories; @@ -575,6 +577,20 @@ public class Builder { } /** + * <p>Configures custom location for a file with features processing instructions. Normally this file is generated + * by the builder if any of blacklisted options are configured.</p> + * <p>If custom location is provided and it's not <code>etc/org.apache.karaf.features.xml</code>, it is copied</p> + * <p>If custom location is provided and it's <code>etc/org.apache.karaf.features.xml</code>, it's left as is</p> + * <p>Any additional blacklisting/overrides configuration via Maven configuration causes overwrite of original + * content.</p> + * @param featuresProcessing + */ + public Builder setFeaturesProcessing(Path featuresProcessing) { + this.featuresProcessingLocation = featuresProcessing; + return this; + } + + /** * Ignore the dependency attribute (dependency="[true|false]") on bundles, effectively forcing their * installation. */ @@ -860,11 +876,26 @@ public class Builder { // profiles are generated after reading features from repositories // so for now, we can only configure blacklisting features processor - Path existingProcessorDefinition = etcDirectory.resolve("org.apache.karaf.features.xml"); + boolean needFeaturesProcessorFileCopy = false; String existingProcessorDefinitionURI = null; + Path existingProcessorDefinition = etcDirectory.resolve("org.apache.karaf.features.xml"); if (existingProcessorDefinition.toFile().isFile()) { existingProcessorDefinitionURI = existingProcessorDefinition.toFile().toURI().toString(); + LOGGER.info("Found existing features processor configuration: {}", homeDirectory.relativize(existingProcessorDefinition)); + } + if (featuresProcessingLocation != null && featuresProcessingLocation.toFile().isFile() + && !featuresProcessingLocation.equals(existingProcessorDefinition)) { + if (existingProcessorDefinitionURI != null) { + LOGGER.warn("Explicitly configured {} will be used for features processor configuration.", homeDirectory.relativize(featuresProcessingLocation)); + } else { + LOGGER.info("Found features processor configuration: {}", homeDirectory.relativize(featuresProcessingLocation)); + } + existingProcessorDefinitionURI = featuresProcessingLocation.toFile().toURI().toString(); + // when there are no other (configured via Maven for example) processing instructions (e.g., blacklisting) + // we don't have to generate this file and may take original content + needFeaturesProcessorFileCopy = true; } + // now we can configure blacklisting features processor which may have already defined (in XML) // configuration for bundle replacements or feature overrides. // we'll add overrides from profiles later. @@ -1014,30 +1045,18 @@ public class Builder { editor.run(); } -// if (!blacklistedFeatures.isEmpty() || !blacklistedBundles.isEmpty()) { -// List<String> lines = new ArrayList<>(); -// lines.add("#"); -// lines.add("# Generated by the karaf assembly builder"); -// lines.add("#"); -// if (!blacklistedFeatures.isEmpty()) { -// lines.add(""); -// lines.add("# Features"); -// lines.addAll(blacklistedFeatures); -// } -// if (!blacklistedBundles.isEmpty()) { -// lines.add(""); -// lines.add("# Bundles"); -// lines.addAll(blacklistedBundles); -// } -// LOGGER.info("Generating {}", homeDirectory.relativize(blacklist)); -// Files.write(blacklist, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); -// } - - // TODO: download overrides, implement fuller override clauses (original->replacement) if (processor.hasInstructions()) { Path featuresProcessingXml = etcDirectory.resolve("org.apache.karaf.features.xml"); - try (FileOutputStream fos = new FileOutputStream(featuresProcessingXml.toFile())) { - processor.writeInstructions(fos); + if (hasOwnInstructions() || overrides.size() > 0) { + // just generate new etc/org.apache.karaf.features.xml file (with external config + builder config) + try (FileOutputStream fos = new FileOutputStream(featuresProcessingXml.toFile())) { + LOGGER.info("Generating features processor configuration: {}", homeDirectory.relativize(featuresProcessingXml)); + processor.writeInstructions(fos); + } + } else if (needFeaturesProcessorFileCopy) { + // we may simply copy configured features processor XML configuration + LOGGER.info("Copying features processor configuration: {} -> {}", homeDirectory.relativize(featuresProcessingLocation), homeDirectory.relativize(featuresProcessingXml)); + Files.copy(featuresProcessingLocation, featuresProcessingXml, StandardCopyOption.REPLACE_EXISTING); } } @@ -1058,6 +1077,20 @@ public class Builder { } /** + * Similar to {@link FeaturesProcessorImpl#hasInstructions()}, we check if there are any builder configuration + * options for blacklisted repos/features/bundles or overwrites. + * @return + */ + private boolean hasOwnInstructions() { + int count = 0; + count += blacklistedRepositoryURIs.size(); + count += blacklistedFeatureIdentifiers.size(); + count += blacklistedBundleURIs.size(); + + return count > 0; + } + + /** * Checks existing (etc/overrides.properties) and configured (in profiles) overrides definitions * @param profileOverrides * @return @@ -1091,7 +1124,7 @@ public class Builder { try { blacklist.blacklistRepository(new LocationPattern(br)); } catch (MalformedURLException e) { - LOGGER.warn("Blacklisted features XML repository URI is invalid {}, ignoring", br); + LOGGER.warn("Blacklisted features XML repository URI is invalid: {}, ignoring", br); } } for (String bf : blacklistedFeatureIdentifiers) { @@ -1101,7 +1134,7 @@ public class Builder { try { blacklist.blacklistBundle(new LocationPattern(bb)); } catch (MalformedURLException e) { - LOGGER.warn("Blacklisted bundle URI is invalid {}, ignoring", bb); + LOGGER.warn("Blacklisted bundle URI is invalid: {}, ignoring", bb); } } if (existingBlacklist != null) { @@ -1320,7 +1353,7 @@ public class Builder { LOGGER.info(" Feature {} is defined as an installed feature", feature.getId()); for (Bundle bundle : feature.getBundle()) { if (!ignoreDependencyFlag || !bundle.isDependency()) { - installer.installArtifact(bundle.getLocation().trim()); + installer.installArtifact(bundle); } } // Install config files @@ -1330,7 +1363,7 @@ public class Builder { for (Conditional cond : feature.getConditional()) { for (Bundle bundle : cond.getBundle()) { if (!ignoreDependencyFlag || !bundle.isDependency()) { - installer.installArtifact(bundle.getLocation().trim()); + installer.installArtifact(bundle); } } } @@ -1392,16 +1425,16 @@ public class Builder { // the feature is a startup feature, updating startup.properties file LOGGER.info(" Feature " + feature.getId() + " is defined as a boot feature"); // add the feature in the system folder - Set<String> locations = new HashSet<>(); + Set<BundleInfo> bundleInfos = new HashSet<>(); for (Bundle bundle : feature.getBundle()) { if (!ignoreDependencyFlag || !bundle.isDependency()) { - locations.add(bundle.getLocation().trim()); + bundleInfos.add(bundle); } } for (Conditional cond : feature.getConditional()) { for (Bundle bundle : cond.getBundle()) { if (!ignoreDependencyFlag || !bundle.isDependency()) { - locations.add(bundle.getLocation().trim()); + bundleInfos.add(bundle); } } } @@ -1413,10 +1446,10 @@ public class Builder { prereqs.put("wrap:", Collections.singletonList("wrap")); prereqs.put("war:", Collections.singletonList("war")); ArtifactInstaller installer = new ArtifactInstaller(systemDirectory, downloader, blacklist); - for (String location : locations) { - installer.installArtifact(location); + for (BundleInfo bundleInfo : bundleInfos) { + installer.installArtifact(bundleInfo); for (Map.Entry<String, List<String>> entry : prereqs.entrySet()) { - if (location.startsWith(entry.getKey())) { + if (bundleInfo.getLocation().trim().startsWith(entry.getKey())) { for (String prereq : entry.getValue()) { Dependency dep = generatedDep.get(prereq); if (dep == null) { diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java index 08f41cb..2830306 100644 --- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java @@ -88,6 +88,13 @@ public class AssemblyMojo extends MojoSupport { @Parameter(defaultValue = "${project.build.directory}/assembly") protected File workDirectory; + /** + * Optional location for custom features processing XML configuration + * (<code>etc/org.apache.karaf.features.cfg</code>) + */ + @Parameter + protected File featuresProcessing; + /* * There are three builder stages related to maven dependency scopes: * - Stage.Startup : scope=compile @@ -462,6 +469,9 @@ public class AssemblyMojo extends MojoSupport { builder.writeProfiles(writeProfiles); builder.environment(environment); builder.defaultStartLevel(defaultStartLevel); + if (featuresProcessing != null) { + builder.setFeaturesProcessing(featuresProcessing.toPath()); + } // Set up remote repositories from Maven build, to be used by pax-url-aether resolver String remoteRepositories = MavenUtil.remoteRepositoryList(project.getRemoteProjectRepositories()); -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
