Skip to content

Commit

Permalink
Extract some generic bndlib code into a common module
Browse files Browse the repository at this point in the history
(cherry picked from commit c478f65)
  • Loading branch information
laeubi committed Feb 12, 2025
1 parent c09e624 commit ede69e7
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 196 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@
<module>tycho-eclipse-plugin</module>
<module>tycho-wrap-plugin</module>
<module>tycho-cleancode-plugin</module>
<module>tycho-bndlib</module>
</modules>
<profiles>
<profile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.eclipse.tycho.bndlib.PathResource;

import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.ManifestResource;
Expand All @@ -54,7 +55,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
String path = StreamSupport.stream(relativePath.spliterator(), false).map(Path::toString)
.collect(Collectors.joining("/"));
log.debug("Adding " + path + " to project jar...");
putResource(path, new MavenProjectResource(file));
putResource(path, new PathResource(file));
} else {
log.debug("Ignore " + relativePath + " because it is filtered");
}
Expand All @@ -81,7 +82,7 @@ public void setManifest(Manifest manifest) {

@Override
public boolean putResource(String path, Resource resource, boolean overwrite) {
if (resource instanceof MavenProjectResource) {
if (resource instanceof PathResource) {
return super.putResource(path, resource, overwrite);
}
Path file = outputFolder.resolve(path);
Expand All @@ -98,6 +99,6 @@ public boolean putResource(String path, Resource resource, boolean overwrite) {
} catch (Exception e) {
throw new RuntimeException(e);
}
return super.putResource(path, new MavenProjectResource(file), overwrite);
return super.putResource(path, new PathResource(file), overwrite);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.bnd.BndRunFile;
import org.eclipse.tycho.bnd.mojos.BndRunMojo;
import org.eclipse.tycho.bndlib.BndRunFile;
import org.eclipse.tycho.core.bnd.BndPluginManager;

import aQute.bnd.build.Project;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProjectHelper;
import org.eclipse.tycho.bnd.BndRunFile;
import org.eclipse.tycho.bndlib.BndRunFile;
import org.osgi.service.resolver.ResolutionException;

import aQute.bnd.build.Container;
Expand Down
8 changes: 8 additions & 0 deletions tycho-bndlib/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17
23 changes: 23 additions & 0 deletions tycho-bndlib/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho</artifactId>
<version>4.0.12-SNAPSHOT</version>
</parent>
<artifactId>tycho-bndlib</artifactId>
<name>Tycho BNDlib Extensions</name>
<description>Provides extensions to BNDlib used by Tycho</description>
<dependencies>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.bnd;
package org.eclipse.tycho.bndlib;

import java.nio.file.Path;

Expand Down
50 changes: 50 additions & 0 deletions tycho-bndlib/src/main/java/org/eclipse/tycho/bndlib/JDTClazz.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2025 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.bndlib;

import java.util.HashSet;
import java.util.Set;

import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.bnd.osgi.Resource;

/**
* An extension to the (bndlib) {@link Clazz} that is capable to return
* discovered information form the java sources.
*/
final class JDTClazz extends Clazz {
private Set<TypeRef> annotations = new HashSet<>();
private TypeRef className;

JDTClazz(Analyzer analyzer, String path, Resource resource, TypeRef className) {
super(analyzer, path, resource);
this.className = className;
}

@Override
public TypeRef getClassName() {
return className;
}

@Override
public Set<TypeRef> annotations() {
return annotations;
}

void addAnnotation(TypeRef typeRef) {
annotations.add(typeRef);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.bnd;
package org.eclipse.tycho.bndlib;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -21,12 +21,12 @@

import aQute.bnd.osgi.Resource;

class MavenProjectResource implements Resource {
public class PathResource implements Resource {

private String extra;
private Path path;

public MavenProjectResource(Path path) {
public PathResource(Path path) {
this.path = path;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*******************************************************************************
* Copyright (c) 2023, 2024 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.bndlib;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;

import aQute.bnd.header.Attrs;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Descriptors.PackageRef;
import aQute.bnd.osgi.FileResource;
import aQute.bnd.service.AnalyzerPlugin;

/**
* Enhances the analyzed classes by information obtained from the source code
*/
public class SourceCodeAnalyzerPlugin implements AnalyzerPlugin {

private static final String PACKAGE_INFO = "package-info";
private static final String ANNOTATION_VERSION = "org.osgi.annotation.versioning.Version";
private static final String ANNOTATION_EXPORT = "org.osgi.annotation.bundle.Export";
private static final String PACKAGE_INFO_JAVA = PACKAGE_INFO + ".java";
private static final String PACKAGE_INFO_CLASS = PACKAGE_INFO + ".class";
private List<Path> sourcePaths;
private Map<PackageRef, Clazz> packageInfoMap = new HashMap<>();
private boolean alreadyRun;

public SourceCodeAnalyzerPlugin() {
this(null);
}

public SourceCodeAnalyzerPlugin(List<Path> sourcePaths) {
this.sourcePaths = sourcePaths;
}

@Override
public boolean analyzeJar(Analyzer analyzer) throws Exception {
if (alreadyRun) {
return false;
}
alreadyRun = true;
ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
Set<String> seenPackages = new HashSet<>();
Set<Path> analyzedPath = new HashSet<>();
for (Path sourcePath : getSourcePath(analyzer)) {
Files.walkFileTree(sourcePath, new FileVisitor<Path>() {

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = file.getFileName().toString().toLowerCase();
if (fileName.endsWith(".java")) {
boolean packageInfo = fileName.equals(PACKAGE_INFO_JAVA);
if (packageInfo || analyzedPath.add(file.getParent())) {
String source = Files.readString(file);
parser.setSource(source.toCharArray());
ASTNode ast = parser.createAST(null);
if (ast instanceof CompilationUnit cu) {
PackageDeclaration packageDecl = cu.getPackage();
if (packageDecl != null) {
String packageFqdn = packageDecl.getName().getFullyQualifiedName();
PackageRef packageRef = analyzer.getPackageRef(packageFqdn);
if (seenPackages.add(packageFqdn)) {
// make the package available to bnd analyzer
analyzer.getContained().put(packageRef);
}
if (packageInfo) {
JDTClazz clazz = new JDTClazz(analyzer,
packageRef.getBinary() + "/" + PACKAGE_INFO_CLASS,
new FileResource(file),
analyzer.getTypeRef(packageRef.getBinary() + "/" + PACKAGE_INFO));
// check for export annotations
boolean export = false;
String version = null;
for (Object raw : packageDecl.annotations()) {
if (raw instanceof Annotation annot) {
String annotationFqdn = annot.getTypeName().getFullyQualifiedName();
if (ANNOTATION_EXPORT.equals(annotationFqdn)) {
export = true;
clazz.addAnnotation(
analyzer.getTypeRef(ANNOTATION_EXPORT.replace('.', '/')));
} else if (ANNOTATION_VERSION.equals(annotationFqdn)) {
if (annot instanceof NormalAnnotation normal) {
for (Object vp : normal.values()) {
MemberValuePair pair = (MemberValuePair) vp;
if ("value"
.equals(pair.getName().getFullyQualifiedName())) {
StringLiteral value = (StringLiteral) pair.getValue();
version = value.getLiteralValue();
}
}
} else if (annot instanceof SingleMemberAnnotation single) {
StringLiteral value = (StringLiteral) single.getValue();
version = value.getLiteralValue();
}
}
}
}
if (export) {
packageInfoMap.put(packageRef, clazz);
if (version == null) {
analyzer.getContained().put(packageRef);
} else {
analyzer.getContained().put(packageRef,
Attrs.create("version", version));
}
}
}
}
}
}
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
return false;
}

private List<Path> getSourcePath(Analyzer analyzer) {
if (sourcePaths != null) {
return sourcePaths;
}
if (analyzer instanceof Builder builder) {
return builder.getSourcePath().stream().map(File::toPath).toList();
}
return List.of();
}

public Clazz getPackageInfo(PackageRef packageRef) {
return packageInfoMap.get(packageRef);
}

}
5 changes: 5 additions & 0 deletions tycho-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-bndlib</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.bndlib.SourceCodeAnalyzerPlugin;
import org.eclipse.tycho.core.TychoProjectManager;
import org.eclipse.tycho.core.maven.MavenDependenciesResolver;
import org.eclipse.tycho.p2maven.InstallableUnitGenerator;
Expand Down
Loading

0 comments on commit ede69e7

Please sign in to comment.