Skip to content

Commit c9db60b

Browse files
committed
Extract code to automatically derive data from maven-project
Currently if one loads the configuration with aQute.bnd.maven.lib.configuration.BndConfiguration then only the configuration itself is loaded, but actually some implicit configuration later apply (e.g. from the maven project configuration) that is currently only performed by the AbstractBndMavenPlugin. This extracts this logic from the AbstractBndMavenPlugin into the BndConfiguration class for the following benefits: - making the AbstractBndMavenPlugin maintain less code in the execute method - allow other users of BndConfiguration to easily inherit common defaults - separation of concerns, easier to debug and understand Signed-off-by: Christoph Läubrich <[email protected]>
1 parent 0e76ec6 commit c9db60b

File tree

3 files changed

+200
-182
lines changed

3 files changed

+200
-182
lines changed

biz.aQute.bnd.maven/src/aQute/bnd/maven/lib/configuration/BndConfiguration.java

+196
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,35 @@
77
import java.util.Objects;
88
import java.util.Optional;
99

10+
import org.apache.maven.model.Developer;
11+
import org.apache.maven.model.License;
1012
import org.apache.maven.model.Plugin;
1113
import org.apache.maven.model.PluginExecution;
1214
import org.apache.maven.model.PluginManagement;
1315
import org.apache.maven.plugin.MojoExecution;
1416
import org.apache.maven.project.MavenProject;
17+
import org.codehaus.plexus.util.StringUtils;
1518
import org.codehaus.plexus.util.xml.Xpp3Dom;
1619
import org.slf4j.Logger;
1720
import org.slf4j.LoggerFactory;
1821

1922
import aQute.bnd.build.Project;
23+
import aQute.bnd.header.OSGiHeader;
24+
import aQute.bnd.osgi.Constants;
2025
import aQute.bnd.osgi.Processor;
26+
import aQute.bnd.version.MavenVersion;
27+
import aQute.bnd.version.Version;
2128
import aQute.lib.io.IO;
29+
import aQute.lib.strings.Strings;
2230
import aQute.lib.utf8properties.UTF8Properties;
2331

2432
/**
2533
* A helper to read Bnd configuration for maven plugins consistently over the
2634
* various Mojos.
2735
*/
2836
public class BndConfiguration {
37+
static final String TSTAMP = "${tstamp}";
38+
static final String SNAPSHOT = "SNAPSHOT";
2939
private final static Logger logger = LoggerFactory.getLogger(BndConfiguration.class);
3040

3141
private final MavenProject project;
@@ -47,6 +57,165 @@ public File loadProperties(Processor processor) throws Exception {
4757
return loadProjectProperties(processor, project, project, configuration);
4858
}
4959

60+
public void inheritPropertiesDefaults(Processor processor) throws Exception {
61+
Xpp3Dom configuration = getConfiguration(project)
62+
.orElseGet(this::defaultConfiguration);
63+
String outputTimestamp = Optional.ofNullable(configuration.getChild("outputTimestamp"))
64+
.map(xpp -> xpp.getValue())
65+
.orElse(null);
66+
// https://maven.apache.org/guides/mini/guide-reproducible-builds.html
67+
boolean isReproducible = Strings.nonNullOrEmpty(outputTimestamp)
68+
// no timestamp configured (1 character configuration is useful
69+
// to override a full value during pom inheritance)
70+
&& ((outputTimestamp.length() > 1) || Character.isDigit(outputTimestamp.charAt(0)));
71+
if (isReproducible) {
72+
processor.setProperty(Constants.REPRODUCIBLE, outputTimestamp);
73+
if (processor.getProperty(Constants.NOEXTRAHEADERS) == null) {
74+
processor.setProperty(Constants.NOEXTRAHEADERS, Boolean.TRUE.toString());
75+
}
76+
}
77+
// Set Bundle-SymbolicName
78+
if (processor.getProperty(Constants.BUNDLE_SYMBOLICNAME) == null) {
79+
processor.setProperty(Constants.BUNDLE_SYMBOLICNAME, project.getArtifactId());
80+
}
81+
// Set Bundle-Name
82+
if (processor.getProperty(Constants.BUNDLE_NAME) == null) {
83+
processor.setProperty(Constants.BUNDLE_NAME, project.getName());
84+
}
85+
// Set Bundle-Version
86+
String snapshot = isReproducible ? SNAPSHOT : null;
87+
if (processor.getProperty(Constants.BUNDLE_VERSION) == null) {
88+
Version version = new MavenVersion(project.getVersion()).getOSGiVersion();
89+
processor.setProperty(Constants.BUNDLE_VERSION, version.toString());
90+
if (snapshot == null) {
91+
snapshot = TSTAMP;
92+
}
93+
}
94+
if (snapshot != null) {
95+
if (processor.getProperty(Constants.SNAPSHOT) == null) {
96+
processor.setProperty(Constants.SNAPSHOT, snapshot);
97+
}
98+
}
99+
100+
// Set Bundle-Description
101+
if (processor.getProperty(Constants.BUNDLE_DESCRIPTION) == null) {
102+
// may be null
103+
if (StringUtils.isNotBlank(project.getDescription())) {
104+
processor.setProperty(Constants.BUNDLE_DESCRIPTION, project.getDescription());
105+
}
106+
}
107+
108+
// Set Bundle-Vendor
109+
if (processor.getProperty(Constants.BUNDLE_VENDOR) == null) {
110+
if (project.getOrganization() != null && StringUtils.isNotBlank(project.getOrganization()
111+
.getName())) {
112+
processor.setProperty(Constants.BUNDLE_VENDOR, project.getOrganization()
113+
.getName());
114+
}
115+
}
116+
117+
// Set Bundle-License
118+
if (processor.getProperty(Constants.BUNDLE_LICENSE) == null) {
119+
StringBuilder licenses = new StringBuilder();
120+
for (License license : project.getLicenses()) {
121+
addHeaderValue(licenses, license.getName(), ',');
122+
// link is optional
123+
if (StringUtils.isNotBlank(license.getUrl())) {
124+
addHeaderAttribute(licenses, "link", license.getUrl(), ';');
125+
}
126+
// comment is optional
127+
if (StringUtils.isNotBlank(license.getComments())) {
128+
addHeaderAttribute(licenses, "description", license.getComments(), ';');
129+
}
130+
}
131+
if (licenses.length() > 0) {
132+
processor.setProperty(Constants.BUNDLE_LICENSE, licenses.toString());
133+
}
134+
}
135+
136+
// Set Bundle-SCM
137+
if (processor.getProperty(Constants.BUNDLE_SCM) == null) {
138+
StringBuilder scm = new StringBuilder();
139+
if (project.getScm() != null) {
140+
if (StringUtils.isNotBlank(project.getScm()
141+
.getUrl())) {
142+
addHeaderAttribute(scm, "url", project.getScm()
143+
.getUrl(), ',');
144+
}
145+
if (StringUtils.isNotBlank(project.getScm()
146+
.getConnection())) {
147+
addHeaderAttribute(scm, "connection", project.getScm()
148+
.getConnection(), ',');
149+
}
150+
if (StringUtils.isNotBlank(project.getScm()
151+
.getDeveloperConnection())) {
152+
addHeaderAttribute(scm, "developer-connection", project.getScm()
153+
.getDeveloperConnection(), ',');
154+
}
155+
if (StringUtils.isNotBlank(project.getScm()
156+
.getTag())) {
157+
addHeaderAttribute(scm, "tag", project.getScm()
158+
.getTag(), ',');
159+
}
160+
if (scm.length() > 0) {
161+
processor.setProperty(Constants.BUNDLE_SCM, scm.toString());
162+
}
163+
}
164+
}
165+
166+
// Set Bundle-Developers
167+
if (processor.getProperty(Constants.BUNDLE_DEVELOPERS) == null) {
168+
StringBuilder developers = new StringBuilder();
169+
// this is never null
170+
for (Developer developer : project.getDevelopers()) {
171+
// id is mandatory for OSGi but not enforced in the pom.xml
172+
if (StringUtils.isNotBlank(developer.getId())) {
173+
addHeaderValue(developers, developer.getId(), ',');
174+
// all attributes are optional
175+
if (StringUtils.isNotBlank(developer.getEmail())) {
176+
addHeaderAttribute(developers, "email", developer.getEmail(), ';');
177+
}
178+
if (StringUtils.isNotBlank(developer.getName())) {
179+
addHeaderAttribute(developers, "name", developer.getName(), ';');
180+
}
181+
if (StringUtils.isNotBlank(developer.getOrganization())) {
182+
addHeaderAttribute(developers, "organization", developer.getOrganization(), ';');
183+
}
184+
if (StringUtils.isNotBlank(developer.getOrganizationUrl())) {
185+
addHeaderAttribute(developers, "organizationUrl", developer.getOrganizationUrl(), ';');
186+
}
187+
if (!developer.getRoles()
188+
.isEmpty()) {
189+
addHeaderAttribute(developers, "roles", StringUtils.join(developer.getRoles()
190+
.iterator(), ","), ';');
191+
}
192+
if (StringUtils.isNotBlank(developer.getTimezone())) {
193+
addHeaderAttribute(developers, "timezone", developer.getTimezone(), ';');
194+
}
195+
} else {
196+
logger.warn(
197+
"Cannot consider developer in line '{}' of file '{}' for bundle header '{}' as it does not contain the mandatory id.",
198+
developer.getLocation("")
199+
.getLineNumber(),
200+
developer.getLocation("")
201+
.getSource()
202+
.getLocation(),
203+
Constants.BUNDLE_DEVELOPERS);
204+
}
205+
}
206+
if (developers.length() > 0) {
207+
processor.setProperty(Constants.BUNDLE_DEVELOPERS, developers.toString());
208+
}
209+
}
210+
211+
// Set Bundle-DocURL
212+
if (processor.getProperty(Constants.BUNDLE_DOCURL) == null) {
213+
if (StringUtils.isNotBlank(project.getUrl())) {
214+
processor.setProperty(Constants.BUNDLE_DOCURL, project.getUrl());
215+
}
216+
}
217+
}
218+
50219
private void loadParentProjectProperties(Processor builder, MavenProject currentProject) throws Exception {
51220
MavenProject parentProject = currentProject.getParent();
52221
if (parentProject == null) {
@@ -111,6 +280,13 @@ private File loadProjectProperties(Processor processor, MavenProject bndProject,
111280
return pomFile;
112281
}
113282

283+
private Optional<Xpp3Dom> getConfiguration(MavenProject mavenProject) {
284+
if (mavenProject == null) {
285+
return Optional.empty();
286+
}
287+
return getConfiguration(mavenProject.getBuildPlugins()).or(() -> getConfiguration(mavenProject.getParent()));
288+
}
289+
114290
private Optional<Xpp3Dom> getConfiguration(List<Plugin> plugins) {
115291
return plugins.stream()
116292
.filter(p -> Objects.equals(p, mojoExecution.getPlugin()))
@@ -126,4 +302,24 @@ private Optional<Xpp3Dom> getConfiguration(List<Plugin> plugins) {
126302
private Xpp3Dom defaultConfiguration() {
127303
return new Xpp3Dom("configuration");
128304
}
305+
306+
private static StringBuilder addHeaderValue(StringBuilder builder, String value, char separator) {
307+
if (builder.length() > 0) {
308+
builder.append(separator);
309+
}
310+
// use quoted string if necessary
311+
OSGiHeader.quote(builder, value);
312+
return builder;
313+
}
314+
315+
private static StringBuilder addHeaderAttribute(StringBuilder builder, String key, String value, char separator) {
316+
if (builder.length() > 0) {
317+
builder.append(separator);
318+
}
319+
builder.append(key)
320+
.append("=");
321+
// use quoted string if necessary
322+
OSGiHeader.quote(builder, value);
323+
return builder;
324+
}
129325
}

biz.aQute.bnd.maven/src/aQute/bnd/maven/lib/configuration/package-info.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@Version("1.2.0")
1+
@Version("1.3.0")
22
@Export
33
package aQute.bnd.maven.lib.configuration;
44

0 commit comments

Comments
 (0)