Skip to content

Commit 7f9d03b

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 d0279b9 commit 7f9d03b

File tree

3 files changed

+188
-182
lines changed

3 files changed

+188
-182
lines changed

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

+184
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,160 @@ public File loadProperties(Processor processor) throws Exception {
4757
return loadProjectProperties(processor, project, project, configuration);
4858
}
4959

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

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)