From fbc917cbd192b3becec226b401991eb254932eff Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Tue, 9 Apr 2024 20:20:10 +0200 Subject: [PATCH 1/4] Update of BndEditModel Now properly reflects the inheritance structure of Processor chains --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../test/test/BndEditModelTest.java | 24 +- .../test/test/PropertiesTest.java | 13 +- .../src/aQute/bnd/build/Project.java | 58 +++- .../src/aQute/bnd/build/SubProject.java | 51 +++ .../aQute/bnd/build/model/BndEditModel.java | 298 ++++++++++-------- .../src/aQute/bnd/osgi/Processor.java | 47 +-- .../src/biz/aQute/resolve/Bndrun.java | 8 +- .../test/biz/aQute/resolve/ResolveTest.java | 1 - .../biz/aQute/resolve/ResolverTester.java | 5 +- .../src/bndtools/editor/BndEditor.java | 119 +++---- .../editor/project/RepositoriesEditModel.java | 5 +- .../editor/workspace/PluginsPart.java | 3 + .../core/resolve/ResolveOperation.java | 7 +- 13 files changed, 394 insertions(+), 245 deletions(-) create mode 100644 biz.aQute.bndlib/src/aQute/bnd/build/SubProject.java diff --git a/biz.aQute.bndlib.tests/test/test/BndEditModelTest.java b/biz.aQute.bndlib.tests/test/test/BndEditModelTest.java index 7ec7ca8895..761514db89 100644 --- a/biz.aQute.bndlib.tests/test/test/BndEditModelTest.java +++ b/biz.aQute.bndlib.tests/test/test/BndEditModelTest.java @@ -152,20 +152,6 @@ public void testVariableInSystemPackages() throws Exception { .mergeProperties(Constants.RUNSYSTEMPACKAGES)); } - @Test - public void testRunReposShared() throws Exception { - Workspace ws = new Workspace(new File("testresources/ws")); - BndEditModel model = new BndEditModel(ws); - File f = new File("testresources/ws/p7/syspkg.bndrun"); - model.setBndResource(f); - model.setBndResourceName("syspkg.bndrun"); - model.loadFrom(f); - - List runrepos = model.getRunRepos(); - assertEquals(1, runrepos.size()); - assertEquals("testing", runrepos.get(0)); - } - @Test public void testRemovePropertyFromStandalone() throws Exception { File runFile = IO.getFile("testresources/standalone.bndrun"); @@ -200,7 +186,7 @@ public void testGetProperties() throws Exception { BndEditModel model = new BndEditModel(run); assertThat(model.getWorkspace()).isNotNull(); - assertThat(model.getProject()).isNotNull(); + assertThat(model.getOwner()).isNotNull(); model.setGenericString("a", "AA"); @@ -248,8 +234,14 @@ public void testGetPropertiesWithoutParent() throws Exception { BndEditModel model = new BndEditModel(); model.setGenericString("foo", "FOO"); Processor p = model.getProperties(); - assertThat(p.getProperty("foo")).isEqualTo("FOO"); + assertThat(p.getPropertyKeys(false)).contains("foo"); + + model.loadFrom(""); + p = model.getProperties(); + assertThat(p.getProperty("foo")).isNull(); + assertThat(p.getPropertyKeys(false)).doesNotContain("foo"); + } @Test diff --git a/biz.aQute.bndlib.tests/test/test/PropertiesTest.java b/biz.aQute.bndlib.tests/test/test/PropertiesTest.java index 68fcd5371e..453468b5e0 100644 --- a/biz.aQute.bndlib.tests/test/test/PropertiesTest.java +++ b/biz.aQute.bndlib.tests/test/test/PropertiesTest.java @@ -1,5 +1,6 @@ package test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -49,14 +50,24 @@ public void testFilter() { p1.setProperty("dan", "bandera"); p1.setProperty("susan", "sarandon"); p1.setProperty("jon", "bostrom"); + p1.setProperty("bj", "hargrave"); Processor p2 = new Processor(p1); - p2.setForceLocal(Arrays.asList("dan")); + p2.setForceLocal(Arrays.asList("dan", "bj")); p2.setProperty("susan", "schwarze"); + p2.setProperty("bj", "ibm"); assertNull(p2.getProperty("dan")); + assertEquals("sarandon", p1.getProperty("susan")); assertEquals("schwarze", p2.getProperty("susan")); + assertEquals("bostrom", p1.getProperty("jon")); assertEquals("bostrom", p2.getProperty("jon")); + assertEquals(null, p2.getProperty("dan")); + assertEquals("bandera", p1.getProperty("dan")); + assertEquals("ibm", p2.getProperty("bj")); + assertEquals("hargrave", p1.getProperty("bj")); + + assertThat(p2.getPropertyKeys(true)).containsExactlyInAnyOrder("susan", "jon", "bj"); } @Test diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/Project.java b/biz.aQute.bndlib/src/aQute/bnd/build/Project.java index 39c68a90ae..f2a0c2a3a7 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/Project.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/Project.java @@ -3678,13 +3678,9 @@ public Optional findProcessor(File file) { .endsWith(".bndrun")) return Optional.of(Run.createRun(getWorkspace(), file)); - try (ProjectBuilder builder = getBuilder(null)) { - for (Builder b : builder.getSubBuilders()) { - if (file.equals(b.getPropertiesFile())) { - Processor sub = new Processor(this); - sub.setProperties(file); - return Optional.of(sub); - } + for (SubProject sub : getSubProjects()) { + if (file.equals(sub.getPropertiesFile())) { + return Optional.of(sub); } } return Optional.empty(); @@ -3692,4 +3688,52 @@ public Optional findProcessor(File file) { throw Exceptions.duck(e); } } + + /** + * Return a list of sub projects. + */ + + @SuppressWarnings("resource") + public List getSubProjects() { + + String sub = getProperty(SUB); + if (sub == null || sub.trim() + .length() == 0 || EMPTY_HEADER.equals(sub)) { + return Collections.emptyList(); + } + + if (isTrue(getProperty(NOBUNDLES))) + return Collections.emptyList(); + + Set parentFiles = new HashSet<>(); + Processor rover = this; + while (rover != null) { + parentFiles.add(rover.getPropertiesFile()); + rover = rover.getParent(); + } + + List subProjects = new ArrayList<>(); + Instructions instructions = new Instructions(sub); + List members = IO.listFiles(getBase()); + nextFile: while (!members.isEmpty()) { + + File file = members.remove(0); + if (!file.isFile() || file.getName() + .startsWith(".") || parentFiles.contains(file)) + continue nextFile; + + for (Instruction instruction : instructions.keySet()) { + if (instruction.matches(file.getName())) { + + if (!instruction.isNegated()) { + subProjects.add(new SubProject(this, file)); + } + continue nextFile; + } + } + } + return subProjects; + + } + } diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/SubProject.java b/biz.aQute.bndlib/src/aQute/bnd/build/SubProject.java new file mode 100644 index 0000000000..99bcaa9228 --- /dev/null +++ b/biz.aQute.bndlib/src/aQute/bnd/build/SubProject.java @@ -0,0 +1,51 @@ +package aQute.bnd.build; + +import java.io.File; + +import aQute.bnd.osgi.Processor; +import aQute.lib.strings.Strings; + +/** + * Models a sub project when the `-sub` instruction is used. + */ +public class SubProject extends Processor { + + final Project project; + final String name; + + SubProject(Project project, File properties) { + super(project); + assert properties != null && properties.isFile(); + this.project = project; + String[] parts = Strings.extension(properties.getName()); + if (parts == null) + name = properties.getName(); + else + name = parts[0]; + + setBase(project.getBase()); + this.setProperties(properties); + use(project); + } + + @Override + public String toString() { + return project + "." + getName(); + } + + public Project getProject() { + return project; + } + + public String getName() { + return name; + } + + public ProjectBuilder getProjectBuilder() throws Exception { + ProjectBuilder builder = new ProjectBuilder(project); + builder.setProperties(getPropertiesFile()); + builder.use(this); + addClose(this); + return builder; + } +} diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java index 89af625a6e..c6a5fd5c99 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java @@ -11,15 +11,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.TreeMap; @@ -31,7 +34,6 @@ import aQute.bnd.build.Project; import aQute.bnd.build.Workspace; -import aQute.bnd.build.WorkspaceLayout; import aQute.bnd.build.model.clauses.ExportedPackage; import aQute.bnd.build.model.clauses.HeaderClause; import aQute.bnd.build.model.clauses.ImportPattern; @@ -67,15 +69,16 @@ import aQute.bnd.properties.PropertiesLineReader; import aQute.bnd.version.Version; import aQute.lib.collections.Iterables; +import aQute.lib.collections.Logic; import aQute.lib.io.IO; import aQute.lib.utf8properties.UTF8Properties; /** - * A model for a Bnd file. In the first iteration, use a simple Properties - * object; this will need to be enhanced to additionally record formatting, e.g. - * line breaks and empty lines, and comments. - * - * @author Neil Bartlett + * A model for a Bnd file. + *

+ * The model is an editor on the properties file on which bnd is based on. + * However, in bnd there is always a Processor involved. The Processor links to + * a file and can inherit from a parent Processor. */ @SuppressWarnings("deprecation") public class BndEditModel { @@ -99,27 +102,10 @@ public class BndEditModel { }; public static final String PROP_WORKSPACE = "_workspace"; - public static final String BUNDLE_VERSION_MACRO = "${" + Constants.BUNDLE_VERSION + "}"; - private static final Map> converters = new HashMap<>(); private static final Map> formatters = new HashMap<>(); - // private final DataModelHelper obrModelHelper = new DataModelHelperImpl(); - - private File bndResource; - private String bndResourceName; - - private final PropertyChangeSupport propChangeSupport = new PropertyChangeSupport( - this); - private Properties properties = new UTF8Properties(); - private final Map objectProperties = new HashMap<>(); - private final Map changesToSave = new TreeMap<>(); - private Project bndrun; - - private volatile boolean dirty; - - // CONVERTERS private final static Converter, String> buildPathConverter = new HeaderClauseListConverter<>( new Converter() { @Override @@ -269,11 +255,19 @@ public ImportPattern error( private final static Converter eeFormatter = new EEFormatter(); private final static Converter> runReposFormatter = new CollectionFormatter<>( LIST_SEPARATOR, Constants.EMPTY_HEADER); - private Workspace workspace; - private IDocument document; - // for change detection when multiple wizards look at the same model + private File inputFile; + private String name; + private final PropertyChangeSupport propChangeSupport = new PropertyChangeSupport( + this); + private Properties properties = new UTF8Properties(); + private final Map objectProperties = new HashMap<>(); + private final Map changesToSave = new TreeMap<>(); + private Processor owner; + private volatile boolean dirty; + private IDocument document; private long lastChangedAt; + private Workspace workspace; // Converter resolveModeFormatter = // EnumFormatter.create(ResolveMode.class, ResolveMode.manual); @@ -315,6 +309,7 @@ public ImportPattern error( converters.put(Constants.RUNREPOS, listConverter); // converters.put(BndConstants.RESOLVE_MODE, resolveModeConverter); converters.put(Constants.BUNDLE_BLUEPRINT, headerClauseListConverter); + converters.put(Constants.INCLUDE_RESOURCE, listConverter); converters.put(Constants.INCLUDERESOURCE, listConverter); converters.put(Constants.STANDALONE, headerClauseListConverter); @@ -365,14 +360,24 @@ public ImportPattern error( } - public BndEditModel() {} + /** + * Default constructor + */ + public BndEditModel() { + setOwner(new Processor()); + } + /** + * Copy constructor + * + * @param model the source + */ public BndEditModel(BndEditModel model) { - this(); - this.bndResource = model.bndResource; + this.inputFile = model.inputFile; this.workspace = model.workspace; this.properties.putAll(model.properties); this.changesToSave.putAll(model.changesToSave); + setOwner(model.getOwner()); } public BndEditModel(Workspace workspace) { @@ -381,14 +386,13 @@ public BndEditModel(Workspace workspace) { } public BndEditModel(IDocument document) throws IOException { - this(); loadFrom(document); } - public BndEditModel(Project bndrun) throws IOException { - this(bndrun.getWorkspace()); - this.bndrun = bndrun; - File propertiesFile = bndrun.getPropertiesFile(); + public BndEditModel(Workspace workspace, Processor processor) throws IOException { + this(workspace); + this.owner = processor; + File propertiesFile = processor.getPropertiesFile(); if (propertiesFile.isFile()) this.document = new Document(IO.collect(propertiesFile)); else @@ -396,25 +400,6 @@ public BndEditModel(Project bndrun) throws IOException { loadFrom(this.document); } - /** - * Is either the workspace (when cnf/build.bnd) or a project (when its - * bnd.bnd) or a random bndrun linked to workspace (event if it isn't a - * bndrun). Primary purpose is to walk the inheritance chain implied in the - * Workspace/Project/sub bnd files files - */ - Processor getOwner() { - if (bndrun == null) - return new Processor(); - - File propertiesFile = bndrun.getPropertiesFile(); - if (!propertiesFile.getName() - .endsWith(".bnd")) - return bndrun; - - return workspace.findProcessor(propertiesFile) - .orElse(bndrun); - } - public void loadFrom(IDocument document) throws IOException { try (InputStream in = toEscaped(document.get())) { loadFrom(in); @@ -450,18 +435,7 @@ public void loadFrom(File file) throws IOException { public void loadFrom(InputStream inputStream) throws IOException { try { - // Clear and load - // The reason we skip standalone workspace properties - // as parent is that they are copy of the Run file. - // and confuse this edit model when you remove a - // property. - - if (this.workspace != null && this.workspace.getLayout() != WorkspaceLayout.STANDALONE) { - properties = (Properties) this.workspace.getProperties() - .clone(); - } else { - properties.clear(); - } + properties.clear(); properties.load(inputStream); objectProperties.clear(); changesToSave.clear(); @@ -477,6 +451,10 @@ public void loadFrom(InputStream inputStream) throws IOException { } + public void loadFrom(String string) throws IOException { + loadFrom(IO.stream(string)); + } + public void saveChangesTo(IDocument document) { this.lastChangedAt = System.currentTimeMillis(); for (Iterator> iter = changesToSave.entrySet() @@ -1014,8 +992,6 @@ public void setPlugins(List plugins) { doSetObject(Constants.PLUGIN, old, plugins, complexHeaderClauseListFormatter); } - - /** * Similar to {@link #getPlugins()} but returns a map where the key is the * property key of the bnd file e.g. @@ -1031,20 +1007,18 @@ public Map> getPluginsProperties() { } private Map> getProperties(String stem) { - // return all properties - // we do step prefix-matching to support merged properties. e.g. - // stem=-plugin hould return - // -plugin.1.Test, -plugin.2.Maven etc. - try { Map> map = new LinkedHashMap<>(); + Processor processor = getProperties(); + Set localKeys = processor.getPropertyKeys(false); + List candidates = processor.getMergePropertyKeys(stem); - PropertyKey.findVisible(getOwner().getMergePropertyKeys(stem)) + PropertyKey.findVisible(candidates) .stream() .forEach(pk -> { - boolean isLocal = isLocalPropertyKey(pk.key()); + boolean isLocal = localKeys.contains(pk.key()); List headers = headerClauseListConverter.convert(pk.getValue()) .stream() @@ -1093,9 +1067,8 @@ private void setProperties(String stem, Map oldList = old.get(p.getKey()); List oldLocalHeaders = oldList == null ? null - : oldList - .stream() - .filter(mh -> mh.isLocal()) + : oldList.stream() + .filter(mh -> mh.isLocal()) .toList(); if (oldList != null && !isLocalPropertyKey(p.getKey())) { @@ -1105,8 +1078,7 @@ private void setProperties(String stem, Maptrue if the given propertyKey is physically in the @@ -1296,21 +1266,24 @@ public void removePropertyChangeListener(String propertyName, PropertyChangeList } public void setBndResource(File bndResource) { - this.bndResource = bndResource; + this.inputFile = bndResource; } public File getBndResource() { - return bndResource; + if (inputFile != null) + return inputFile; + + return owner.getPropertiesFile(); } public String getBndResourceName() { - if (bndResourceName == null) + if (name == null) return ""; - return bndResourceName; + return name; } public void setBndResourceName(String bndResourceName) { - this.bndResourceName = bndResourceName; + this.name = bndResourceName; } public List getBundleBlueprint() { @@ -1387,12 +1360,13 @@ private boolean hasIncludeResourceHeaderLikeInstruction() { return properties.containsKey(Constants.INCLUDE_RESOURCE); } + @Deprecated public void setProject(Project project) { - this.bndrun = project; + setOwner(project); } public Project getProject() { - return bndrun; + return null; } public Workspace getWorkspace() { @@ -1414,57 +1388,83 @@ public void setGenericString(String name, String value) { } /** - * Return a processor for this model. This processor is based on the parent - * project or the bndrun file. It will contain the properties of the project - * file and the changes from the model. + * Return a processor for this model. This processor is based on the + * properties of the source processor but with the values of the changed + * properties in this edit model. I.e. the view of the returned processor of + * the properties is the same as when this model would be saved. + *

+ * The returned processor will use the owner of this model as the parent so + * that all unchanged properties come from the original owner. + *

+ * When using this method, realize that if you edit a project's bnd.bnd + * file, the returned processor adds an intermediate layer. The + * {@link #owner} is the original Workspace, Project, Bndrun, or sub bnd + * object. * - * @return a processor that reflects the actual project or bndrun file setup - * @throws Exception + * @return a processor that reflects the actual processors setup */ + public Processor getProperties() throws Exception { - File source = getBndResource(); - Processor parent; - if (bndrun != null) { - parent = bndrun; - if (source == null) { - source = bndrun.getPropertiesFile(); - } - } else if (workspace != null && isCnf()) { - parent = workspace; - if (source == null) { - source = workspace.getPropertiesFile(); - } - } else if (source != null) { - parent = Workspace.getRun(source); - if (parent == null) { - parent = new Processor(); - parent.setProperties(source); - } - } else { - parent = new Processor(properties, false); + UTF8Properties currentProperties = new UTF8Properties(); + currentProperties.putAll(properties); + if (!changesToSave.isEmpty()) { + String changes = changesToString(); + currentProperties.load(changes, null, null); } - UTF8Properties p = new UTF8Properties(parent.getProperties()); + Set ownerLocalKeys = owner.getPropertyKeys(false); + Set editedLocalKeys = currentProperties.keySet() + .stream() + .map(String.class::cast) + .collect(Collectors.toSet()); - if (!changesToSave.isEmpty()) { - StringBuilder sb = new StringBuilder(); - changesToSave.forEach((key, value) -> sb.append(key) - .append(':') - .append(' ') - .append(value) - .append('\n') - .append('\n')); - p.load(sb.toString(), null, null); + Collection deleted = Logic.remove(ownerLocalKeys, editedLocalKeys); + + Set inheritedKeysWithoutOwner = new HashSet<>(editedLocalKeys); + + Processor parent = owner.getParent(); + if (parent != null) { + + // we leave out the keys of the owner + inheritedKeysWithoutOwner.addAll(parent.getPropertyKeys(true)); } - Processor result; - p = p.replaceHere(parent.getBase()); - result = new Processor(parent, p, false); - result.setBase(parent.getBase()); - if (source != null) - result.setPropertiesFile(source); - return result; + File source = getBndResource(); + Processor dummy = new Processor(owner) { + @Override + public Set getPropertyKeys(boolean inherit) { + if (inherit) { + return Collections.unmodifiableSet(inheritedKeysWithoutOwner); + } + return super.getPropertyKeys(false); + } + + @Override + public String getProperty(String key, String deflt, String separator) { + if (!inheritedKeysWithoutOwner.contains(key)) + return deflt; + + return super.getProperty(key, deflt, separator); + } + }; + dummy.setBase(owner.getBase()); + dummy.setPropertiesFile(owner.getPropertiesFile()); + + currentProperties = currentProperties.replaceHere(dummy.getBase()); + dummy.setProperties(currentProperties); + return dummy; + } + + String changesToString() { + StringBuilder sb = new StringBuilder(); + changesToSave.forEach((key, value) -> sb.append(key) + .append(':') + .append(' ') + .append(value) + .append('\n') + .append('\n')); + return sb.toString(); } private String cleanup(String value) { @@ -1501,10 +1501,10 @@ public Map getDocumentChanges() { */ public void saveChanges() throws IOException { assert document != null - && bndrun != null : "you can only call saveChanges when you created this edit model with a project"; + && owner != null : "you can only call saveChanges when you created this edit model with a project"; saveChangesTo(document); - store(document, getProject().getPropertiesFile()); + store(document, owner.getPropertiesFile()); dirty = false; } @@ -1518,7 +1518,7 @@ public ResolutionInstructions.ResolveMode getResolveMode() { try { return aQute.lib.converter.Converter.cnv(ResolutionInstructions.ResolveMode.class, resolve); } catch (Exception e) { - bndrun.error("Invalid value for %s: %s. Allowed values are %s", Constants.RESOLVE, resolve, + owner.error("Invalid value for %s: %s. Allowed values are %s", Constants.RESOLVE, resolve, ResolutionInstructions.ResolveMode.class.getEnumConstants()); } } @@ -1542,7 +1542,7 @@ public void setDirty(boolean isDirty) { } public void load() throws IOException { - loadFrom(bndrun.getPropertiesFile()); + loadFrom(owner.getPropertiesFile()); } /** @@ -1550,9 +1550,10 @@ public void load() throws IOException { * * @return true if it is the cnf project */ + @Deprecated public boolean isCnf() { - return bndResource != null && Workspace.CNFDIR.equals(bndResource.getParentFile() - .getName()) && Workspace.BUILDFILE.equals(bndResource.getName()); + return inputFile != null && Workspace.CNFDIR.equals(inputFile.getParentFile() + .getName()) && Workspace.BUILDFILE.equals(inputFile.getName()); } /** @@ -1587,11 +1588,13 @@ public > String add(String header, String toAdd) { @SuppressWarnings("rawtypes") T newValue = (T) last.getClass() + .getConstructor() .newInstance(); if (oldValue != null) newValue.addAll(oldValue); else oldValue = (T) last.getClass() + .getConstructor() .newInstance(); newValue.addAll(last); @@ -1599,7 +1602,8 @@ public > String add(String header, String toAdd) { Converter formatter = (Converter) formatters.get(header); doSetObject(header, oldValue, newValue, formatter); return header + ": " + formatter.convert(newValue); - } catch (IllegalArgumentException | InstantiationException | IllegalAccessException e) { + } catch (IllegalArgumentException | InstantiationException | IllegalAccessException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { throw Exceptions.duck(e); } } @@ -1607,4 +1611,24 @@ public > String add(String header, String toAdd) { public long getLastChangedAt() { return lastChangedAt; } + + public void setOwner(Processor p) { + this.owner = p; + } + + public Processor getOwner() { + return owner; + } + + public Optional getOwner(Class class1) { + if (class1.isInstance(owner)) + return Optional.of(class1.cast(owner)); + else + return Optional.empty(); + } + + public BndEditModel(Project domain) throws IOException { + this(domain.getWorkspace(), domain); + } + } diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java index 2b94ddab88..b95f93959e 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java @@ -29,7 +29,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -175,7 +174,7 @@ public Processor(Properties props) { } public Processor(Processor parent) { - this(parent, parent.getProperties0(), true); + this(parent, parent.getRawProperties(), true); } public Processor(Properties props, boolean wrap) { @@ -192,8 +191,8 @@ public Processor(Processor parent, Properties props, boolean wrap) { public void setParent(Processor parent) { this.parent = parent; - Properties updated = (parent != null) ? new UTF8Properties(parent.getProperties0()) : new UTF8Properties(); - updated.putAll(getProperties0()); + Properties updated = (parent != null) ? new UTF8Properties(parent.getRawProperties()) : new UTF8Properties(); + updated.putAll(getRawProperties()); properties = updated; propertiesChanged(); } @@ -625,10 +624,16 @@ public Properties getProperties() { fixup = false; begin(); } - return getProperties0(); + return getRawProperties(); } - private Properties getProperties0() { + /** + * This is the primary place where we get the local Properties. No code in + * this class should use this variable directory. + * + * @return the local properties + */ + protected Properties getRawProperties() { return properties; } @@ -680,9 +685,9 @@ public void setProperties(InputStream properties) throws IOException { public void setProperties(File base, Properties properties) { doIncludes(base, properties); - getProperties0().putAll(properties); + getRawProperties().putAll(properties); mergeProperties(Constants.INIT); // execute macros in -init - getProperties0().remove(Constants.INIT); + getRawProperties().remove(Constants.INIT); propertiesChanged(); } @@ -882,7 +887,7 @@ boolean isStrict() { public void forceRefresh() { included.clear(); Processor p = getParent(); - properties = (p != null) ? new UTF8Properties(p.getProperties0()) : new UTF8Properties(); + properties = (p != null) ? new UTF8Properties(p.getRawProperties()) : new UTF8Properties(); setProperties(propertiesFile, base); } @@ -1061,12 +1066,19 @@ public int compareTo(PropertyKey o) { * @param keys sorted keys defined by {@link #compareTo(PropertyKey)} * @return only unique keys which are visible (lowest floor value) */ - public static Collection findVisible(Collection keys) { - Map map = new LinkedHashMap<>(); - for (PropertyKey pk : keys) { - map.putIfAbsent(pk.key(), pk); + public static List findVisible(Collection keys) { + List l = new ArrayList<>(keys); + Collections.sort(l); + String rover = null; + Iterator it = l.iterator(); + while (it.hasNext()) { + PropertyKey candidate = it.next(); + if (!candidate.key.equals(rover)) { + rover = candidate.key; + } else + it.remove(); } - return new LinkedHashSet<>(map.values()); + return l; } } @@ -1318,7 +1330,7 @@ public Set getPropertyKeys(boolean inherit) { result.removeAll(filter); } } - for (Object o : getProperties0().keySet()) { + for (Object o : getRawProperties().keySet()) { result.add(o.toString()); } return result; @@ -1910,7 +1922,7 @@ public Spliterator spliterator() { } private Iterable iterable(boolean inherit, Predicate keyFilter) { - Set first = getProperties0().keySet(); + Set first = getRawProperties().keySet(); Iterable second; if (getParent() == null || !inherit) { second = Collections.emptyList(); @@ -2220,7 +2232,7 @@ public boolean since(Version introduced) { public void report(Map table) throws Exception { table.put("Included Files", getIncluded()); table.put("Base", getBase()); - table.put("Properties", getProperties0().entrySet()); + table.put("Properties", getRawProperties().entrySet()); } /** @@ -2731,5 +2743,4 @@ public boolean isPedantic() { public void setPedantic(boolean pedantic) { this.pedantic = pedantic; } - } diff --git a/biz.aQute.resolve/src/biz/aQute/resolve/Bndrun.java b/biz.aQute.resolve/src/biz/aQute/resolve/Bndrun.java index 09d25e777b..6f9adce1aa 100644 --- a/biz.aQute.resolve/src/biz/aQute/resolve/Bndrun.java +++ b/biz.aQute.resolve/src/biz/aQute/resolve/Bndrun.java @@ -73,17 +73,17 @@ public static Bndrun createBndrun(Workspace workspace, File file) throws Excepti } public Bndrun(BndEditModel model) throws Exception { - super(model.getWorkspace(), model.getProject() + super(model.getWorkspace(), model.getOwner() .getPropertiesFile()); this.model = model; - this.resolutionInstructions = Syntax.getInstructions(model.getProject(), ResolutionInstructions.class); + this.resolutionInstructions = Syntax.getInstructions(model.getOwner(), ResolutionInstructions.class); } public Bndrun(Workspace workspace, File propertiesFile) throws Exception { super(workspace, propertiesFile); this.model = new BndEditModel(this); - this.resolutionInstructions = Syntax.getInstructions(model.getProject(), ResolutionInstructions.class); + this.resolutionInstructions = Syntax.getInstructions(model.getOwner(), ResolutionInstructions.class); } /** @@ -156,7 +156,7 @@ public boolean update(RunResolution resolution, boolean failOnChanges, boolean w try { model.saveChanges(); } catch (Exception e) { - error("Could not save runbundles in their properties file %s. %s", model.getProject(), + error("Could not save runbundles in their properties file %s. %s", model.getOwner(), e.getMessage()); } } diff --git a/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java b/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java index f76d63208f..fe63a8b3ec 100644 --- a/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java +++ b/biz.aQute.resolve/test/biz/aQute/resolve/ResolveTest.java @@ -637,7 +637,6 @@ public void testMultipleOptionsNotDuplicated() throws Exception { runModel.setEE(EE.JavaSE_1_7); runModel.setSystemPackages(Collections.singletonList(new ExportedPackage("org.w3c.dom.traversal", null))); runModel.setGenericString("-resolve.effective", "active"); - // Require the log service, GoGo shell and GoGo commands List requirements = new ArrayList<>(); diff --git a/biz.aQute.resolve/test/biz/aQute/resolve/ResolverTester.java b/biz.aQute.resolve/test/biz/aQute/resolve/ResolverTester.java index 5c67ee6fe6..3722475097 100644 --- a/biz.aQute.resolve/test/biz/aQute/resolve/ResolverTester.java +++ b/biz.aQute.resolve/test/biz/aQute/resolve/ResolverTester.java @@ -14,6 +14,7 @@ import org.osgi.resource.Wiring; import org.osgi.service.log.LogService; +import aQute.bnd.build.Project; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Processor; @@ -38,7 +39,9 @@ public ResolverTester(String test) throws Exception { } public ResolverTester(String descriptor, BndEditModel model) throws Exception { - super(model.getProperties(), model.getProject(), model.getProperties(), log); + super(model.getProperties(), model.getOwner(Project.class) + .orElse(null), + model.getProperties(), log); this.model = model; this.descriptor = descriptor; diff --git a/bndtools.core/src/bndtools/editor/BndEditor.java b/bndtools.core/src/bndtools/editor/BndEditor.java index bd45a351dd..daae63e131 100644 --- a/bndtools.core/src/bndtools/editor/BndEditor.java +++ b/bndtools.core/src/bndtools/editor/BndEditor.java @@ -14,7 +14,6 @@ import org.bndtools.api.ILogger; import org.bndtools.api.Logger; -import org.bndtools.api.RunMode; import org.bndtools.api.editor.IBndEditor; import org.bndtools.api.launch.LaunchConstants; import org.bndtools.core.jobs.JobUtil; @@ -84,8 +83,8 @@ import aQute.bnd.build.model.BndEditModel; import aQute.bnd.exceptions.Exceptions; import aQute.bnd.help.instructions.ResolutionInstructions.ResolveMode; +import aQute.bnd.osgi.Processor; import aQute.bnd.properties.BadLocationException; -import biz.aQute.resolve.Bndrun; import bndtools.Plugin; import bndtools.central.Central; import bndtools.editor.common.IPriority; @@ -224,8 +223,10 @@ private static boolean isExtWorkspaceConfig(String path, String projectName) { private IHandlerActivation resolveHandlerActivation; private JobChangeAdapter resolveJobListener; - /* (non-Javadoc) - * @see bndtools.editor.IBndEditor#doSave(org.eclipse.core.runtime.IProgressMonitor) + /* + * (non-Javadoc) + * @see bndtools.editor.IBndEditor#doSave(org.eclipse.core.runtime. + * IProgressMonitor) */ @Override public void doSave(IProgressMonitor monitor) { @@ -244,7 +245,8 @@ public void doSave(IProgressMonitor monitor) { } } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see bndtools.editor.IBndEditor#commitDirtyPages() */ @Override @@ -266,7 +268,7 @@ private void reallySave(IProgressMonitor monitor) { return; } sourcePage.doSave(monitor); - loadEditModel(); + loadEditModel(inputFile, model); updateIncludedPages(); } catch (Exception e) { ErrorDialog.openError(getEditorSite().getShell(), "Error", null, @@ -537,14 +539,12 @@ public void init(IEditorSite site, IEditorInput input) throws PartInitException .addResourceChangeListener(this); inputFile = inputResource.getLocation() .toFile(); - model.setBndResourceName(inputResource.getName()); } else { if (input instanceof FileStoreEditorInput) { URI uri = ((FileStoreEditorInput) input).getURI(); if (uri != null && uri.getScheme() .equalsIgnoreCase("file")) { this.inputFile = new File(uri); - model.setBndResourceName(this.inputFile.getName()); } } } @@ -554,27 +554,20 @@ public void init(IEditorSite site, IEditorInput input) throws PartInitException "The bnd editor can only edit files inside the workspace")); } - // Initialize pages and title + model.setBndResourceName(this.inputFile.getName()); + initPages(site, input); setSourcePage(sourcePage); setPartNameForInput(input); IDocumentProvider docProvider = sourcePage.getDocumentProvider(); - // #1625: Ensure the IDocumentProvider is not null. if (docProvider != null) { docProvider.addElementStateListener(new ElementStateListener()); - if (!Central.hasWorkspaceDirectory()) { // default ws will be - // created we can load - // immediately - modelReady = loadEditModel(); - } else { // a real ws will be resolved so we need to load async - modelReady = Central.onAnyWorkspace(workspace -> loadEditModel()); - } + modelReady = loadEditModel(inputFile, model); } else { modelReady = Central.promiseFactory() - .failed(new Exception("Model unavailable")); + .failed(new Exception("Model unavailable because there is no doc provider")); } - setupActions(); } catch (Exception e1) { @@ -616,51 +609,60 @@ public void done(IJobChangeEvent event) { } - private Promise loadEditModel() throws Exception { - // Create the bnd edit model and workspace - Project bndProject; - if (inputResource != null) { - bndProject = LaunchUtils.createRun(inputResource, RunMode.EDIT); - } else { - bndProject = Bndrun.createBndrun(null, this.inputFile); - } - model.setWorkspace(bndProject.getWorkspace()); - model.setProject(bndProject); - - // Load content into the edit model + private Promise loadEditModel(File inputFile, BndEditModel model) throws Exception { Deferred completed = Central.promiseFactory() .deferred(); - Display.getDefault() - .asyncExec(() -> { - final IDocumentProvider docProvider = sourcePage.getDocumentProvider(); - // #1625: Ensure the IDocumentProvider is not null. - if (docProvider != null) { + + Central.onAnyWorkspace(workspace -> { + + Processor p = workspace.readLocked(() -> workspace.findProcessor(inputFile) + .orElseGet(() -> { + Processor dummy = new Processor(); + dummy.setBase(inputFile.getParentFile()); + dummy.setPropertiesFile(inputFile); + return dummy; + })); + model.setWorkspace(workspace); + model.setOwner(p); + + Display.getDefault() + .asyncExec(() -> { try { - IDocument document = docProvider.getDocument(getEditorInput()); - model.loadFrom(new IDocumentWrapper(document)); - model.setBndResource(inputFile); - model.setDirty(false); - completed.resolve(model.getWorkspace()); - } catch (IOException e) { - logger.logError("Unable to load edit model", e); - completed.fail(e); - } + final IDocumentProvider docProvider = sourcePage.getDocumentProvider(); + if (docProvider != null) { + try { + IDocument document = docProvider.getDocument(getEditorInput()); + model.loadFrom(new IDocumentWrapper(document)); + model.setDirty(false); + } catch (IOException e) { + logger.logError("Unable to load edit model", e); + completed.fail(e); + } - for (int i = 0; i < getPageCount(); i++) { - Control control = getControl(i); + for (int i = 0; i < getPageCount(); i++) { + Control control = getControl(i); - if (control instanceof ScrolledForm) { - ScrolledForm form = (ScrolledForm) control; + if (control instanceof ScrolledForm) { + ScrolledForm form = (ScrolledForm) control; - if (SYNC_MESSAGE.equals(form.getMessage())) { - form.setMessage(null, IMessageProvider.NONE); + if (SYNC_MESSAGE.equals(form.getMessage())) { + form.setMessage(null, IMessageProvider.NONE); + } + } } + } else { + completed.fail(new Exception("Model unavailable")); + } + } finally { + if (!completed.getPromise() + .isDone()) { + completed.resolve(workspace); } } - } else { - completed.fail(new Exception("Model unavailable")); - } - }); + }); + + }); + return completed.getPromise(); } @@ -726,7 +728,9 @@ public void dispose() { .removeResourceChangeListener(this); } - LaunchUtils.endRun((Run) model.getProject()); + if (model.getOwner() instanceof Run run) { + LaunchUtils.endRun(run); + } if (resolveHandlerActivation != null) { resolveHandlerActivation.getHandlerService() @@ -878,7 +882,8 @@ public void elementContentAboutToBeReplaced(Object element) { } } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see bndtools.editor.IBndEditor#getModel() */ @Override diff --git a/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java b/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java index effd9450ae..96be58a6e5 100644 --- a/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java +++ b/bndtools.core/src/bndtools/editor/project/RepositoriesEditModel.java @@ -34,7 +34,8 @@ class RepositoriesEditModel { this.standalone = model.getStandaloneLinks(); this.runrepos = model.getRunRepos(); this.ignoreStandalone = model.getIgnoreStandalone(); - this.run = (Run) (model.getProject() instanceof Run ? model.getProject() : null); + this.run = model.getOwner(Run.class) + .orElse(null); if (runrepos == null) { actualOrder.addAll(pluginOrder); @@ -205,7 +206,7 @@ void updateStandaloneWorkspace(BndEditModel model) throws Exception { assert isStandalone(); Processor properties = model.getProperties(); - model.setWorkspace(Workspace.createStandaloneWorkspace(properties, model.getProject() + model.setWorkspace(Workspace.createStandaloneWorkspace(properties, model.getOwner() .getPropertiesFile() .toURI())); } diff --git a/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java b/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java index 5fdd3dce94..9b1bf8186d 100644 --- a/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java +++ b/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java @@ -101,6 +101,9 @@ final void createSection(Section section, FormToolkit toolkit) { ColumnViewerToolTipSupport.enableFor(viewer); viewer.setContentProvider(ArrayContentProvider.getInstance()); viewer.setLabelProvider(new PluginClauseLabelProvider(configElements)); + viewer.addDoubleClickListener(e -> { + doEdit(); + }); Button btnReload = toolkit.createButton(composite, "Reload", SWT.NONE); btnReload.setImage(refreshImg); diff --git a/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java b/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java index 9cfccd76e6..c4744ebdbe 100644 --- a/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java +++ b/bndtools.core/src/org/bndtools/core/resolve/ResolveOperation.java @@ -17,6 +17,7 @@ import org.osgi.service.coordinator.Coordinator; import org.osgi.service.resolver.ResolutionException; +import aQute.bnd.build.Project; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.exceptions.Exceptions; import aQute.bnd.exceptions.RunnableWithException; @@ -54,7 +55,11 @@ public void run(IProgressMonitor monitor) { operationCallbacks.addAll(callbacks); operationCallbacks.add(new ResolutionProgressCallback(monitor)); - RunResolution resolution = RunResolution.resolve(model.getProject(), model.getProperties(), + Project run = model.getOwner(Project.class) + .orElse(null); + + RunResolution resolution = RunResolution.resolve(run, + model.getProperties(), operationCallbacks, logger); if (resolution.isOK()) { result = new ResolutionResult(Outcome.Resolved, resolution, status, logger); From 9240c05e6c5e1675116cd91f6cfe42ce3d194318 Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Wed, 10 Apr 2024 10:16:17 +0200 Subject: [PATCH 2/4] Fixed test case, minor beautifcation --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../test/test/bndmodel/BndModelTest.java | 6 +++--- .../aQute/bnd/build/model/BndEditModel.java | 21 +++++++++++-------- .../editor/workspace/PluginsPart.java | 3 ++- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java b/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java index 24eaad15cf..634a3bdbd0 100644 --- a/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java +++ b/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java @@ -109,11 +109,11 @@ public void testSetBuildPath(@InjectTemporaryDirectory @Test public void testParent() throws Exception { - BndEditModel model = new BndEditModel(); - model.setRunFw("${fw}"); // set changes File f = IO.getFile("testresources/bndmodel/test-01.bndrun"); + BndEditModel model = new BndEditModel(); model.setBndResource(f); - + model.load(); + model.setRunFw("${fw}"); // set changes Processor p = model.getProperties(); assertEquals("a, b, c", p.getProperty(Constants.RUNBUNDLES), "Set in file, refers to macro"); diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java index c6a5fd5c99..988c30e22d 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java @@ -76,9 +76,11 @@ /** * A model for a Bnd file. *

- * The model is an editor on the properties file on which bnd is based on. - * However, in bnd there is always a Processor involved. The Processor links to - * a file and can inherit from a parent Processor. + * The bndedit model maintains a Properties that can be modified/added with + * convenient semantic methods and/or properties can be deleted. The bnd file + * tends to be kept in a Processor, and the processors are kept in a inheritance + * chain. The BndEditModel can provide a Processor that extends the original but + * reflects the changes made in the inheritance model. */ @SuppressWarnings("deprecation") public class BndEditModel { @@ -360,6 +362,7 @@ public ImportPattern error( } + /** * Default constructor */ @@ -1360,11 +1363,6 @@ private boolean hasIncludeResourceHeaderLikeInstruction() { return properties.containsKey(Constants.INCLUDE_RESOURCE); } - @Deprecated - public void setProject(Project project) { - setOwner(project); - } - public Project getProject() { return null; } @@ -1542,7 +1540,7 @@ public void setDirty(boolean isDirty) { } public void load() throws IOException { - loadFrom(owner.getPropertiesFile()); + loadFrom(inputFile); } /** @@ -1631,4 +1629,9 @@ public BndEditModel(Project domain) throws IOException { this(domain.getWorkspace(), domain); } + @Deprecated + public void setProject(Project project) { + setOwner(project); + } + } diff --git a/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java b/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java index 9b1bf8186d..5136a4c3b2 100644 --- a/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java +++ b/bndtools.core/src/bndtools/editor/workspace/PluginsPart.java @@ -315,7 +315,8 @@ void doRemove() { viewer.remove(sel.toArray()); // remove by value - sel.toList() + List list = sel.toList(); + list .forEach(selectedPlugin -> { Set>> entrySet = data.entrySet(); inner: for (Iterator>> iterator = entrySet.iterator(); iterator From b37787f0acf6005707d9e9eab7b170fcafc8744c Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Fri, 19 Apr 2024 12:06:21 +0200 Subject: [PATCH 3/4] =?UTF-8?q?After=20review=20of=20Chris=20R=C3=BCger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../test/test/bndmodel/BndModelTest.java | 22 +++++++++++++++++++ .../aQute/bnd/build/model/BndEditModel.java | 8 +++---- .../src/aQute/bnd/osgi/Processor.java | 2 +- bndtools.core/_plugin.xml | 4 ++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java b/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java index 634a3bdbd0..8414d436ab 100644 --- a/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java +++ b/biz.aQute.bndlib.tests/test/test/bndmodel/BndModelTest.java @@ -1,5 +1,6 @@ package test.bndmodel; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -14,6 +15,7 @@ import org.junit.jupiter.api.Test; import aQute.bnd.build.model.BndEditModel; +import aQute.bnd.build.model.clauses.ExportedPackage; import aQute.bnd.build.model.clauses.VersionedClause; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Processor; @@ -120,4 +122,24 @@ public void testParent() throws Exception { assertEquals("framework", p.getProperty(Constants.RUNFW), "Changes, refers to macro"); } + + /** + * Check if we can get a processor of the model and verify that we get the + * proper properties. + */ + @Test + public void testTypes() throws Exception { + + File f = IO.getFile("testresources/bndmodel/test-01.bndrun"); + BndEditModel model = new BndEditModel(); + model.setBndResource(f); + model.load(); + model.add("Export-Package", "foo;version=1,bar;version=2;xyz=1"); + + List exportedPackages = model.getExportedPackages(); + assertThat(exportedPackages).hasSize(2); + model.add("Export-Package", "foo2;version=2,bar2;version=2;xyz=2"); + exportedPackages = model.getExportedPackages(); + assertThat(exportedPackages).hasSize(4); + } } diff --git a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java index 988c30e22d..a2594e034d 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java +++ b/biz.aQute.bndlib/src/aQute/bnd/build/model/BndEditModel.java @@ -88,7 +88,7 @@ public class BndEditModel { public static final String NEWLINE_LINE_SEPARATOR = "\\n\\\n\t"; public static final String LIST_SEPARATOR = ",\\\n\t"; - private static String[] KNOWN_PROPERTIES = new String[] { + static String[] KNOWN_PROPERTIES = new String[] { Constants.BUNDLE_LICENSE, Constants.BUNDLE_CATEGORY, Constants.BUNDLE_NAME, Constants.BUNDLE_DESCRIPTION, Constants.BUNDLE_COPYRIGHT, Constants.BUNDLE_UPDATELOCATION, Constants.BUNDLE_VENDOR, Constants.BUNDLE_CONTACTADDRESS, Constants.BUNDLE_DOCURL, Constants.BUNDLE_SYMBOLICNAME, @@ -106,8 +106,8 @@ public class BndEditModel { public static final String PROP_WORKSPACE = "_workspace"; public static final String BUNDLE_VERSION_MACRO = "${" + Constants.BUNDLE_VERSION + "}"; - private static final Map> converters = new HashMap<>(); - private static final Map> formatters = new HashMap<>(); + static final Map> converters = new HashMap<>(); + static final Map> formatters = new HashMap<>(); private final static Converter, String> buildPathConverter = new HeaderClauseListConverter<>( new Converter() { @Override @@ -132,7 +132,7 @@ public VersionedClause error( private final static Converter, String> clauseListConverter = new HeaderClauseListConverter<>( new VersionedClauseConverter()); - private final static Converter stringConverter = new NoopConverter<>(); + final static Converter stringConverter = new NoopConverter<>(); private final static Converter includedSourcesConverter = new Converter() { @Override public Boolean convert( diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java index b95f93959e..6add8c69e7 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java @@ -1063,7 +1063,7 @@ public int compareTo(PropertyKey o) { * among the {@code PropertyKey} objects with the same key, only the one * with the lowest floor number is included in the result. * - * @param keys sorted keys defined by {@link #compareTo(PropertyKey)} + * @param keys * @return only unique keys which are visible (lowest floor value) */ public static List findVisible(Collection keys) { diff --git a/bndtools.core/_plugin.xml b/bndtools.core/_plugin.xml index 2889718eb9..4fb49aefb5 100644 --- a/bndtools.core/_plugin.xml +++ b/bndtools.core/_plugin.xml @@ -904,7 +904,7 @@ - + @@ -932,7 +932,7 @@ - + From f37f8574b7e887644c036cea073d19d853072159 Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Fri, 19 Apr 2024 12:17:08 +0200 Subject: [PATCH 4/4] Misunderstood the ${.}, had to be escaped --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java | 6 +++++- bndtools.core/_plugin.xml | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java index 950761be8e..6220a28e33 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java @@ -1404,7 +1404,11 @@ private void copy(Jar jar, String path, File from, Instructions preprocess, Map< if (from.exists()) { Resource resource = new FileResource(from); if (preprocess != null && preprocess.matches(path)) { - resource = new PreprocessResource(this, resource); + Processor tmp = new Processor(this); + addClose(tmp); + tmp.setProperty(".", from.getAbsolutePath() + .replace('\\', '/')); + resource = new PreprocessResource(tmp, resource); } addExtra(resource, extra.get("extra")); if (path.endsWith("/")) diff --git a/bndtools.core/_plugin.xml b/bndtools.core/_plugin.xml index 4fb49aefb5..c44c5e31a1 100644 --- a/bndtools.core/_plugin.xml +++ b/bndtools.core/_plugin.xml @@ -904,7 +904,7 @@ - + @@ -932,7 +932,7 @@ - +