Skip to content

Commit

Permalink
[decoration] Backward compatibility
Browse files Browse the repository at this point in the history
The decoration changes to always include literals was not backward
compatible since it added literals for the `-runbundles`.

After some discussion we decided to add `++` for decorations
that always add literals and a single `+` for the 6.2 behavior
of not adding literals.

Since we use decorations requiring adding literals in our own build,
this changes adds support for `++` decoration while `+` decoration
still adds literals.

After this build is complete, we will following with changing our
build to use `++` where necessary and also change the `+` behavior
back to not adding literals.

Signed-off-by: Peter Kriens <Peter.Kriens@aqute.biz>
Signed-off-by: BJ Hargrave <bj@hargrave.dev>
  • Loading branch information
pkriens authored and bjhargrave committed May 24, 2022
1 parent cff2231 commit 451c445
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 30 deletions.
8 changes: 5 additions & 3 deletions biz.aQute.bndlib.tests/test/test/InstructionTest.java
Expand Up @@ -31,7 +31,7 @@ public void testSelect() {
public void buildpath_decoration() throws Exception {
try (Processor p = new Processor()) {
p.setProperty("maven.target.version", "3.3.9");
p.setProperty("-buildpath+", "\"{aQute.libg}\";version=project;packages=\"!aQute.lib.exceptions.*,*\"");
p.setProperty("-buildpath++", "aQute.libg;version=project;packages=\"!aQute.lib.exceptions.*,*\"");
p.setProperty("-buildpath+.maven",
"org.apache.maven:*;version=${maven.target.version};maven-scope=provided");
p.setProperty("-buildpath",
Expand All @@ -50,6 +50,8 @@ public void buildpath_decoration() throws Exception {
assertThat(bundles.get("org.apache.maven:maven-settings")).isEmpty();

Instructions decorator = new Instructions(p.mergeProperties("-buildpath" + "+"));
decorator.decorate(bundles);
decorator = new Instructions(p.mergeProperties("-buildpath" + "++"));
decorator.decorate(bundles, true);
System.out.println(bundles);
assertThat(bundles.keySet()).contains("aQute.libg", "org.apache.maven:maven-artifact",
Expand All @@ -75,13 +77,13 @@ public void buildpath_decoration() throws Exception {
@Test
public void conditionalpackage_decoration() throws Exception {
try (Processor p = new Processor()) {
p.setProperty("-conditionalpackage+", "=!aQute.lib.exceptions.*");
p.setProperty("-conditionalpackage++", "=!aQute.lib.exceptions.*");
p.setProperty("-conditionalpackage", "aQute.lib.*,aQute.libg.*");

Parameters parameters = p.getMergedParameters("-conditionalpackage");
assertThat(parameters.keySet()).containsExactly("aQute.lib.*", "aQute.libg.*");

parameters = p.decorated("-conditionalpackage", true);
parameters = p.decorated("-conditionalpackage");
System.out.println(parameters);
assertThat(parameters.keySet()).containsExactly("!aQute.lib.exceptions.*", "aQute.lib.*", "aQute.libg.*");
}
Expand Down
16 changes: 16 additions & 0 deletions biz.aQute.bndlib.tests/test/test/ProcessorTest.java
Expand Up @@ -513,4 +513,20 @@ public void toExternalTest() {
assertThat(ext).hasSize(1);
assertThat(ext.getTyped("foo")).isEqualTo(value);
}

@Test
public void testMergAndSuffixes() throws IOException {
try (Processor p = new Processor()) {
p.setProperty("foo+", "a,b,c");
p.setProperty("foo+.1", "x,y,z");
p.setProperty("foo++", "d,e,f");

String plus = p.mergeProperties("foo+");
assertThat(plus).isEqualTo("a,b,c,x,y,z");

String plusplus = p.mergeProperties("foo++");
assertThat(plusplus).isEqualTo("d,e,f");
}

}
}
37 changes: 20 additions & 17 deletions biz.aQute.bndlib.tests/test/test/ProjectTest.java
Expand Up @@ -226,26 +226,29 @@ public void testMulti() throws Exception {
public void testDecoration() throws Exception {
Workspace ws = getWorkspace(IO.getFile("testresources/ws"));
Project project = ws.getProject("multipath");
project.setProperty("-runbundles+", "org.apache.*;startlevel=10");
project.setProperty("-runbundles++",
"org.apache.*;startlevel=10, org.apache.felix.org.apache.felix.ipojo.ant;startlevel=1000");
assertNotNull(project);

List<Container> runbundles = new ArrayList<>(project.getRunbundles());
assertEquals(3, runbundles.size());
assertEquals("org.apache.felix.configadmin", runbundles.get(0)
.getBundleSymbolicName());
assertEquals("10", runbundles.get(0)
.getAttributes()
.get("startlevel"));
assertEquals("org.apache.felix.ipojo", runbundles.get(1)
.getBundleSymbolicName());
assertEquals("10", runbundles.get(1)
.getAttributes()
.get("startlevel"));
assertEquals("osgi.core", runbundles.get(2)
.getBundleSymbolicName());
assertThat(runbundles.get(2)
.getAttributes()
.get("startlevel")).isNull();
assertEquals(4, runbundles.size());

Container cm = runbundles.get(0);
Container ipojo = runbundles.get(1);
Container osgi = runbundles.get(2);
Container ant = runbundles.get(3);

assertThat(cm.getBundleSymbolicName()).isEqualTo("org.apache.felix.configadmin");
assertThat(cm.getAttributes()).containsEntry("startlevel", "10");

assertThat(ipojo.getBundleSymbolicName()).isEqualTo("org.apache.felix.ipojo");
assertThat(ipojo.getAttributes()).containsEntry("startlevel", "10");

assertThat(osgi.getBundleSymbolicName()).isEqualTo("osgi.core");
assertThat(osgi.getAttributes()).doesNotContainKey("startlevel");

assertThat(ant.getBundleSymbolicName()).isEqualTo("org.apache.felix.org.apache.felix.ipojo.ant");
assertThat(ant.getAttributes()).containsEntry("startlevel", "1000");

List<Container> runpath = new ArrayList<>(project.getRunpath());
assertEquals(3, runpath.size());
Expand Down
3 changes: 3 additions & 0 deletions biz.aQute.bndlib/src/aQute/bnd/build/Project.java
Expand Up @@ -619,6 +619,9 @@ public List<Container> getBundles(Strategy strategyx, String spec, String source
Parameters bundles = parseHeader(spec);
if (source != null) {
Instructions decorator = new Instructions(mergeProperties(source + "+"));
// TODO change the decorated call to remove the second arg.
decorator.decorate(bundles, true);
decorator = new Instructions(mergeProperties(source + "++"));
decorator.decorate(bundles, true);
}

Expand Down
4 changes: 4 additions & 0 deletions biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java
Expand Up @@ -402,6 +402,7 @@ public boolean hasSources() {
@Override
protected Jar getExtra() throws Exception {
Parameters conditionals = getMergedParameters(CONDITIONAL_PACKAGE);
// TODO change the decorated call to remove the second arg.
conditionals.putAll(decorated(CONDITIONALPACKAGE, true));
if (conditionals.isEmpty())
return null;
Expand Down Expand Up @@ -628,8 +629,10 @@ private void doExpand(Jar dot) throws Exception {
}

Parameters private_package = getParameters(PRIVATE_PACKAGE);
// TODO change the decorated call to remove the second arg.
Parameters privatepackage = decorated(PRIVATEPACKAGE, true);
Parameters testpackage = new Parameters();
// TODO change the decorated call to remove the second arg.
Parameters includepackage = decorated(INCLUDEPACKAGE, true);

if (buildInstrs.undertest()) {
Expand Down Expand Up @@ -902,6 +905,7 @@ private Instruction matches(Instructions instructions, String pack, Set<Instruct
private void doIncludeResources(Jar jar) throws Exception {
Parameters includes = parseHeader(getProperty("Bundle-Includes"));
if (includes.isEmpty()) {
// TODO change the decorated call to remove the second arg.
includes = decorated(Constants.INCLUDERESOURCE, true);
includes.putAll(getMergedParameters(Constants.INCLUDE_RESOURCE));
} else {
Expand Down
6 changes: 5 additions & 1 deletion biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java
Expand Up @@ -2532,7 +2532,9 @@ public String getJavaExecutable(String java) {

/**
* Return a parameters that contains the merged properties of the given key
* and that is decorated by the merged properties of the key + '+'
* and that is decorated by the merged properties of the key + '+',
* optionally including literals, and decorated by the merged properties of
* the key + '++', always including literals.
*
* @param key The key of the property
*/
Expand All @@ -2541,6 +2543,8 @@ public Parameters decorated(String key, boolean literalsIncluded) {
Parameters parameters = getMergedParameters(key);
Instructions decorator = new Instructions(mergeProperties(key + "+"));
decorator.decorate(parameters, literalsIncluded);
decorator = new Instructions(mergeProperties(key + "++"));
decorator.decorate(parameters, true);
return parameters;
}

Expand Down
2 changes: 1 addition & 1 deletion bndtools.core/src/bndtools/editor/completion/BndHover.java
Expand Up @@ -66,7 +66,7 @@ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
sb.append("\nE.g. ");
sb.append(syntax.getExample());
}
Parameters decorated = properties.decorated(key, true);
Parameters decorated = properties.decorated(key);
if (!decorated.isEmpty()) {
sb.append("\n")
.append(key)
Expand Down
18 changes: 12 additions & 6 deletions docs/_chapters/820-instructions.md
Expand Up @@ -94,13 +94,17 @@ This will result in a buildpath of (when debug is not false) of: `com.example.fo

## Decorated Instructions

Instructions can also be _decorated_. A _decorator_ is a header that ends with a `+` sign. A header `-runbundles` is first merged and then decorated by getting all the properties with the keys that match`-runbundles+(.*)`. Notice that for the decorator the root key includes the `+` sign, the suffixes must come after the `+` sign.
Instructions can also be _decorated_. A _decorator_ is a header that ends with `+` or `++`. A header like `-runbundles` is first _merged_ and then _decorated_.

The decorator is a Parameters, it consists of a key and a set of attributes. The decorator key is usually a glob.
In this case, `-runbundles` is the _stem_. First, the total header is assembled by _merging_ the property that has that stem. If there are properties that match stem + `+.*` or `++.*`, then these properties are used to decorate the merged property. Notice that for the decorator the root key includes the `+` sign, the suffixes must come after the `+` sign. For example, for the header `foo`, the decorator would be `foo+` and that would match a key like `foo+.bar`.

After the instruction is merged, the key of each Parameter entry is matched against all globs in the decorator following the order of the decorator. When the first match is found, the attributes of the decorator clause that matches are stored with the attributes of the Parameter entry, overriding any attribute with the same attribute key. A Parameter entry key can only match one decorator glob.
If the name of the decorator clause attribute starts with `!`, then the attribute, using the attribute name after removing the leading `!`, is removed from the Parameter entry.
If the name of the decorator clause attribute starts with `~`, then the decorator clause attribute value will not overwrite an existing value of the Parameter entry attribute, using the attribute name after removing the leading `~`.
The decorator is a Parameters, it consists of a key and a set of attributes. The decorator key is usually a glob expressions.

After the header is merged, the key of each entry is matched against all globs in the decorator following the order of the decorator. When the first match is found, the attributes of the decorator clause that matches are stored with the attributes of the Parameter entry, overriding any attribute with the same attribute key. A Parameter entry key can only match one decorator glob expression.

For example, `-runbundles a` and `-runbundles+ *;startlevel=20` will result in the content `a;startlevel=20`.

If the name of the decorator clause attribute starts with `!`, then the attribute, using the attribute name after removing the leading `!`, is removed from the Parameter entry. If the name of the decorator clause attribute starts with `~`, then the decorator clause attribute value will not overwrite an existing value of the Parameter entry attribute, using the attribute name after removing the leading `~`.

Example:

Expand All @@ -109,10 +113,12 @@ Example:
-foo+.d d;skip=true

In this case, the first entry is `b` and it is matched against the second entry in the `-foo` instruction. Since the decorator has the `skip=true` attribute, it is carried over to the instruction. The result is therefore:
In this case, the first entry matched is `b` and it is matched against the second entry in the `-foo` instruction. Since the decorator has the `skip=true` attribute, it is carried over to the instruction. The result is therefore:

a, b;skip=true; c;skip=false, d;skip=true

If the decoration ends with 2 plus signs, for example `-foo++`, then the literals in the decoration headers will be added to the result if they are not matched to any key in the source header. If the decoration ends with a single `+` sign, literals that do not match are ignored.

* Decoration is not used for all instructions. It should be indicated on the instruction page if it is applied.
* There is a macro [`decorated`](/macros/decorated.html) that can be used to apply decoration to any property key

Expand Down
4 changes: 2 additions & 2 deletions docs/_instructions/runbundles.md
Expand Up @@ -36,8 +36,8 @@ Use the [-runstartlevel][2] instruction to let the resolver calculate the start
resolver will add the `startlevel` attribute.

Use the _decoration_ facility. With the decoration facility you can augment the `-runbundles` instruction by
specifying the `-runbundles+` property. The keys are _glob_ expressions and any attributes or directives
will be set (or overridden) on the merged `-runbundles` instruction.
specifying the `-runbundles+` property (or the `-runbundles++` if you want to add literals). The keys are _glob_ expressions
and any attributes or directives will be set (or overridden) on the merged `-runbundles` instruction.

-runbundles: \
org.apache.felix.configadmin;version='[1.8.8,1.8.9)',\
Expand Down

0 comments on commit 451c445

Please sign in to comment.