Unable to use includeresources with pattern on path
I would like to create a JAR file using bnd that contains no classes and only some explicitly defined resources that reside in certain paths using the bnd-maven-plugin.
I have been able to get it work for simple filename based patterns like (https://github.com/bndtools/bnd/issues/6794#issuecomment-3250170088)
<configuration>
<includeClassesDir>false</includeClassesDir>
<bnd>
-includeresource: /=src/main/resources/;filter:="*.json"
</bnd>
</configuration>
But it does not seem to work for matching paths, e.g.
-includeresource: /=src/main/resources/;filter:="**/*.json"
-includeresource: /=src/main/resources/;filter:="*/data/*"
-includeresource: /=src/main/resources/;filter:="**/data/**"
If I read the source correctly, then it is not possible to use includeresources with a pattern to match a path:
https://github.com/bndtools/bnd/blob/master/biz.aQute.bndlib/src/aQute/bnd/osgi/Instruction.java#L33-L48
If I read the source correctly, then it is not possible to use
includeresourceswith a pattern to match a path:https://github.com/bndtools/bnd/blob/master/biz.aQute.bndlib/src/aQute/bnd/osgi/Instruction.java#L33-L48
I think you are right @reckart Also the docs state it: https://bnd.bndtools.org/instructions/includeresource.html
The filter: directive is an optional filter on the resources. This uses the same format as the instructions. Only the file name is verified against this instruction.
What do you propose how to go about this? I think we need to keep the current sematics of :filter directive as is to stay backwards compatible. Do you think it should be a new directive which specifies the behavior of :filter?
For example :filtermode:
:filtermode=name(current default):filtermode=path(the new one which goes to the full path
Or would you instead use a completely new directive like e.g. :pathfilter which would consider the whole path?
Considering that dir separators are not valid in regular filenames, I don't think that there it would be a breaking change to perform a proper path matching if the filter expression contains a dir separator (in particular /)?
So you mean something like this (pseudo code)?
if (instruction.contains("/")){
// do pathmatching
}
else{
// do what we do right now in https://github.com/bndtools/bnd/blob/master/biz.aQute.bndlib/src/aQute/bnd/osgi/Instruction.java#L33-L48
}
Right. Maybe I am missing something though...
If we currently have something like filter:=foo.txt, it actually means filter:=**/foo.txt in path semantics.
That means if a filter does not contain a /, it would mean prepending **/ and applying path matching semantics.
If one wanted to express just foo.txt in the top-level folder (currently impossible), it would mean something like /foo.txt or maybe ./foo.txt - which should also be compatible with path-matching semantics.
Do you see any potentially problematic case?
Do you see any potentially problematic case?
I am not completely sure, we would need to try it out I guess.
I am not sure if the current matcher in Instruction.java is really doing ant-style path matching. But I currently assume we would not change the matching behavior of Instruction.java but just use the path instead of the name only, right?
Here is a quick ChatGPTed base for discussion, just to see if we are on the same page.
public static class Filter implements FileFilter {
private final static Pattern DEFAULT_DO_NOT_COPY_P = Pattern.compile(Constants.DEFAULT_DO_NOT_COPY);
private final Instruction instruction;
private final boolean recursive;
private final Pattern doNotCopy;
private final boolean pathMatching;
public Filter(Instruction instruction, boolean recursive, Pattern doNotCopy) {
this.instruction = instruction;
this.recursive = recursive;
this.doNotCopy = doNotCopy;
// pathMatching is true if instruction contains a "/" in its original string form
this.pathMatching = instruction != null && instruction.toString().contains("/");
}
public Filter(Instruction instruction, boolean recursive) {
this(instruction, recursive, DEFAULT_DO_NOT_COPY_P);
}
public boolean isRecursive() {
return recursive;
}
@Override
public boolean accept(File pathname) {
String name = pathname.getName();
if (pathMatching) {
// --- New logic: path-based matching ---
String fullPath = pathname.getPath().replace(File.separatorChar, '/');
if (doNotCopy != null && doNotCopy.matcher(fullPath).matches()) {
return false;
}
if (instruction == null) {
return true;
}
boolean matches = instruction.matches(fullPath) ^ instruction.isNegated();
if (pathname.isDirectory()) {
return recursive && matches;
}
return matches;
} else {
// --- Old logic: name-based matching ---
if (doNotCopy != null && doNotCopy.matcher(name).matches()) {
return false;
}
if (pathname.isDirectory() && isRecursive()) {
return true;
}
if (instruction == null) {
return true;
}
return instruction.matches(name) ^ instruction.isNegated();
}
}
}
Is this what you have in mind?
it would mean something like
/foo.txtor maybe./foo.txt- which should also be compatible with path-matching semantics.
I am not sure if or how the code should handle ./foo.txt or /foo.txt.
Could you maybe create a PR with the code above and maybe add a testcase in /biz.aQute.bndlib.tests/test/IncludeResourceTest.java? since you know exactly what you are expecting.
I don't want to wriggle out of this, but tbh working with the gradle-based build of bnd always gives me a head-ache... I'm really used to working with Maven...
Also, I don't know if there is an ant-style matcher in the bnd code. If I read the documentation correctly, e.g. the @ unroll selector uses a regex. So although I think an ant-styler matcher would be best, maybe a regex would be more consistent with other parts of the bnd implementation...
Also, I don't know if there is an ant-style matcher in the bnd code.
In bnd usually everything is a Glob-Expression. see e.g. https://bnd.bndtools.org/macros/glob.html or https://bnd.bndtools.org/commands/find.html
But I saw that there is FileSet.java which mentions Ant/Gradle in the description
https://github.com/bndtools/bnd/blob/5d699c7550deb6ab65583fe69ef8bc8e7d0225e9/aQute.libg/src/aQute/lib/fileset/FileSet.java#L13-L17
But FileSet is unfortunatelly not used by
https://github.com/bndtools/bnd/blob/5d699c7550deb6ab65583fe69ef8bc8e7d0225e9/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java#L1250-L1254
So one could think about how to change the caller of aQute.bnd.osgi.Builder.resolveFiles(File, FileFilter, boolean, String, Map<String, File>, boolean) in a way that it uses FileSet.
but tbh working with the gradle-based build of bnd always gives me a head-ache... I'm really used to working with Maven...
@reckart I took your comment to give a Maven Tycho build a try: https://github.com/bndtools/bnd/pull/6814 Would that help you?