cursive icon indicating copy to clipboard operation
cursive copied to clipboard

Support adding brick as :extra-deps for a Polylith workspace in development

Open tengstrand opened this issue 3 years ago • 17 comments

The Polylith architecture comes with the poly tool written for Clojure that is based on tools.deps.

I've been working on issue-66 for a while in the issue-66 branch to support defining bricks as :extra-deps instead of :extra-paths, see deps.edn.

This works fine in e.g. Emacs/Cider and VSCode/Calva but not in IDEA/Cursive. What happens is that the src directories are not recognised by Cursive and will therefore not show up as green.

Instead of this: brick-defined-using-extra-paths

...we get this: brick-defined-using-extra-deps

The good part is that the code is recognised by the REPL, but unfortunately not by the IDE.

The workaround is to add them as :extra-paths, but it would be much better if they could be added as :extra-deps instead:

  • It would be consistent with how bricks are added to other projects (development is a special kind of project).
  • Instead of defining two paths, src and resources, we can define one dependency per brick, resulting in less code.
  • If a resources directory is added or removed from a brick, the change will automatically be detected by tools.deps.

Some teams will probably start to use the :extra-deps way of defining bricks in development, which unfortunately will stop people that joins the team from using Cursive. With better support in Cursive, this could be avoided.

Regards, Joakim Tengstrand

tengstrand avatar May 20 '21 12:05 tengstrand

I did try to work around this by re-importing the entire workspace into idea and marking all local/root refs as modules. That did solve the folder mark problem and did not break the repl classpath: https://github.com/polyfy/polylith/issues/127

However, as @tengstrand & co kindly checked for me, it does not solve the problem of symbol resolution in case a brick references another brick's interface. Due to how polylith is set up, these inter-brick dependencies are not listed as relative local/root deps in the bricks' own deps.edn files - this is how polylith achieves swappability of implementations. Multiple bricks might have the same interface signature (via some code duplication) and it's decided at the project (or development) level which brick to reference as a dependency to satisfy a requirement for an interface.

I created a repro case at https://github.com/imrekoszo/cursive-polylith

With the root deps.edn looking like

                  :extra-deps {org.clojure/clojure {:mvn/version "1.10.3"}
                               org.clojure/tools.deps.alpha {:mvn/version "0.12.1003"}
                               poly/user {:local/root "components/user"}
                               poly/foo {:local/root "components/foo"}}}

            :test {:extra-paths ["components/user/test"
                                 "components/foo/test"]}

And no cross-brick references, se.example.foo.interface cannot be navigated to from the following file:

(ns se.example.user.core
  (:require [se.example.foo.interface :as foo]))

imrekoszo avatar Sep 08 '21 14:09 imrekoszo

I finally got some time to look at this, sorry for the delay. Thanks for the repro case @imrekoszo, that's very helpful.

So there are two problems here. One is that components added to the root project deps.edn are not added as modules, which means that their source roots are not registered in Cursive. A workaround for this problem is to add the modules manually as Imre did, which isn't terrible. I considered automatically adding :local/root deps as modules but there are cases where you don't want that (Cursive itself has one). I could potentially add some easier way to add them in the Deps toolwindow to facilitate that.

The second problem is that with this setup, there are two modules which share the same source root. In Imre's example, both the root deps.edn and the component ones share the test classpath, e.g. components/foo/test is shared by both the foo component and the root application. IntelliJ will not allow that, a particular source root has to be associated with just one module. Is it essential that that folder be shared between the two?

cursive-ide avatar Oct 28 '21 02:10 cursive-ide

Hey @cursive-ide, thanks for picking this up. I chatted to @tengstrand on the clojurians slack about this, here's what I gathered:

As for the first problem you mention, while a convenience feature would be nice, as long as reimporting manually works, that shouldn't be a deal-breaker.

For the second problem, it appears those test paths can actually be dropped from the top-level deps.edn - it was only added there as an attempt to make it more Cursive-friendly. I went ahead and dropped those paths from the repro case in my repo.

The problem that remains after these is that go to definition does not work between bricks:

Screenshot 2021-11-02 at 18 33 14

I'm assuming the reason why this (orange arrow) doesn't currently work in Cursive is because in polylith there must be no reference to the foo brick from the user brick (red arrow).

polylith quick info: components and bases are in the category of bricks and there must be no direct deps.edn references between bricks. projects on the other hand act as the composing layer and will reference (usually multiple) bricks.

In the dev alias (which is a special, development-type 'project') that I have selected, there are still references to both of those bricks, meaning they will both be on the classpath if I run a repl with the Idea classpath so I guess the missing connection can be figured out somehow. ~This should ideally work transitively, so if I have an alias selected which :local/root references a project, and that project :local/root references some bricks, go to definition should work between those bricks too.~

Edit: it appears the transitive case isn't needed for polylith.

imrekoszo avatar Nov 02 '21 18:11 imrekoszo

Hi! Thank you for picking up this issue! I’m one of the Polylith team members and I’ll try to shed light on what is working and what is not working in Cursive for Polylith projects. For that, I’ll start by giving a short overview of what Polylith does.

Polylith has these two important concepts, component and base (they are referred bricks collectively). They are the building blocks with different purposes, bases being responsible of exposing an external API and component being small Lego-like bricks implementing the logic and exposing and internal functional API. Each base and component has their own deps.edn file, defining their source, resource, and test folders (with :test alias) as well as their external library dependencies. One of the most important thing in Polylith is, bricks do not define internal dependencies in their deps.edn, they are picked up when you put them together in a project and this enables Polylith users to interchange components with different implementations.

Polylith has a special project, which is called development project, that has a deps.edn file at the root of the project. Here we define our local development project and include all the components and bases in it so that we can reach to all code in the repository, even though they might be split into different projects in deployed versions.

What is working with Cursive:

If we have the following deps.edn structure, Cursive works:

{:aliases {:dev  {:extra-paths ["components/comp-a/src"
                                "components/comp-a/resources"
                                "components/comp-b/src"
                                "components/comp-b/resources"
                                "components/base-a/src"
                                "components/base-b/resources"]

                  :extra-deps  {some.external/dependency-of-comp-a {:mvn/version "1.0.0"}
                                some.external/dependency-of-comp-b {:mvn/version "1.0.0"}
                                some.external/dependency-of-base-a {:mvn/version "1.0.0"}
                                some.external/dependency-of-base-b {:mvn/version "1.0.0"}}}

           :test {:extra-paths ["components/comp-a/test"
                                "components/comp-b/test"
                                "components/base-a/test"
                                "components/base-b/test"]

                  :extra-deps  {some.external/test-dependency-of-comp-a {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-comp-b {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-base-a {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-base-b {:mvn/version "1.0.0"}}}}}

This is a very simple example and you can see a realworld example here.

What does not work in Cursive and works in other IDEs

If we have the following deps.edn structure, Cursive does not work by default. Even if we import each component and base as a module, it still cannot resolve namespaces from classpath for the code navigation and other features of Cursive to work:

{:aliases {:dev  {:extra-deps  {poly/comp-a {:local/root "components/comp-a"}
                                poly/comp-b {:local/root "components/comp-b"}
                                poly/base-a {:local/root "bases/base-a"}
                                poly/base-b {:local/root "bases/base-b"}}}

           :test {:extra-paths ["components/comp-a/test"
                                "components/comp-b/test"
                                "components/base-a/test"
                                "components/base-b/test"]

                  :extra-deps  {some.external/test-dependency-of-comp-a {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-comp-b {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-base-a {:mvn/version "1.0.0"}
                                some.external/test-dependency-of-base-b {:mvn/version "1.0.0"}}}}}

Since :local/root syntax does not allow depending on an alias in the target deps.edn, we still need to duplicate test paths and extra dependencies for the tests from individual components and bases.

What would be ideal 😎

It would be the best If Cursive can understand that everything starting with poly/ in the extra-deps is a Polylith component or base, and resolve their src, resource, and test directories and src and test dependencies. Then, we wouldn't need to duplicate anything and have both sources and tests in our REPL. In a Polylith workspace, components and bases always have their tests under :test alias, since thats where the poly CLI looks for.

{:aliases {:dev  {:extra-deps  {poly/comp-a {:local/root "components/comp-a"}
                                poly/comp-b {:local/root "components/comp-b"}
                                poly/base-a {:local/root "bases/base-a"}
                                poly/base-b {:local/root "bases/base-b"}}}}}

Let me know if you need any further information from us. You can reach out to me or the rest of the team at #polylith channel in Clojurians Slack.

furkan3ayraktar avatar Nov 03 '21 08:11 furkan3ayraktar

Thanks for the examples @imrekoszo and @furkan3ayraktar. I've looked into this further, and I think I have a better idea of how Polylith works now. I'm still not sure how best to support it, though. Thinking through what I would have to do to support this, it's something like:

  1. User clicks on something, or Cursive tries to resolve it in the editor.
  2. Cursive checks to see it looks like the reference is contained within a brick.
  3. If it is, then Cursive should construct a resolve scope for the project, probably using a union of the development project scope (for source references across bricks) and the original brick's scope (to get the dependencies of the brick itself). Or maybe just the development project's scope for everything? I'm not sure about this.

There are a couple of assumptions here. One is that there's either: 1) a 1-1 correspondence between an IntelliJ project and a Polylith project, or: 2) that bricks are in a consistent place relative to the development project so that I can find the development project from them. I'm guessing that 1) is probably not a good assumption to make, since these projects might be contained within a larger monorepo. I guess the question is: how can Cursive determine that a deps project is a Polylith development project, and modify its resolution accordingly?

I spent some time looking at the Realworld project example, and there are still cases there where the same source root is present in multiple modules, e.g. the test roots are present in both the root development project and in the components themselves. I'm fairly sure this used to be a hard error in IntelliJ but it's not complaining now, perhaps that has changed in recent versions. I'll check that with JetBrains. If my memory is correct then there's nothing I can do about that, unfortunately.

cursive-ide avatar Nov 16 '21 03:11 cursive-ide

Hi @cursive-ide! Thanks for looking into this, I’ll try to elaborate on the topics that you mentioned.

I can start with the project structure. Polylith has a strict directory structure. This is important for our own poly CLI to work properly. The structure is as following:

example              # workspace dir
├── .git             # git repository dir
├── bases            # bases dir
│   ├── base-1       # base dir
│   │   ├─ src       # base sources
│   │   ├─ resources # base resources
│   │   ├─ test      # base tests (use-case: unit tests)
│   │   └─ deps.edn  # Specifies src, resources, and test paths. Specifies only external dependencies. Always has a :test alias 
│   └── base-2
│   │   ├─ src
│   │   ├─ resources
│   │   ├─ test
│   │   └─ deps.edn
│   ...
│   
├── components       # components dir
│   ├── comp-1       # component dir
│   │   ├─ src       # component sources
│   │   ├─ resources # component resources
│   │   ├─ test      # component tests (use-case: unit tests)
│   │   └─ deps.edn  # Specifies src, resources, and test paths. Specifies only external dependencies. Always has a :test alias 
│   └── comp-2
│   │   ├─ src
│   │   ├─ resources
│   │   ├─ test
│   │   └─ deps.edn
│   ...
│   
├── development
│   └── src          # development specific code (only used during development, within REPL)
├── projects         # projects dir
│   ├── proj-1       # project dir
│   │   ├─ src       # project specific source dir (not recommended to have project specific sources)
│   │   ├─ resources # project specific resources dir (optional)
│   │   ├─ test      # project specific test dir (optional) (use-case: integration tests)
│   │   └─ deps.edn  # Specifies source paths, resource paths, internal brick dependencies (:local/root) and any extra external dependencies (optional). Optionally has a :test alias to include bricks used only during tests but not included in the deployable artifact. 
│   └── proj-2
│   │  ├─ src
│   │  ├─ resources
│   │  ├─ test
│   │  └─ deps.edn
│   ...
│
├── deps.edn         # development config file
└── workspace.edn    # workspace config file (an indication that you are at the root of a Polylith workspace)

The deps.edn at the root directory is for the development project and it is a valid project configuration for a developer to start a REPL with the correct classpath. All brick and external dependencies (if needed) under :dev alias and all test paths and external dependencies under :test alias. There could also be extra profiles defined by other aliases, this means not all components needs to be in the classpath (and REPL), but ideally all should be navigable from the IDE.

The reason we need to include test sources again in the root deps.edn is that tools.deps does not allow to refer to an alias (:test in this case) via :local/root. If we don’t do this, test paths and dependencies won’t be in the REPL. However, we need test sources and dependencies in the bricks deps.edn for the poly CLI to work with incremental tests.

I do not have any experience with Intellij IDE internals, so this might be a bad idea, however I’m going to say it anyway 😂. What I think is, the bricks should not be modules, since they are not independent projects. Cursive could treat them as places where source and test paths live, and resolve them and their dependencies from the development projects deps.edn.

I think assumption 1 is good enough, since that’s how Polylith works in other IDEs and I don’t see the benefit of having two Polylith workspaces in a single monorepo, it’s better to combine them to get the best out of it. When it comes to assumption 2, bricks are always in a consistent place relative to the development projects deps.edn. It is a flat structure under components and bases directories from the root directory of the project.

furkan3ayraktar avatar Nov 16 '21 11:11 furkan3ayraktar

@furkan3ayraktar I wouldn't completely rule out Colin's concerns wrt assumption 1 - workflows differ.

However, Cursive might be able to use workspace.edn to find polylith roots? Is that always present in the polylith root? Is there a schema/spec available for its contents, should Cursive want to also check that to differentiate from some other kind of workspace.edn?

imrekoszo avatar Nov 16 '21 15:11 imrekoszo

Yes, for reference the largest lein project I'm aware of had > 90 project.clj files. Someone somewhere is going to want to put two Polylith apps in one IntelliJ project.

cursive-ide avatar Nov 16 '21 20:11 cursive-ide

@cursive-ide is there any update on this? Could it be a possible solution to treat active :local/root deps, which resolve to paths within the intellij project, source paths as opposed to library paths?

The following examples use

IntelliJ IDEA 2022.2 EAP (Community Edition)
Build #IC-222.2680.4, built on May 25, 2022
    com.cursiveclojure.cursive (1.12.4-eap2-2022.2)

This is the current situation when one only uses deps - those library paths could be source paths instead: cursive-only-deps

The following is the half-arsed workaround I use now on my poly workspaces. I reference poly bricks as both deps (to pull in their transitive deps) and paths (to satisfy Cursive). It does result in those paths still being marked somewhere half way between source and lib and so some inspections, like "namespace is not in the correct location" not work. cursive-deps-and-paths

And the following is how it looks with the poly-recommended workaround. This has the downside of potentially having to specify multiple (src, resources etc) paths per brick and not automatically pulling in deps of those bricks. cursive-all-paths

@furkan3ayraktar reading back on your comments I would actually discourage using poly/brick-name for internal naming (and adding special cases to Cursive based on that). This can cause clashes when git-dep-referencing a poly project from another poly workspace.

@cursive-ide I've updated my repro repo with the above examples.

imrekoszo avatar May 30 '22 10:05 imrekoszo

@imrekoszo No update sorry, I've been busy with other things. I'll try to take another look at this and think about the source path idea. At first glance I'm reluctant, because it makes the inter-module dependencies even weirder than they already are with Deps, but I haven't really thought about it in detail.

cursive-ide avatar May 31 '22 10:05 cursive-ide

@imrekoszo yes, I think I wrote above comment before we discussed the potential issue with using poly/ as a default identifier for Polylith projects. However, we can come up with a standard way, if it would make it easy for Cursive to resolve Polylith bricks correctly. An idea could be something like top-ns.poly/ to minimise conflicts.

furkan3ayraktar avatar May 31 '22 13:05 furkan3ayraktar

make it easy for Cursive to resolve Polylith bricks correctly

@furkan3ayraktar I would prefer a solution that is not Polylith-specific and I believe Colin is on the same opinion. I think there are improvements that could be made in general to how Cursive handles local/root deps and I think if that is sorted out, this issue will also be resolved.

I'm just working on a more general repro case for my suggestion above.

imrekoszo avatar May 31 '22 13:05 imrekoszo

Thanks @cursive-ide.

To reiterate, the suggestion treat paths of :local/root deps that resolve to within the intellij project is not polylith-specific. I created another repro repo to demonstrate what I think isn't really nice when working with local/root deps in Cursive: https://github.com/imrekoszo/cursive-local-root - note that this is not a polylith workspace.

In the example project I have 3 deps projects, one app and two libs, following the official guide up to https://clojure.org/guides/deps_and_cli#_using_local_libraries and adding a bit on top. The app and one lib are added as modules to the IntelliJ project, I left one as a non-module to demo that case as well (as for polylith we don't normally do this).

cursive-local-root

As shown in the screenshot, both libs are marked as library root, resulting in the following:

  • Namespace name does not correspond to filesystem hierarchy error to not show up (middle editor row)
  • File not under a source root header for namespaces in the lib not loaded as a module

I think one of the purposes of :local/root deps (pointing to a folder with a deps.edn) is that we have direct access to sources that we can modify and load into the application.

If the :local/root points to a location within the IntelliJ project, I really don't see a reason not to treat those paths (the ones that the referenced deps.edn has in its top-level :deps key) as proper sources. I would think this should apply for both when the referenced deps.edn is loaded as a module or not (which would be the poly case).

If it points outside the IntelliJ project, that's a different question and I don't have arguments either for or against.

@cursive-ide @furkan3ayraktar what do you think?

imrekoszo avatar May 31 '22 14:05 imrekoszo

I agree with @imrekoszo. :local/root dependencies end up in the classpath as source files, and it makes sense to me to treat them as source files. I don't think it matters if it's in the Intellij project or not. However, I do not know if this makes things too complicated, so it's up to @cursive-ide to choose if the sources outside of the project should be included or not.

One think that could be valuable for Polylith users: neither the Clojure CLI nor other IDEs include the test files when other projects are included as a :local/root dependency (since tests are defined in an alias and you cannot depend on an alias with :local/root). It would be nice to have a special Polylith support, so that, Cursive can detect and include the test files as well in the development project's Classpath automatically for Polylith projects when we start a REPL session (the ideal scenario I mentioned on my comment above).

furkan3ayraktar avatar May 31 '22 16:05 furkan3ayraktar

@furkan3ayraktar thanks for reviewing this.

I would caution against the extra test-paths support however. That is something tools.deps itself doesn't do, and the current issue stems from the fact that Cursive does something differently from tools.deps. My opinion is that editors should try to match what tools.deps does so just by configuring your deps.edns you'll get the same behavior everywhere. Extras should be - and to a good extent already are - provided by the poly tool which I think is the perfect location for polylith-specific additions.

imrekoszo avatar May 31 '22 17:05 imrekoszo

@cursive-ide I created yet another repro case. It still isn't polylith but somewhat closer to it. Subprojects don't reference each other on a deps.edn level, only in code. All subprojects are added as local/root deps in the top-level deps.edn.

https://github.com/imrekoszo/cursive-local-root-2

image

imrekoszo avatar Aug 08 '22 11:08 imrekoszo

Ok, I've spent some more time looking at this. Many thanks again to @imrekoszo for the great repro cases, they've been very helpful in terms of clarifying my understanding of the problems.

There are 3 main problems, I think:

  1. Cursive complains about files not being under a source root when a file is in a :local/root dependency which is not added as a module in IntelliJ.
  2. IntelliJ puts files in reader mode when they're in library roots, even if they're also in source roots. I think this must be a recent platform change. This is what causes the lack of incorrect namespace warnings in :local/root deps which are added as modules to IntelliJ.
  3. Find Usages has various failure cases due to the way in which Polylith treats dependencies.

Cases 1 and 2 are quite easy to fix, and are basically just generic bugs in the way Cursive supports Deps. The one case which might be tricky to solve is git deps, which will also use source roots on the local hard drive, but they're not :local/root deps that you're likely to want to edit.

Case 3 is tricky. The bricks have dependencies which are not explicitly expressed in the code anywhere, and it's up to the developer to ensure that the code has all its dependencies fulfilled at run time. Bricks are not valid code on their own, which is an unusual code structure. What this means is that if you're searching for usages of a particular program element, it could literally be anywhere in your project.

Rather than trying to add a bunch of Polylith-specific code to handle this case, I think the best option would be to have a per-project config flag, which basically says to treat the whole project as one big classpath. So, for navigation, find usages etc, basically just tell Cursive that elements could be located anywhere and Cursive must search the whole project for them. This might cause some strange effects, but I can't think of any off the top of my head. This might even be useful for other types of projects doing funky things with the classpath, I'm not sure.

One thing I could do is try to detect at project open if a project is a Polylith project (based on the presence of a workspace.edn or something) and prompt the user via a notification to turn that flag on for that project.

cursive-ide avatar Aug 12 '22 10:08 cursive-ide

Hi Colin! I suggest that the development project + the default profile (if used) should be used as default within the workspace, and that Cursive only see the bricks specified in that project and profile + their libraries + libraries specified in the development project itself (I use the Polylith definition of a project here). This is the way most people will use Polylith, working in a single REPL from the development project. Being able to switch to another profile would be useful also (as a way to "simulate" different production environments). Being able to switch to other projects than development is less important, but could be good to have. Remember that profiles are only used by the development project, not the projects under the projects directory.

tengstrand avatar Dec 08 '22 07:12 tengstrand

@cursive-ide Hi Colin! Are there any plans to incorporate the :extra-deps (i.e. :local/root deps) fix into Cursive soon? It's quite annoying that now one have to use :extra-paths instead + duplicate all the components' library deps within the :dev alias as a workaround specifically for Cursive. It ruins an otherwise perfectly good Polylith-stuffed dish. =)

Having a per-project config flag, which tells IDE to treat the whole project as one big classpath, also sounds good. While adding a Polylith project autodetection and prompting the user to turn that flag on, imho, is a cherry on top. Overall, it would be great to have Navigate to Declaration and Find Usages working for Polylith projects.

P.S. I think it's good to note, that in the comment above Joakim is talking about the deps.edn located in the root directory (a.k.a. the development Polylith project). It is this deps.edn that requires Cursive-specific manipulations that I've mentioned above. And the default profile Joakim mentions is merely a Polylith-specific :+default alias.

marksto avatar Feb 01 '23 08:02 marksto

@marksto I have a plan to fix this, but it's a very large change which will affect all deps users, so I'm trying to figure out the best time to make it. It will probably be the next major release of Cursive, it's not something I want to ship in a point release.

cursive-ide avatar Feb 26 '23 21:02 cursive-ide

Hi! Just want to draw your attention to this discussion about how to best support ClojureScript in the poly tool @cursive-ide.

tengstrand avatar Apr 11 '23 09:04 tengstrand

Ok, a fix for this has finally been released in 1.13.0-eap2. It's a massive change in the deps support, which the Polylith support mostly just falls out of. All the issues reported by @imrekoszo in his test repos and other Github issues are now fixed. When using Polylith, users will need to check the Preferences | Languages & Frameworks | Clojure | Project Specific Options | Resolve over whole project option, which will fix the project resolution issue. In the end I went for simply resolving over the whole project, which has the advantages of a) simplicity, both in implementation and ease of understanding for end users, and b) not being Polylith-specific. The Polylith RealWorld example repo syncs correctly now, and as far as I can tell behaves sanely.

As I say, this is a huge change so things may have broken. I'm also interested to know if there are things that I've missed or that don't work correctly - I don't use Polylith myself so this is hard for me to evaluate.

Many thanks again to @imrekoszo for the repro repos, they were invaluable in ensuring that everything works as expected.

cursive-ide avatar Jun 30 '23 01:06 cursive-ide

Great news Colin, thank you so much! Can't wait to try it :)

imrekoszo avatar Jun 30 '23 15:06 imrekoszo

Hi Colin!

I have now verified this with:

  • IntelliJ IDEA 2023.2 EAP (Ultimate Edition), Build #IU-232.8453.116, built on June 29, 2023
  • 1.13.0-eap3-2023.2

...and it works flawless!

Thank you so much Colin, @imrekoszo, and @furkan3ayraktar for all the great work on this one!

/Joakim

tengstrand avatar Jul 01 '23 04:07 tengstrand

@tengstrand Glad it worked well! There are still some kinks in the implementation, but they should hopefully get stabilised over the next week or so.

cursive-ide avatar Jul 02 '23 06:07 cursive-ide

Hi again!

I have tested some more and when using profiles the navigation could be improved so that the tool can navigate to the correct component (the one that is included by the selected aliases).

If I understand correctly, this is something that works in e.g. Calva today, and it would be nice if it could work in Cursive too!

So if we for example include the system interface: image

And try to navigate to the system component via its interface, Cursive can't figure out which implementation of that interface it should use (the system or system-x component in this case): image

These two components live under the components directory and use the same namespace (the same interface in Polylith terms): image

The poly tool forces us to select either the :+default alias (the default profile in Polylith terms) or the :+plain alias when executing commands, and doesn't allow us to use both at the same time (it detects that polylith.clj.core.system is included twice). Here the plain profile is selected: image

In the example above, we have the plain profile selected (the :+plain alias) which holds the source code for the polylith.clj.core.system.interface namespace in the system component: https://github.com/polyfy/polylith/blob/393145cc39aaa4c2e9f8bfc04957988b860d076f/deps.edn#L95-L96

Now when we know that polylith.clj.core.system.interface is only included once, the tool should be able to navigate to the correct component.

It may be good to know that the naming convention for profile aliases is to begin with a +.

tengstrand avatar Jul 03 '23 08:07 tengstrand

I found one more problem.

When I run the polylith.clj.core.creator.workspace-test test from within the IDE, it doesn't recognise polylith.clj.core.test-helper.interface when I include test-helper using :extra-deps, but it works when I included it using :extra-paths, see this commit.

tengstrand avatar Jul 03 '23 17:07 tengstrand

I had a look at the multiple references problem. I think there's a bit of a tradeoff here, this probably will work in Calva because Calva uses REPL introspection for its navigation, and presumably you only have one copy loaded into the REPL at any one time. However, that also comes at the cost of not being able to navigate to the other one, which I can imagine you might want to do - if you're working on one and you change the interface, for example, you're going to want to change the other too, and you won't be able to using a REPL-based system unless you restart your REPL.

That said, this should work better in Cursive, and I'm not sure why it doesn't. Here, I have +plain selected and you can see that only one of these has a module created, and the other doesn't even have a source root, but IntelliJ still finds the usage:

Screenshot 2023-07-05 at 15 57 17

I'll see if I can figure that out. If that were not the case, then you could switch from one to the other in the deps tool window by just selecting the right alias and refreshing, which seems pretty light-touch. I'll try to look at this at some point, but I'm super busy right now and this seems like a nice-to-have at best. I'll see what I can do.

cursive-ide avatar Jul 05 '23 04:07 cursive-ide

I looked at the test problem too, and using the following run config the test works for me with test-helper pulled in using :extra-deps: Screenshot 2023-07-05 at 16 07 46

cursive-ide avatar Jul 05 '23 04:07 cursive-ide

I found the problem. I had to select polylith as module, and now the polylith.clj.core.creator.workspace-test test also works with these settings (Run with IntelliJ project classpath) :

image

There is still one problem left. Every time I run the tests by clicking on the two green arrows at the top left corner: image

...a new configuration is created, where module is set to creator instead of keeping it as polylith: image

It would be good if the tests were always executed using the polylith module (this worked in earlier versions of Cursive).

tengstrand avatar Jul 05 '23 08:07 tengstrand