bndtools / bnd

Bnd/Bndtools. Tooling to build OSGi bundles including Eclipse, Maven, and Gradle plugins.
https://bndtools.org
Other
526 stars 304 forks source link

fix source lookup for bundle classpath lib jars during debugging #6165

Open chrisrueger opened 1 week ago

chrisrueger commented 1 week ago

What problem does it solve?

This PR solves the problem that the source lookup during a debug session did not work when stepping into a method (F5) of a class which was coming from a jar inside the bundle classpath which was included via

-buildpath: \
    foo.bar;version=latest,\
-includeresource: \
    ${repo;foo.bar;latest}; lib:=true

Basically my bundle looks like this:

image

the +library.2.11.0.jar is a non-OSGI dep and because classloading issues we included it directly to have it on the BCP. But for classes from +library.2.11.0.jar the source code is not found during debugging when you step into a method.

then you get this when you "Step into a method" (F5)

image

I found out that the reason was, that those deps / jars in the Bundle Classpath are not considered for source lookup during debugging.

Note: F3 (Open Implementation) works fine and it goes to the correct source file - but that does not help while debugging, because you want to step through the code with F5.

What does the Solution do?

Basically when we have a project at hand (in the loop of the code I touched) we not only add the project itself to the array of ISourceContainers but now also add all bundles of this project's -buildpath to this array.

After that I could successfully F5 into the method of dependencies which are on the BCP via -includeresource: ${repo;bsn;latest}; lib:=true,\ and a corresponding -buildpath entry. Before this was not working.

I did not see a noticable performance hit, although now more bundles are added to that array which are searched. I suspect (but don't know) that on a higher level there is some caching and filtering of duplicates already. e.g. because I noticed that this specific method is only run once.

chrisrueger commented 1 week ago

@pkriens Maybe you have a hint:

-buildpath: \
    foo.bar;version=latest,\
-includeresource: \
    ${repo;foo.bar;latest}; lib:=true

Is there a way I can get get these jar files from the buildpath referenced bz -includeresource ?

Right now I am hacked it by just using all the buildpath entries. But that is too much.

Collection<Container> buildpath = project
    .getBuildpath();
for (Container bp : buildpath) {
    if (TYPE.REPO == bp.getType()) {
        additionalSourceContainers
            .add(new BundleSourceContainer(bp));
    }
}

I would like to filter only those entries which are defined in -includeresource:

Update

I now used BundleSourceContainer which is already used. Even though more bundles are added to the resulting array of that method it seems that results are cached, because my breakpoint in bndtools.launch.sourcelookup.containers.BndrunDirectiveSourceContainer.createSourceContainers() was hit just once during a vm-lifetime - and it was only called hit when my breakpoint in the debug instance (the other eclipse) was stopping at the breakpoint there.

So what do you think?

Also marking @kriegfrj since I noticed you worked on the class before. in #3993 (PR #4011)

pkriens commented 2 days ago

finding the referenced repo entries in other headers is tricky. The macro processing completely bypasses dependency logic. After the macro has done its work, it is a normal file. All repo info is gone.

A way to make this work is to override the ${repo} macro in a temporary Processor subclass.

class RepoCollector extends Processor {
    final Set<BundleId> ids = new LinkedHashSet<>();

    RepoCollector(Processor parent) { super(parent); }

    public String _repo(String[] args) {
               BundleId id = toId(args);
               ids.add(id);
               return // orginal version of repo in Workspace (which should be in the parent chain)
   }
}

If you do this, you might want to make a method in Project, looks useful for other things.

chrisrueger commented 22 hours ago

Thanks @pkriens for the hint. I try to wrap my head around it.

chrisrueger commented 21 hours ago

Thanks @pkriens . Your hint with _repo() gave the initial spark. But unfortunatelly I did not find out where to hook in your RepoCollector Processor suggestion.

So I took a different approach, since I found out _repo() triggeres the ${repo;} macro processing and Project.add() gets called with those results.

This is how the new method Project.getRepoRefs() came to this world.

https://github.com/bndtools/bnd/pull/6165/files#diff-a01878046dba7ceb8f43d338872d8b16e659f050c099b70671419d4b778a9a93R950-R964

This populates Project.repoRefs and is called by the source lookup stuff in bndtools.launch.sourcelookup.containers.BndrunDirectiveSourceContainer.addRepoRefs(Set<ISourceContainer>, Project) which basically gets called when you step into a method with F5 during debugging.

Another way to trigger (and test) this code in BndrunDirectiveSourceContainer is:

Basically runbundles now shows repoRef entries coming from -includeresource which are not there in 7.0.0.