spring BomExtension 源码
springboot BomExtension 代码
文件路径:/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java
/*
* Copyright 2012-2022 the original author or authors.
*
* 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
*
* 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.springframework.boot.build.bom;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import groovy.lang.Closure;
import groovy.lang.GroovyObjectSupport;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.InvalidUserCodeException;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.JavaPlatformPlugin;
import org.gradle.api.publish.maven.tasks.GenerateMavenPom;
import org.gradle.api.tasks.Sync;
import org.gradle.api.tasks.TaskExecutionException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.springframework.boot.build.DeployedPlugin;
import org.springframework.boot.build.bom.Library.DependencyConstraintsDependencyVersions;
import org.springframework.boot.build.bom.Library.DependencyLockDependencyVersions;
import org.springframework.boot.build.bom.Library.DependencyVersions;
import org.springframework.boot.build.bom.Library.Exclusion;
import org.springframework.boot.build.bom.Library.Group;
import org.springframework.boot.build.bom.Library.LibraryVersion;
import org.springframework.boot.build.bom.Library.Module;
import org.springframework.boot.build.bom.Library.ProhibitedVersion;
import org.springframework.boot.build.bom.Library.VersionAlignment;
import org.springframework.boot.build.bom.bomr.version.DependencyVersion;
import org.springframework.boot.build.mavenplugin.MavenExec;
import org.springframework.util.FileCopyUtils;
/**
* DSL extensions for {@link BomPlugin}.
*
* @author Andy Wilkinson
*/
public class BomExtension {
private final Map<String, DependencyVersion> properties = new LinkedHashMap<>();
private final Map<String, String> artifactVersionProperties = new HashMap<>();
private final List<Library> libraries = new ArrayList<>();
private final UpgradeHandler upgradeHandler;
private final DependencyHandler dependencyHandler;
private final Project project;
public BomExtension(DependencyHandler dependencyHandler, Project project) {
this.dependencyHandler = dependencyHandler;
this.upgradeHandler = project.getObjects().newInstance(UpgradeHandler.class);
this.project = project;
}
public List<Library> getLibraries() {
return this.libraries;
}
public void upgrade(Action<UpgradeHandler> action) {
action.execute(this.upgradeHandler);
}
public Upgrade getUpgrade() {
return new Upgrade(this.upgradeHandler.upgradePolicy, new GitHub(this.upgradeHandler.gitHub.organization,
this.upgradeHandler.gitHub.repository, this.upgradeHandler.gitHub.issueLabels));
}
public void library(String name, Action<LibraryHandler> action) {
this.library(name, null, action);
}
public void library(String name, String version, Action<LibraryHandler> action) {
ObjectFactory objects = this.project.getObjects();
LibraryHandler libraryHandler = objects.newInstance(LibraryHandler.class, (version != null) ? version : "",
objects);
action.execute(libraryHandler);
LibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version),
libraryHandler.versionAlignment);
addLibrary(new Library(name, libraryVersion, libraryHandler.groups, libraryHandler.prohibitedVersions,
libraryHandler.dependencyVersions));
}
public void effectiveBomArtifact() {
Configuration effectiveBomConfiguration = this.project.getConfigurations().create("effectiveBom");
this.project.getTasks().matching((task) -> task.getName().equals(DeployedPlugin.GENERATE_POM_TASK_NAME))
.all((task) -> {
Sync syncBom = this.project.getTasks().create("syncBom", Sync.class);
syncBom.dependsOn(task);
File generatedBomDir = new File(this.project.getBuildDir(), "generated/bom");
syncBom.setDestinationDir(generatedBomDir);
syncBom.from(((GenerateMavenPom) task).getDestination(), (pom) -> pom.rename((name) -> "pom.xml"));
try {
String settingsXmlContent = FileCopyUtils
.copyToString(new InputStreamReader(
getClass().getClassLoader().getResourceAsStream("effective-bom-settings.xml"),
StandardCharsets.UTF_8))
.replace("localRepositoryPath",
new File(this.project.getBuildDir(), "local-m2-repository").getAbsolutePath());
syncBom.from(this.project.getResources().getText().fromString(settingsXmlContent),
(settingsXml) -> settingsXml.rename((name) -> "settings.xml"));
}
catch (IOException ex) {
throw new GradleException("Failed to prepare settings.xml", ex);
}
MavenExec generateEffectiveBom = this.project.getTasks().create("generateEffectiveBom",
MavenExec.class);
generateEffectiveBom.setProjectDir(generatedBomDir);
File effectiveBom = new File(this.project.getBuildDir(),
"generated/effective-bom/" + this.project.getName() + "-effective-bom.xml");
generateEffectiveBom.args("--settings", "settings.xml", "help:effective-pom",
"-Doutput=" + effectiveBom);
generateEffectiveBom.dependsOn(syncBom);
generateEffectiveBom.getOutputs().file(effectiveBom);
generateEffectiveBom.doLast(new StripUnrepeatableOutputAction(effectiveBom));
this.project.getArtifacts().add(effectiveBomConfiguration.getName(), effectiveBom,
(artifact) -> artifact.builtBy(generateEffectiveBom));
});
}
private String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {
return groupId + ":" + artifactId + ":" + version;
}
Map<String, DependencyVersion> getProperties() {
return this.properties;
}
String getArtifactVersionProperty(String groupId, String artifactId, String classifier) {
String coordinates = groupId + ":" + artifactId + ":" + classifier;
return this.artifactVersionProperties.get(coordinates);
}
private void putArtifactVersionProperty(String groupId, String artifactId, String versionProperty) {
putArtifactVersionProperty(groupId, artifactId, null, versionProperty);
}
private void putArtifactVersionProperty(String groupId, String artifactId, String classifier,
String versionProperty) {
String coordinates = groupId + ":" + artifactId + ":" + ((classifier != null) ? classifier : "");
String existing = this.artifactVersionProperties.putIfAbsent(coordinates, versionProperty);
if (existing != null) {
throw new InvalidUserDataException("Cannot put version property for '" + coordinates
+ "'. Version property '" + existing + "' has already been stored.");
}
}
private void addLibrary(Library library) {
this.libraries.add(library);
String versionProperty = library.getVersionProperty();
if (versionProperty != null) {
this.properties.put(versionProperty, library.getVersion().getVersion());
}
for (Group group : library.getGroups()) {
for (Module module : group.getModules()) {
putArtifactVersionProperty(group.getId(), module.getName(), module.getClassifier(), versionProperty);
this.dependencyHandler.getConstraints().add(JavaPlatformPlugin.API_CONFIGURATION_NAME,
createDependencyNotation(group.getId(), module.getName(), library.getVersion().getVersion()));
}
for (String bomImport : group.getBoms()) {
putArtifactVersionProperty(group.getId(), bomImport, versionProperty);
String bomDependency = createDependencyNotation(group.getId(), bomImport,
library.getVersion().getVersion());
this.dependencyHandler.add(JavaPlatformPlugin.API_CONFIGURATION_NAME,
this.dependencyHandler.platform(bomDependency));
this.dependencyHandler.add(BomPlugin.API_ENFORCED_CONFIGURATION_NAME,
this.dependencyHandler.enforcedPlatform(bomDependency));
}
}
}
public static class LibraryHandler {
private final List<Group> groups = new ArrayList<>();
private final List<ProhibitedVersion> prohibitedVersions = new ArrayList<>();
private final ObjectFactory objectFactory;
private String version;
private VersionAlignment versionAlignment;
private DependencyVersions dependencyVersions;
@Inject
public LibraryHandler(String version, ObjectFactory objectFactory) {
this.version = version;
this.objectFactory = objectFactory;
}
public void version(String version, Action<VersionHandler> action) {
this.version = version;
VersionHandler versionHandler = new VersionHandler();
action.execute(versionHandler);
this.versionAlignment = new VersionAlignment(versionHandler.libraryName);
}
public void group(String id, Action<GroupHandler> action) {
GroupHandler groupHandler = new GroupHandler(id);
action.execute(groupHandler);
this.groups
.add(new Group(groupHandler.id, groupHandler.modules, groupHandler.plugins, groupHandler.imports));
}
public void prohibit(String range, Action<ProhibitedVersionHandler> action) {
ProhibitedVersionHandler prohibitedVersionHandler = new ProhibitedVersionHandler();
action.execute(prohibitedVersionHandler);
try {
this.prohibitedVersions.add(new ProhibitedVersion(VersionRange.createFromVersionSpec(range),
prohibitedVersionHandler.reason));
}
catch (InvalidVersionSpecificationException ex) {
throw new InvalidUserCodeException("Invalid version range", ex);
}
}
public void dependencyVersions(Action<DependencyVersionsHandler> action) {
DependencyVersionsHandler dependencyVersionsHandler = this.objectFactory
.newInstance(DependencyVersionsHandler.class, this.version);
action.execute(dependencyVersionsHandler);
this.dependencyVersions = dependencyVersionsHandler.dependencyVersions;
}
public static class VersionHandler {
private String libraryName;
public void shouldAlignWithVersionFrom(String libraryName) {
this.libraryName = libraryName;
}
}
public static class ProhibitedVersionHandler {
private String reason;
public void because(String because) {
this.reason = because;
}
}
public class GroupHandler extends GroovyObjectSupport {
private final String id;
private List<Module> modules = new ArrayList<>();
private List<String> imports = new ArrayList<>();
private List<String> plugins = new ArrayList<>();
public GroupHandler(String id) {
this.id = id;
}
public void setModules(List<Object> modules) {
this.modules = modules.stream()
.map((input) -> (input instanceof Module module) ? module : new Module((String) input))
.collect(Collectors.toList());
}
public void setImports(List<String> imports) {
this.imports = imports;
}
public void setPlugins(List<String> plugins) {
this.plugins = plugins;
}
public Object methodMissing(String name, Object args) {
if (args instanceof Object[] && ((Object[]) args).length == 1) {
Object arg = ((Object[]) args)[0];
if (arg instanceof Closure<?> closure) {
ModuleHandler moduleHandler = new ModuleHandler();
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure.setDelegate(moduleHandler);
closure.call(moduleHandler);
return new Module(name, moduleHandler.type, moduleHandler.classifier, moduleHandler.exclusions);
}
}
throw new InvalidUserDataException("Invalid configuration for module '" + name + "'");
}
public class ModuleHandler {
private final List<Exclusion> exclusions = new ArrayList<>();
private String type;
private String classifier;
public void exclude(Map<String, String> exclusion) {
this.exclusions.add(new Exclusion(exclusion.get("group"), exclusion.get("module")));
}
public void setType(String type) {
this.type = type;
}
public void setClassifier(String classifier) {
this.classifier = classifier;
}
}
}
public static class DependencyVersionsHandler {
private final String libraryVersion;
private DependencyVersions dependencyVersions;
@Inject
public DependencyVersionsHandler(String libraryVersion) {
this.libraryVersion = libraryVersion;
}
public void extractFrom(Action<ExtractFromHandler> action) {
action.execute(new ExtractFromHandler());
}
public class ExtractFromHandler {
public void dependencyLock(String location) {
DependencyVersionsHandler.this.dependencyVersions = new DependencyLockDependencyVersions(location,
DependencyVersionsHandler.this.libraryVersion);
}
public void dependencyConstraints(String location) {
DependencyVersionsHandler.this.dependencyVersions = new DependencyConstraintsDependencyVersions(
location, DependencyVersionsHandler.this.libraryVersion);
}
}
}
}
public static class UpgradeHandler {
private UpgradePolicy upgradePolicy;
private final GitHubHandler gitHub = new GitHubHandler();
public void setPolicy(UpgradePolicy upgradePolicy) {
this.upgradePolicy = upgradePolicy;
}
public void gitHub(Action<GitHubHandler> action) {
action.execute(this.gitHub);
}
}
public static final class Upgrade {
private final UpgradePolicy upgradePolicy;
private final GitHub gitHub;
private Upgrade(UpgradePolicy upgradePolicy, GitHub gitHub) {
this.upgradePolicy = upgradePolicy;
this.gitHub = gitHub;
}
public UpgradePolicy getPolicy() {
return this.upgradePolicy;
}
public GitHub getGitHub() {
return this.gitHub;
}
}
public static class GitHubHandler {
private String organization = "spring-projects";
private String repository = "spring-boot";
private List<String> issueLabels;
public void setOrganization(String organization) {
this.organization = organization;
}
public void setRepository(String repository) {
this.repository = repository;
}
public void setIssueLabels(List<String> issueLabels) {
this.issueLabels = issueLabels;
}
}
public static final class GitHub {
private String organization = "spring-projects";
private String repository = "spring-boot";
private final List<String> issueLabels;
private GitHub(String organization, String repository, List<String> issueLabels) {
this.organization = organization;
this.repository = repository;
this.issueLabels = issueLabels;
}
public String getOrganization() {
return this.organization;
}
public String getRepository() {
return this.repository;
}
public List<String> getIssueLabels() {
return this.issueLabels;
}
}
private static final class StripUnrepeatableOutputAction implements Action<Task> {
private final File effectiveBom;
private StripUnrepeatableOutputAction(File xmlFile) {
this.effectiveBom = xmlFile;
}
@Override
public void execute(Task task) {
try {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(this.effectiveBom);
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList comments = (NodeList) xpath.evaluate("//comment()", document, XPathConstants.NODESET);
for (int i = 0; i < comments.getLength(); i++) {
org.w3c.dom.Node comment = comments.item(i);
comment.getParentNode().removeChild(comment);
}
org.w3c.dom.Node build = (org.w3c.dom.Node) xpath.evaluate("/project/build", document,
XPathConstants.NODE);
build.getParentNode().removeChild(build);
org.w3c.dom.Node reporting = (org.w3c.dom.Node) xpath.evaluate("/project/reporting", document,
XPathConstants.NODE);
reporting.getParentNode().removeChild(reporting);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document),
new StreamResult(this.effectiveBom));
}
catch (Exception ex) {
throw new TaskExecutionException(task, ex);
}
}
}
}
相关信息
相关文章
0
赞
- 所属分类: 后端技术
- 本文标签: Spring Boot Java Spring
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦