-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from CodeNoobKing/feat/dynamically-add-patch
<feat> add dynamic adapter
- Loading branch information
Showing
13 changed files
with
799 additions
and
0 deletions.
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
koupleless-build-plugin/koupleless-base-build-plugin/pom.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>com.alipay.sofa.koupleless</groupId> | ||
<artifactId>koupleless-build-plugin</artifactId> | ||
<version>${revision}</version> | ||
<relativePath>../pom.xml</relativePath> | ||
</parent> | ||
|
||
<artifactId>koupleless-base-build-plugin</artifactId> | ||
<version>${revision}</version> | ||
<packaging>maven-plugin</packaging> | ||
|
||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.maven</groupId> | ||
<artifactId>maven-plugin-api</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.maven.plugin-tools</groupId> | ||
<artifactId>maven-plugin-annotations</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.maven</groupId> | ||
<artifactId>maven-aether-provider</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.maven</groupId> | ||
<artifactId>maven-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.maven</groupId> | ||
<artifactId>maven-project</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.dataformat</groupId> | ||
<artifactId>jackson-dataformat-yaml</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.commons</groupId> | ||
<artifactId>commons-collections4</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.mockito</groupId> | ||
<artifactId>mockito-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<resources> | ||
<resource> | ||
<directory>src/main/resources</directory> | ||
<filtering>true</filtering> | ||
</resource> | ||
</resources> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-plugin-plugin</artifactId> | ||
<version>3.5</version> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.3</version> | ||
<configuration> | ||
<source>8</source> | ||
<target>8</target> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
229 changes: 229 additions & 0 deletions
229
.../java/com/alipay/sofa/koupleless/base/build/plugin/KouplelessBaseBuildPrePackageMojo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
/* | ||
* 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 com.alipay.sofa.koupleless.base.build.plugin; | ||
|
||
/* | ||
* Copyright 2001-2005 The Apache Software Foundation. | ||
* | ||
* 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 | ||
* | ||
* 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. | ||
*/ | ||
|
||
import com.alipay.sofa.koupleless.base.build.plugin.common.JarFileUtils; | ||
import com.alipay.sofa.koupleless.base.build.plugin.model.KouplelessAdapterConfig; | ||
import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyAdapterMapping; | ||
import com.alipay.sofa.koupleless.base.build.plugin.model.MavenDependencyMatcher; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; | ||
import com.google.common.base.Preconditions; | ||
import lombok.SneakyThrows; | ||
import org.apache.commons.collections4.CollectionUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.apache.maven.execution.MavenSession; | ||
import org.apache.maven.model.Dependency; | ||
import org.apache.maven.plugin.AbstractMojo; | ||
import org.apache.maven.plugin.MojoExecutionException; | ||
import org.apache.maven.plugins.annotations.Component; | ||
import org.apache.maven.plugins.annotations.LifecyclePhase; | ||
import org.apache.maven.plugins.annotations.Mojo; | ||
import org.apache.maven.plugins.annotations.Parameter; | ||
import org.apache.maven.project.MavenProject; | ||
import org.eclipse.aether.RepositorySystem; | ||
import org.eclipse.aether.artifact.Artifact; | ||
import org.eclipse.aether.artifact.DefaultArtifact; | ||
import org.eclipse.aether.resolution.ArtifactRequest; | ||
import org.eclipse.aether.resolution.ArtifactResult; | ||
|
||
import java.io.*; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.*; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* Goal which touches a timestamp file. | ||
* | ||
* @goal touch | ||
* @phase process-sources | ||
*/ | ||
@Mojo(name = "add-patch", defaultPhase = LifecyclePhase.PROCESS_CLASSES) | ||
public class KouplelessBaseBuildPrePackageMojo extends AbstractMojo { | ||
|
||
@Parameter(defaultValue = "${project.build.directory}", readonly = true) | ||
File outputDirectory; | ||
|
||
@Parameter(defaultValue = "${project}", required = true, readonly = true) | ||
MavenProject project; | ||
|
||
@Parameter(defaultValue = "${session}", required = true, readonly = true) | ||
MavenSession session; | ||
|
||
@Component | ||
RepositorySystem repositorySystem; | ||
|
||
private ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); | ||
|
||
KouplelessAdapterConfig kouplelessAdapterConfig; | ||
|
||
String defaultGroupId = ""; | ||
String defaultVersion = ""; | ||
|
||
void initKouplelessAdapterConfig() throws Exception { | ||
if (kouplelessAdapterConfig == null) { | ||
InputStream mappingConfigIS = this.getClass().getClassLoader() | ||
.getResourceAsStream("adapter-mapping.yaml"); | ||
|
||
kouplelessAdapterConfig = yamlMapper.readValue(mappingConfigIS, | ||
KouplelessAdapterConfig.class); | ||
|
||
for (MavenDependencyAdapterMapping mappings : CollectionUtils | ||
.emptyIfNull(kouplelessAdapterConfig.getAdapterMappings())) { | ||
|
||
} | ||
} | ||
|
||
Properties properties = new Properties(); | ||
properties.load(getClass().getClassLoader().getResourceAsStream("project.properties")); | ||
defaultGroupId = properties.getProperty("project.groupId"); | ||
defaultVersion = properties.getProperty("project.version"); | ||
} | ||
|
||
String getDependencyId(Dependency dependency) { | ||
return dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" | ||
+ dependency.getVersion() + ":" + dependency.getType() | ||
+ (dependency.getClassifier() != null ? ":" + dependency.getClassifier() : ""); | ||
} | ||
|
||
// visible for testing | ||
List<Dependency> getDependenciesToAdd() { | ||
List<Dependency> adapterDependencies = new ArrayList<>(); | ||
if (kouplelessAdapterConfig == null) { | ||
getLog().info("kouplelessAdapterConfig is null, skip adding dependencies."); | ||
return adapterDependencies; | ||
} | ||
|
||
if (kouplelessAdapterConfig.getCommonDependencies() != null) { | ||
adapterDependencies.addAll(kouplelessAdapterConfig.getCommonDependencies()); | ||
} | ||
|
||
Collection<MavenDependencyAdapterMapping> adapterMappings = CollectionUtils | ||
.emptyIfNull(kouplelessAdapterConfig.getAdapterMappings()); | ||
for (MavenDependencyAdapterMapping adapterMapping : adapterMappings) { | ||
MavenDependencyMatcher matcher = adapterMapping.getMatcher(); | ||
|
||
if (matcher != null && matcher.getRegexp() != null) { | ||
String regexp = matcher.getRegexp(); | ||
for (Dependency dependency : project.getDependencies()) { | ||
String dependencyId = getDependencyId(dependency); | ||
if (Pattern.compile(regexp).matcher(dependencyId).matches()) { | ||
adapterDependencies.add(adapterMapping.getAdapter()); | ||
} | ||
} | ||
} | ||
|
||
} | ||
return adapterDependencies; | ||
} | ||
|
||
void addDependenciesDynamically() { | ||
if (kouplelessAdapterConfig == null) { | ||
getLog().info("kouplelessAdapterConfig is null, skip adding dependencies."); | ||
return; | ||
} | ||
|
||
Collection<Dependency> dependencies = getDependenciesToAdd(); | ||
for (Dependency dependency : dependencies) { | ||
try { | ||
if (StringUtils.isBlank(dependency.getVersion())) { | ||
dependency.setVersion(defaultVersion); | ||
} | ||
if (StringUtils.isBlank(dependency.getGroupId())) { | ||
dependency.setGroupId(defaultGroupId); | ||
} | ||
getLog().debug("start downloading dependency: " + dependency.toString()); | ||
Artifact artifact = downloadAdapterDependency(dependency); | ||
getLog().debug("start add dependency to project root: " + dependency.toString()); | ||
addArtifactToProjectRoot(artifact); | ||
getLog().info("success add dependency: " + dependency.toString()); | ||
} catch (Throwable t) { | ||
getLog().error("error add dependency: " + dependency.toString(), t); | ||
} | ||
} | ||
} | ||
|
||
Artifact downloadAdapterDependency(Dependency dependency) { | ||
DefaultArtifact patchArtifact = new DefaultArtifact(dependency.getGroupId() + ":" | ||
+ dependency.getArtifactId() + ":" | ||
+ dependency.getVersion()); | ||
|
||
try { | ||
ArtifactRequest artifactRequest = new ArtifactRequest().setArtifact(patchArtifact) | ||
.setRepositories(project.getRemoteProjectRepositories()); | ||
|
||
ArtifactResult artifactResult = repositorySystem.resolveArtifact( | ||
session.getRepositorySession(), artifactRequest); | ||
|
||
Preconditions.checkState(artifactResult.isResolved(), "artifact not resolved."); | ||
return artifactResult.getArtifact(); | ||
} catch (Throwable t) { | ||
getLog().error(t); | ||
throw new RuntimeException(t); | ||
} | ||
} | ||
|
||
void addArtifactToProjectRoot(Artifact artifact) { | ||
File file = artifact.getFile(); | ||
Map<String, Byte[]> entryToContent = JarFileUtils.getFileContentAsLines(file, | ||
Pattern.compile(".*\\.class$")); | ||
for (Map.Entry<String, Byte[]> entry : entryToContent.entrySet()) { | ||
addPatchToProjectRoot(entry.getKey(), entry.getValue()); | ||
} | ||
} | ||
|
||
@SneakyThrows | ||
void addPatchToProjectRoot(String entryName, Byte[] bytes) { | ||
Path outputfile = Paths.get(outputDirectory.getAbsolutePath(), "classes", entryName); | ||
Path parentDir = outputfile.getParent(); | ||
byte[] primitiveByte = new byte[bytes.length]; | ||
for (int i = 0; i < bytes.length; i++) { | ||
primitiveByte[i] = bytes[i]; | ||
} | ||
Files.createDirectories(parentDir); | ||
Files.write(outputfile, primitiveByte); | ||
} | ||
|
||
@Override | ||
public void execute() throws MojoExecutionException { | ||
try { | ||
initKouplelessAdapterConfig(); | ||
addDependenciesDynamically(); | ||
} catch (Throwable t) { | ||
getLog().error(t); | ||
throw new RuntimeException(t); | ||
} | ||
} | ||
} |
Oops, something went wrong.