Skip to content

Commit e2e410b

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 e2e410b

File tree

3 files changed

+198
-182
lines changed

3 files changed

+198
-182
lines changed

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

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

281+
private Optional<Xpp3Dom> getConfiguration(MavenProject mavenProject) {
282+
if (mavenProject == null) {
283+
return Optional.empty();
284+
}
285+
return getConfiguration(mavenProject.getBuildPlugins()).or(() -> getConfiguration(mavenProject.getParent()));
286+
}
287+
114288
private Optional<Xpp3Dom> getConfiguration(List<Plugin> plugins) {
115289
return plugins.stream()
116290
.filter(p -> Objects.equals(p, mojoExecution.getPlugin()))
@@ -126,4 +300,24 @@ private Optional<Xpp3Dom> getConfiguration(List<Plugin> plugins) {
126300
private Xpp3Dom defaultConfiguration() {
127301
return new Xpp3Dom("configuration");
128302
}
303+
304+
private static StringBuilder addHeaderValue(StringBuilder builder, String value, char separator) {
305+
if (builder.length() > 0) {
306+
builder.append(separator);
307+
}
308+
// use quoted string if necessary
309+
OSGiHeader.quote(builder, value);
310+
return builder;
311+
}
312+
313+
private static StringBuilder addHeaderAttribute(StringBuilder builder, String key, String value, char separator) {
314+
if (builder.length() > 0) {
315+
builder.append(separator);
316+
}
317+
builder.append(key)
318+
.append("=");
319+
// use quoted string if necessary
320+
OSGiHeader.quote(builder, value);
321+
return builder;
322+
}
129323
}

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)