Skip to content

Commit d76cce2

Browse files
authored
Merge pull request #6362 from laeubi/extract_common_code_to_maven_artifact
Extract code to automatically derive data from maven-project
2 parents 477c875 + f439ce8 commit d76cce2

File tree

3 files changed

+201
-182
lines changed

3 files changed

+201
-182
lines changed

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

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

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

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)