Skip to content

Commit a5c618e

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 a5c618e

File tree

3 files changed

+193
-186
lines changed

3 files changed

+193
-186
lines changed

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

+189-4
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,211 @@
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;
3242
private final MojoExecution mojoExecution;
43+
private Xpp3Dom configuration;
3344

3445
public BndConfiguration(MavenProject project, MojoExecution mojoExecution) {
3546
this.project = requireNonNull(project);
3647
this.mojoExecution = requireNonNull(mojoExecution);
48+
configuration = Optional.ofNullable(project.getBuildPlugins())
49+
.flatMap(this::getConfiguration)
50+
.orElseGet(this::defaultConfiguration);
3751
}
3852

3953
public File loadProperties(Processor processor) throws Exception {
4054
// Load parent project properties first
4155
loadParentProjectProperties(processor, project);
4256

43-
// Load current project properties
44-
Xpp3Dom configuration = Optional.ofNullable(project.getBuildPlugins())
45-
.flatMap(this::getConfiguration)
46-
.orElseGet(this::defaultConfiguration);
4757
return loadProjectProperties(processor, project, project, configuration);
4858
}
4959

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

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)