Skip to content

Commit

Permalink
Merge pull request #6406 from chrisrueger/bndeditmodel-effective-ui
Browse files Browse the repository at this point in the history
first draft of Effective tab for BndEditor
  • Loading branch information
pkriens authored Jan 14, 2025
2 parents 898a842 + d5bb738 commit c61e476
Show file tree
Hide file tree
Showing 21 changed files with 918 additions and 54 deletions.
30 changes: 15 additions & 15 deletions aQute.libg/src/aQute/lib/utf8properties/PropertiesParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.Collection;
import java.util.Collections;
import java.util.Properties;

import aQute.lib.hex.Hex;
import aQute.lib.strings.Strings;
Expand Down Expand Up @@ -40,18 +39,20 @@ final class PropertiesParser {
INFO['\\'] = NOKEY;
}

private int n = 0;
private int line = 0;
private int pos = -1;
private int marker = 0;
private char current;
private Properties properties;
private boolean validKey;
private boolean continuation = true;
private int n = 0;
private int line = 0;
private int pos = -1;
private int marker = 0;
private char current;
private UTF8Properties properties;
private boolean validKey;
private boolean continuation = true;
private final Collection<String> syntaxHeaders;
private final String provenance;

PropertiesParser(String source, String file, Reporter reporter, Properties properties,
Collection<String> syntaxHeaders) {
PropertiesParser(String source, String file, Reporter reporter, UTF8Properties properties,
Collection<String> syntaxHeaders, String provenance) {
this.provenance = provenance;
this.source = source.toCharArray();
this.file = file;
this.reporter = reporter;
Expand Down Expand Up @@ -154,19 +155,18 @@ void parse() {
next();
skipWhitespace();
if (current == '\n') {
properties.put(key, "");
properties.setProperty(key, "", provenance);
continue;
}
}

if (current != '\n') {

String value = token(LINE, isSyntaxHeader(key));
properties.put(key, value);

properties.setProperty(key, value, provenance);
} else {
error("No value specified for key: %s. An empty value should be specified as '%<s:' or '%<s='", key);
properties.put(key, "");
properties.setProperty(key, "", provenance);
continue;
}
assert current == '\n';
Expand Down
100 changes: 97 additions & 3 deletions aQute.libg/src/aQute/lib/utf8properties/UTF8Properties.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -46,6 +49,10 @@ public class UTF8Properties extends Properties {
private static final List<ThreadLocal<CharsetDecoder>> decoders = Collections.unmodifiableList(
Arrays.asList(ThreadLocal.withInitial(UTF_8::newDecoder), ThreadLocal.withInitial(ISO_8859_1::newDecoder)));

record Provenance(String source) {}

private final Map<String, Provenance> provenance = new HashMap<>();

public UTF8Properties(Properties p) {
super(p);
}
Expand All @@ -66,7 +73,8 @@ public UTF8Properties(File file, Reporter reporter) throws Exception {
load(file, reporter, (Collection<String>) null);
}

public UTF8Properties() {}
public UTF8Properties() {
}

private static Collection<String> fromArray(String[] array) {
return (array != null) ? Arrays.asList(array) : null;
Expand Down Expand Up @@ -95,8 +103,13 @@ public void load(String source, File file, Reporter reporter, String[] syntaxHea
}

public void load(String source, File file, Reporter reporter, Collection<String> syntaxHeaders) throws IOException {
load(source, file, reporter, syntaxHeaders, file == null ? "" : file.getAbsolutePath());
}

public void load(String source, File file, Reporter reporter, Collection<String> syntaxHeaders, String provenance)
throws IOException {
PropertiesParser parser = new PropertiesParser(source, file == null ? null : file.getAbsolutePath(), reporter,
this, syntaxHeaders);
this, syntaxHeaders, provenance);
parser.parse();
}

Expand Down Expand Up @@ -201,7 +214,7 @@ private UTF8Properties replaceAll(Pattern regex, String replacement) {
String value = (String) entry.getValue();
value = regex.matcher(value)
.replaceAll(replacement);
result.put(key, value);
result.setProperty(key, value, getProvenance(key).orElse(null));
}
return result;
}
Expand All @@ -221,4 +234,85 @@ public UTF8Properties replaceHere(File file) {
}
return replaceAll(HERE_PATTERN, Matcher.quoteReplacement(here));
}

public synchronized Object setProperty(String key, String value, String provenance) {
if (provenance != null)
getProvenance().put(key, new Provenance(provenance));
return super.setProperty(key, value);
}

@Override
public synchronized Object remove(Object key) {
getProvenance().remove(key);
return super.remove(key);
}

/**
* Get the provenance of the given key if set
*
* @param key the key
*/

public Optional<String> getProvenance(String key) {
Provenance provenance = getProvenance().get(key);
return Optional.ofNullable(provenance)
.map(Provenance::source);
}

/**
* Set the provenance of the given key
*
* @param key the key
* @param provenance the provenance, maybe null to remove
*/

public UTF8Properties setProvenance(String key, String provenance) {
if (provenance == null)
getProvenance().remove(key);
else
getProvenance().put(key, new Provenance(provenance));
return this;
}

/**
* Load the properties from a properties. If the properties is a
* UTF8Properties, we also copy the provenance.
*
* @param properties the properties
* @param overwriteIfPresent overwrite an exissting value in this properties
*/
public void load(Properties properties, boolean overwriteIfPresent) {
BiConsumer<String, String> set = properties instanceof UTF8Properties p
? (k, v) -> setProperty(k, v, p.getProvenance(k)
.orElse(null))
: (k, v) -> setProperty(k, v);

properties.forEach((k, v) -> {
String key = (String) k;
String value = (String) v;
if (overwriteIfPresent || !contains(key))
set.accept(key, value);
});
}

Map<String, Provenance> getProvenance() {
return provenance;
}

@Override
public synchronized void putAll(Map<?, ?> t) {
if (t instanceof Properties p) {
load(p, true);
} else
super.putAll(t);
}

/**
* Set the provenance on all current keys
*
* @param provenance
*/
public void setProvenance(String provenance) {
keySet().forEach(k -> setProvenance((String) k, provenance));
}
}
2 changes: 1 addition & 1 deletion aQute.libg/src/aQute/lib/utf8properties/package-info.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@Version("4.1.0")
@Version("4.2.0")
package aQute.lib.utf8properties;

import org.osgi.annotation.versioning.Version;
35 changes: 35 additions & 0 deletions aQute.libg/test/aQute/lib/utf8properties/UTF8PropertiesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,41 @@ public void testWriteFile(@InjectTemporaryDirectory
assertThat(p1).containsExactlyInAnyOrderEntriesOf(p);
}

@Test
public void testProvenance() throws IOException {
UTF8Properties a = new UTF8Properties();
a.load("""
a.a = 1
a.b = 2
x = 0
""", null, null, null, "from_a");
UTF8Properties b = new UTF8Properties();
b.load("""
b.a = 1
b.c = 3
x = 0
""", null, null, null, "from_b");

assertThat(a.getProvenance("x")).isPresent()
.get()
.isEqualTo("from_a");
assertThat(b.getProvenance("x")).isPresent()
.get()
.isEqualTo("from_b");
assertThat(a.getProvenance("y")).isNotPresent();

a.load(b, true);
assertThat(a.getProvenance("x")).isPresent()
.get()
.isEqualTo("from_b");
assertThat(a.getProvenance("a.a")).isPresent()
.get()
.isEqualTo("from_a");
assertThat(a.getProvenance("b.a")).isPresent()
.get()
.isEqualTo("from_b");
}

private void testProperty(String content, String key, String value) throws IOException {
testProperty(content, key, value, null);
}
Expand Down
76 changes: 76 additions & 0 deletions biz.aQute.bndlib.tests/test/test/ProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import aQute.lib.collections.ExtList;
import aQute.lib.io.IO;
import aQute.lib.strings.Strings;
import aQute.lib.utf8properties.UTF8Properties;
import aQute.libg.reporter.ReporterAdapter;
import aQute.service.reporter.Reporter;
import aQute.service.reporter.Reporter.SetLocation;
Expand Down Expand Up @@ -774,4 +775,79 @@ public void testIncludeItself() throws IOException {
}
}

@Test
public void testProvenance() throws IOException {
File base = IO.getFile("generated/provenance");
try {
base.mkdirs();
File bnd = new File(base, "bnd.bnd");
IO.store("""
-include sup.bnd, ~inf.bnd
in_top = top
in_sup = top
#in_inf = top
top = true
""", bnd);
File sup = new File(base, "sup.bnd");
IO.store("""
#in_top = sup
in_sup = sup
#in_inf = sup
sup = true
""", sup);
File inf = new File(base, "inf.bnd");
IO.store("""
-include sup.bnd, ~inf.bnd
in_top = inf
in_sup = inf
in_inf = inf
inf = true
sup = false
top = false
""", inf);

try (Processor a = new Processor(); Processor b = new Processor(a)) {
a.setProperty("a", "true");
b.setProperties(bnd);
UTF8Properties bp = (UTF8Properties) b.getProperties();
assertThat(b.getProperty("a")).isEqualTo("true");
assertThat(b.getProperty("in_top")).isEqualTo("top");
assertThat(b.getProperty("in_sup")).isEqualTo("sup");
assertThat(b.getProperty("in_inf")).isEqualTo("inf");
assertThat(b.getProperty("top")).isEqualTo("true");
assertThat(b.getProperty("sup")).isEqualTo("true");
assertThat(b.getProperty("inf")).isEqualTo("true");

assertThat(bp.getProvenance("in_top")).isPresent()
.get()
.isEqualTo(bnd.getAbsolutePath());
assertThat(bp.getProvenance("in_sup")).isPresent()
.get()
.isEqualTo(sup.getAbsolutePath());
assertThat(bp.getProvenance("in_inf")).isPresent()
.get()
.isEqualTo(inf.getAbsolutePath());
assertThat(bp.getProvenance("top")).isPresent()
.get()
.isEqualTo(bnd.getAbsolutePath());
assertThat(bp.getProvenance("sup")).isPresent()
.get()
.isEqualTo(sup.getAbsolutePath());

bp.remove("in_top");
assertThat(bp.getProvenance("in_top")).isNotPresent();

b.setProperty("in_top", "foo");
assertThat(bp.getProvenance("in_top")).isNotPresent();
b.setProperty("in_top", "bar", "xxx");
assertThat(bp.getProvenance("in_top")).isPresent()
.get()
.isEqualTo("xxx");
}
} finally {
IO.delete(base);
}

}

}
2 changes: 2 additions & 0 deletions biz.aQute.bndlib.tests/testresources/provenance/bnd.bnd
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-include a/sup.bnd,~a/inf.bnd

9 changes: 5 additions & 4 deletions biz.aQute.bndlib/src/aQute/bnd/build/MagicBnd.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import aQute.bnd.result.Result;
import aQute.lib.io.IO;
import aQute.lib.strings.Strings;
import aQute.lib.utf8properties.UTF8Properties;
import aQute.libg.re.Catalog;
import aQute.libg.re.RE;
import aQute.libg.re.RE.Match;
Expand Down Expand Up @@ -77,8 +78,8 @@ private static Result<Properties> convertOBR(Workspace workspace, File file) {
.append("'");
}

Properties p = new Properties();
p.put("-plugin.ext." + file.getName(), sb.toString());
UTF8Properties p = new UTF8Properties();
p.setProperty("-plugin.ext." + file.getName(), sb.toString(), file.getAbsolutePath());
return Result.ok(p);
}

Expand Down Expand Up @@ -163,8 +164,8 @@ private static Result<Properties> convertMaven(Workspace ws, File file) {
.collect(Collectors.joining()))
.append("'");

Properties p = new Properties();
p.put("-plugin.ext." + file.getName(), sb.toString());
UTF8Properties p = new UTF8Properties();
p.setProperty("-plugin.ext." + file.getName(), sb.toString(), file.getAbsolutePath());
return Result.ok(p);
}
}
2 changes: 1 addition & 1 deletion biz.aQute.bndlib/src/aQute/bnd/build/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ public void prepare() throws Exception {

// We use a builder to construct all the properties for
// use.
setProperty("basedir", basePath);
setProperty("basedir", basePath, "[project]");

// If a bnd.bnd file exists, we read it.
// Otherwise, we just do the build properties.
Expand Down
Loading

0 comments on commit c61e476

Please sign in to comment.