Skip to content

Commit

Permalink
Merge pull request #6 from CodeNoobKing/feat/dynamically-add-patch
Browse files Browse the repository at this point in the history
<feat> add dynamic adapter
  • Loading branch information
lvjing2 authored Mar 14, 2024
2 parents bb91112 + 9bad9fb commit de38a71
Show file tree
Hide file tree
Showing 13 changed files with 799 additions and 0 deletions.
102 changes: 102 additions & 0 deletions koupleless-build-plugin/koupleless-base-build-plugin/pom.xml
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>
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);
}
}
}
Loading

0 comments on commit de38a71

Please sign in to comment.