Skip to content

Commit

Permalink
feat: 模块瘦身检查 && 允许不自动排除和基座相同的依赖 (#1017)
Browse files Browse the repository at this point in the history
* 优化显示

* fix as bizStateRecords

* 更新显示

* feat: add 'build failed when exclude different base dependency'; allow not to exclude same dependency by base-starter automatically

* build failed when exclude dependencies not in base

* rm all gradle

* fix merge

* fix ut

---------

Co-authored-by: leo james <[email protected]>
  • Loading branch information
gaosaroma and lvjing2 authored Nov 1, 2024
1 parent 53fa805 commit a99756a
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import com.alipay.sofa.ark.common.util.StringUtils;
import com.alipay.sofa.ark.tools.ArtifactItem;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.project.MavenProject;

import java.util.Arrays;
Expand All @@ -26,6 +28,7 @@
import java.util.Optional;
import java.util.Set;

import static com.alipay.sofa.ark.spi.constant.Constants.STRING_COLON;
import static java.util.Arrays.asList;

public class MavenUtils {
Expand Down Expand Up @@ -113,4 +116,54 @@ private static ArtifactItem getArtifactItem(String lineContent) {
public static boolean inUnLogScopes(String scope) {
return UN_LOG_SCOPES.contains(scope);
}

public static String getGAVIdentity(Artifact artifact) {
return artifact.getGroupId() + STRING_COLON + artifact.getArtifactId() + STRING_COLON
+ artifact.getBaseVersion();
}

public static String getArtifactIdentity(Artifact artifact) {
if (artifact.hasClassifier()) {
return artifact.getGroupId() + STRING_COLON + artifact.getArtifactId() + STRING_COLON
+ artifact.getBaseVersion() + STRING_COLON + artifact.getClassifier()
+ STRING_COLON + artifact.getType();
} else {
return artifact.getGroupId() + STRING_COLON + artifact.getArtifactId() + STRING_COLON
+ artifact.getBaseVersion() + STRING_COLON + artifact.getType();
}
}

public static String getArtifactIdentityWithoutVersion(Artifact artifact) {
if (artifact.hasClassifier()) {
return artifact.getGroupId() + STRING_COLON + artifact.getArtifactId() + STRING_COLON
+ artifact.getClassifier() + STRING_COLON + artifact.getType();
} else {
return artifact.getGroupId() + STRING_COLON + artifact.getArtifactId() + STRING_COLON
+ artifact.getType();
}

}

public static String getDependencyIdentity(Dependency dependency) {
if (org.apache.commons.lang3.StringUtils.isNotEmpty(dependency.getClassifier())) {
return dependency.getGroupId() + STRING_COLON + dependency.getArtifactId()
+ STRING_COLON + dependency.getVersion() + STRING_COLON
+ dependency.getClassifier() + STRING_COLON + dependency.getType();
} else {
return dependency.getGroupId() + STRING_COLON + dependency.getArtifactId()
+ STRING_COLON + dependency.getVersion() + STRING_COLON + dependency.getType();
}
}

public static String getDependencyIdentityWithoutVersion(Dependency dependency) {
if (org.apache.commons.lang3.StringUtils.isNotEmpty(dependency.getClassifier())) {
return dependency.getGroupId() + STRING_COLON + dependency.getArtifactId()
+ STRING_COLON + dependency.getClassifier() + STRING_COLON
+ dependency.getType();
} else {
return dependency.getGroupId() + STRING_COLON + dependency.getArtifactId()
+ STRING_COLON + dependency.getType();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,44 +33,54 @@ public class ModuleSlimConfig {
* group-a:tracer-core:3.0.10
* group-b:tracer-core:3.0.10:jdk17
*/
private LinkedHashSet<String> excludes = new LinkedHashSet<>();
private LinkedHashSet<String> excludes = new LinkedHashSet<>();

/**
* list of groupId names to exclude (exact match).
*/
private LinkedHashSet<String> excludeGroupIds = new LinkedHashSet<>();
private LinkedHashSet<String> excludeGroupIds = new LinkedHashSet<>();

/**
* list of artifact names to exclude (exact match).
*/
private LinkedHashSet<String> excludeArtifactIds = new LinkedHashSet<>();
private LinkedHashSet<String> excludeArtifactIds = new LinkedHashSet<>();

/**
* Colon separated groupId, artifactId [and classifier] to exclude (exact match). e.g:
* group-a:tracer-core:3.0.10
* group-b:tracer-core:3.0.10:jdk17
*/
private LinkedHashSet<String> includes = new LinkedHashSet<>();
private LinkedHashSet<String> includes = new LinkedHashSet<>();

/**
* list of groupId names to exclude (exact match).
*/
private LinkedHashSet<String> includeGroupIds = new LinkedHashSet<>();
private LinkedHashSet<String> includeGroupIds = new LinkedHashSet<>();

/**
* list of artifact names to exclude (exact match).
*/
private LinkedHashSet<String> includeArtifactIds = new LinkedHashSet<>();
private LinkedHashSet<String> includeArtifactIds = new LinkedHashSet<>();

/**
* 基座依赖标识,以 ${groupId}:${artifactId}:${version} 标识
*/
private String baseDependencyParentIdentity;

/**
* 是否排除依赖时,同时排除依赖及间接依赖。如:A依赖B,B依赖C,当 excludes 只配置了 A 时,B 和 C 都会被排除
* 在排除依赖时,是否同时排除依赖及间接依赖。如:A依赖B,B依赖C,当 excludes 只配置了 A 时,B 和 C 都会被排除
*/
private boolean excludeWithIndirectDependencies = true;
private boolean excludeWithIndirectDependencies = true;

/**
* 在排除依赖时,是否根据基座依赖标识(baseDependencyParentIdentity)排除与基座相同的依赖(GAV 均相同)
*/
private boolean excludeSameBaseDependency = true;

/**
* 在排除依赖时,如果排除的依赖与基座不一致,是否构建失败
*/
private boolean buildFailWhenExcludeBaseDependencyWithDiffVersion = false;

public LinkedHashSet<String> getExcludeArtifactIds() {
return excludeArtifactIds;
Expand Down Expand Up @@ -157,4 +167,20 @@ public boolean isExcludeWithIndirectDependencies() {
public void setExcludeWithIndirectDependencies(boolean excludeWithIndirectDependencies) {
this.excludeWithIndirectDependencies = excludeWithIndirectDependencies;
}

public boolean isExcludeSameBaseDependency() {
return excludeSameBaseDependency;
}

public void setExcludeSameBaseDependency(boolean excludeSameBaseDependency) {
this.excludeSameBaseDependency = excludeSameBaseDependency;
}

public boolean isBuildFailWhenExcludeBaseDependencyWithDiffVersion() {
return buildFailWhenExcludeBaseDependencyWithDiffVersion;
}

public void setBuildFailWhenExcludeBaseDependencyWithDiffVersion(boolean buildFailWhenExcludeBaseDependencyWithDiffVersion) {
this.buildFailWhenExcludeBaseDependencyWithDiffVersion = buildFailWhenExcludeBaseDependencyWithDiffVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
import java.util.Set;
import java.util.stream.Collectors;

import static com.alipay.sofa.ark.boot.mojo.MavenUtils.getArtifactIdentity;
import static com.alipay.sofa.ark.boot.mojo.MavenUtils.getArtifactIdentityWithoutVersion;
import static com.alipay.sofa.ark.boot.mojo.MavenUtils.getDependencyIdentity;
import static com.alipay.sofa.ark.boot.mojo.MavenUtils.getGAVIdentity;
import static com.alipay.sofa.ark.boot.mojo.MavenUtils.inUnLogScopes;
import static com.alipay.sofa.ark.boot.mojo.utils.ParseUtils.getBooleanWithDefault;
import static com.alipay.sofa.ark.boot.mojo.utils.ParseUtils.getStringSet;
Expand Down Expand Up @@ -77,9 +81,13 @@ public class ModuleSlimStrategy {

private File baseDir;

private static final String EXTENSION_EXCLUDE_WITH_INDIRECT_DEPENDENCIES = "excludeWithIndirectDependencies";
private static final String EXTENSION_EXCLUDE_WITH_INDIRECT_DEPENDENCIES = "excludeWithIndirectDependencies";

private static final String DEFAULT_EXCLUDE_RULES = "rules.txt";
private static final String EXTENSION_EXCLUDE_SAME_BASE_DEPENDENCY = "excludeSameBaseDependency";

private static final String EXTENSION_BUILD_FAIL_WHEN_EXCLUDE_DIFF_BASE_DEPENDENCY = "buildFailWhenExcludeDiffBaseDependency";

private static final String DEFAULT_EXCLUDE_RULES = "rules.txt";

ModuleSlimStrategy(MavenProject project, DependencyNode projDependencyGraph,
ModuleSlimConfig config, File baseDir, Log log) {
Expand All @@ -92,43 +100,121 @@ public class ModuleSlimStrategy {

public Set<Artifact> getSlimmedArtifacts() throws MojoExecutionException, IOException {
initSlimStrategyConfig();
Set<Artifact> toFilterByBase = getArtifactsToFilterByParentIdentity(project.getArtifacts());

Set<Artifact> toFilterByBase = getArtifactsToFilterByParentIdentity(project.getArtifacts());
Set<Artifact> toFilterByExclude = getArtifactsToFilterByExcludeConfig(project
.getArtifacts());
Set<Artifact> toAddByInclude = getArtifactsToAddByIncludeConfig(project.getArtifacts());

checkExcludeByParentIdentity(toFilterByExclude, toAddByInclude);

Set<Artifact> filteredArtifacts = new HashSet<>(project.getArtifacts());
filteredArtifacts.removeAll(toFilterByBase);
filteredArtifacts.removeAll(toFilterByExclude);
filteredArtifacts.addAll(toAddByInclude);
return filteredArtifacts;
}

protected void checkExcludeByParentIdentity(Set<Artifact> toFilterByExclude, Set<Artifact> toAddByInclude) throws MojoExecutionException {
if (StringUtils.isEmpty(config.getBaseDependencyParentIdentity())) {
return;
}

Set<Artifact> toFilter = new HashSet<>(toFilterByExclude);
toFilter.removeAll(toAddByInclude);

Set<Artifact> excludedButNoDependencyInBase = getExcludedButNoDependencyInBase(toFilter);
Set<Artifact> excludedButDifferentVersionDependencyInBase = getExcludedButDifferentVersionDependencyInBase(toFilter);

if(excludedButNoDependencyInBase.isEmpty() && excludedButDifferentVersionDependencyInBase.isEmpty()){
getLog().info(String.format("check excludeWithBaseDependencyParentIdentity success with base: %s",config.getBaseDependencyParentIdentity()));
return;
}

// Dependency not found in base; please add it to the base or do not exclude it in the module
excludedButNoDependencyInBase.forEach(artifact -> {
getLog().error(
String.format(
"error to exclude package jar: %s because no such jar in base, please keep the jar or add it to base",
getArtifactIdentity(artifact)));
});

if(!excludedButNoDependencyInBase.isEmpty()){
throw new MojoExecutionException(String.format("check excludeWithBaseDependencyParentIdentity failed with base: %s",config.getBaseDependencyParentIdentity()));
}

// The base contains this dependency, but the version and module are inconsistent; Please use the same dependency version as the base in the module.
List<Dependency> baseDependencies = getAllBaseDependencies();
Map<String,Dependency> baseDependencyIdentityWithoutVersion = baseDependencies.stream().collect(Collectors.toMap(MavenUtils::getDependencyIdentityWithoutVersion, it -> it));
excludedButDifferentVersionDependencyInBase.forEach(artifact -> {
Dependency baseDependency = baseDependencyIdentityWithoutVersion.get(getArtifactIdentityWithoutVersion(artifact));
getLog().error(
String.format(
"error to exclude package jar: %s because it has different version with: %s in base, please keep the jar or set same version with base",
getArtifactIdentity(artifact), getDependencyIdentity(baseDependency)));
});

if(config.isBuildFailWhenExcludeBaseDependencyWithDiffVersion()){
throw new MojoExecutionException(String.format("check excludeWithBaseDependencyParentIdentity failed with base: %s",config.getBaseDependencyParentIdentity()));
}
}

protected Set<Artifact> getArtifactsToFilterByParentIdentity(Set<Artifact> artifacts)
throws MojoExecutionException {
if (StringUtils.isEmpty(config.getBaseDependencyParentIdentity())) {
return Collections.emptySet();
}

if (!config.isExcludeSameBaseDependency()) {
return Collections.emptySet();
}

// 过滤出模块和基座版本一致的依赖,即需要瘦身的依赖
return getSameVersionArtifactsWithBase(artifacts);
}

private Set<Artifact> getSameVersionArtifactsWithBase(Set<Artifact> artifacts) throws MojoExecutionException {
List<Dependency> baseDependencies = getAllBaseDependencies();

Set<String> dependencyIdentities = baseDependencies.stream().map(MavenUtils::getDependencyIdentity).collect(Collectors.toSet());

return artifacts.stream().filter(it -> dependencyIdentities.contains(getArtifactIdentity(it))).collect(Collectors.toSet());
}

private Set<Artifact> getExcludedButNoDependencyInBase(Set<Artifact> toFilter) throws MojoExecutionException {
List<Dependency> baseDependencies = getAllBaseDependencies();

Map<String,Dependency> baseDependencyIdentityWithoutVersion = baseDependencies.stream().collect(Collectors.toMap(MavenUtils::getDependencyIdentityWithoutVersion, it -> it));

return toFilter.stream().filter(it -> !baseDependencyIdentityWithoutVersion.containsKey(getArtifactIdentityWithoutVersion(it))).collect(Collectors.toSet());
}

private Set<Artifact> getExcludedButDifferentVersionDependencyInBase(Set<Artifact> toFilter) throws MojoExecutionException {
List<Dependency> baseDependencies = getAllBaseDependencies();
Map<String,Dependency> baseDependencyIdentityWithoutVersion = baseDependencies.stream().collect(Collectors.toMap(MavenUtils::getDependencyIdentityWithoutVersion, it -> it));
return toFilter.stream().filter(artifact ->
{
String identityWithoutVersion = getArtifactIdentityWithoutVersion(artifact);
return baseDependencyIdentityWithoutVersion.containsKey(identityWithoutVersion)
&& (!artifact.getBaseVersion().equals(baseDependencyIdentityWithoutVersion.get(identityWithoutVersion).getVersion()));
}
).collect(Collectors.toSet());
}

private List<Dependency> getAllBaseDependencies() throws MojoExecutionException {
// 获取基座DependencyParent的原始Model
Model baseDependencyPom = getBaseDependencyParentOriginalModel();
if(null == baseDependencyPom){
throw new MojoExecutionException(String.format("can not find base dependency parent: %s",config.getBaseDependencyParentIdentity()));
if (null == baseDependencyPom) {
throw new MojoExecutionException(
String.format("can not find base dependency parent: %s",
config.getBaseDependencyParentIdentity()));
}

if(null == baseDependencyPom.getDependencyManagement()){
return Collections.emptySet();
if (null == baseDependencyPom.getDependencyManagement()) {
return Collections.emptyList();
}

List<Dependency> baseDependencies = baseDependencyPom.getDependencyManagement().getDependencies();
Set<String> dependencyIdentities = baseDependencies.stream().map(this::getDependencyIdentity).collect(Collectors.toSet());
return artifacts.stream().filter(it -> dependencyIdentities.contains(getArtifactIdentity(it))).collect(Collectors.toSet());
return baseDependencyPom.getDependencyManagement().getDependencies();
}

protected Model getBaseDependencyParentOriginalModel() {
Expand Down Expand Up @@ -179,11 +265,22 @@ private String getDependencyIdentity(Dependency dependency) {
protected void initSlimStrategyConfig() throws IOException {
Map<String, Object> arkYaml = ArkConfigHolder.getArkYaml(baseDir.getAbsolutePath());
Properties prop = ArkConfigHolder.getArkProperties(baseDir.getAbsolutePath());

config.setExcludeWithIndirectDependencies(getBooleanWithDefault(prop,
EXTENSION_EXCLUDE_WITH_INDIRECT_DEPENDENCIES, true));
config.setExcludeWithIndirectDependencies(getBooleanWithDefault(arkYaml,
EXTENSION_EXCLUDE_WITH_INDIRECT_DEPENDENCIES, true));

config.setExcludeSameBaseDependency(getBooleanWithDefault(prop,
EXTENSION_EXCLUDE_SAME_BASE_DEPENDENCY, true));
config.setExcludeSameBaseDependency(getBooleanWithDefault(arkYaml,
EXTENSION_EXCLUDE_SAME_BASE_DEPENDENCY, true));

config.setBuildFailWhenExcludeBaseDependencyWithDiffVersion(getBooleanWithDefault(prop,
EXTENSION_BUILD_FAIL_WHEN_EXCLUDE_DIFF_BASE_DEPENDENCY, false));
config.setBuildFailWhenExcludeBaseDependencyWithDiffVersion(getBooleanWithDefault(arkYaml,
EXTENSION_BUILD_FAIL_WHEN_EXCLUDE_DIFF_BASE_DEPENDENCY, false));

initExcludeAndIncludeConfig();
}

Expand Down Expand Up @@ -222,8 +319,8 @@ protected Set<Artifact> getArtifactsToFilterByExcludeConfig(Set<Artifact> artifa
}

private Set<Artifact> excludeWithIndirectDependencies(Set<Artifact> literalArtifactsToExclude, Set<Artifact> artifacts) {
Set<String> excludeArtifactIdentities = literalArtifactsToExclude.stream().map(this::getArtifactIdentity).collect(Collectors.toSet());
Map<String,Artifact> artifactMap = artifacts.stream().collect(Collectors.toMap(this::getArtifactIdentity,it->it));
Set<String> excludeArtifactIdentities = literalArtifactsToExclude.stream().map(MavenUtils::getArtifactIdentity).collect(Collectors.toSet());
Map<String,Artifact> artifactMap = artifacts.stream().collect(Collectors.toMap(MavenUtils::getArtifactIdentity,it->it));
return getExcludeWithIndirectDependencies(projDependencyGraph,excludeArtifactIdentities,artifactMap);
}

Expand Down
Loading

0 comments on commit a99756a

Please sign in to comment.