Hi all - continuing to experience difficulty leveraging reuse of the same interface across multiple components, only one of which is provided in any given project. For example, I have the following project structure:
bases
cli
resources
src
tlns
cli
core.clj
deps.edn
components
do-thing-one
resources
src
tlns
shared-interface
core.clj
interface.clj
deps.edn
do-thing-two
resources
src
tlns
shared-interface
core.clj
interface.clj
deps.edn
maybe-depended-upon
resources
src
tlns
maybe-depended-upon
core.clj
interface.clj
deps.edn
projects
do-thing-one-via-cli
deps.edn
do-thing-two-via-cli
deps.edn
deps.edn
• Component maybe-depended-upon defines an interface tlns.maybe-depended-upon and has no other dependencies internal or external.
• Component do-thing-one defines an interface tlns.hared-interface also implemented by component do-thing-two, but has no other dependencies internal or external.
• Component do-thing-two defines the same interface tlns.shared-interface, but with a different implementation that internally depends upon the interface tlns.maybe-depended-upon. Crucially, this dependency is not present in the implementation of do-thing-one.
• Base cli defines its own dedicated ns tlns.cli which only depends internally upon the interface tlns.shared-interface.
• Project do-thing-one-via-cli depends upon base cli and component do-thing-one.
• Project do-thing-two-via-cli depends upon base cli and component do-thing-two.
• In the root deps.edn, there are separate profiles +dt1 and +dt2 that keep the conflicting dependencies separated, per the documentation.
With this setup, however, attempting to run the info command gives me the following error:
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
This is not correct, as only the implementation in project do-thing-two-via-cli actually depends upon maybe-depended-upon; the do-thing-one-via-cli has no such dependencies in its implementation.
What is the recommended way to go about having multiple implementations of the same interface that themselves have distinct dependencies per implementation?In 99 out of 100 cases the interfaces will be identical for both differently implemented components. Is there a way to duplicate an identical interface from component to component without copy-pasting it?
Nothing built-in, no.
Interfaces commonly has a lot of docstrings in real code and it will be cool not to duplicate whole interface. Maybe any un-standart, but still easy(not potemkin-like) ways exists?
I just copy/paste the file in my editor, as a starting point. Multiple implementations are relatively rare - we had at most three, I think, in a 200 brick project.
And then I tend to edit the docstrings to highlight differences in functionality. And most times there is some difference in the code too...
Have you read through https://cljdoc.org/d/polylith/clj-poly/0.2.21/doc/profile ? Does it make sense, or do you have questions?
@seancorfield Yes, I have, but there must still be something I'm failing utterly to grasp.
Will give it a read again.
Do you have :+default in deps.edn? One of your profiles needs to be the default.
And how exactly are you running info? Are you specifying which profile(s) it should use?
I do, yes. And I get the same error regardless of whether I run info alone, or specifying a profile (either +default or one of the two mentioned)
We have an almost identical setup at work with an i18n component and an i18n-preview component, both with an identical ws.i18n.interface and different impl nses that depend on different components, and our preview project depends on i18n-preview and info works fine for us...
OK, then there's almost certainly something I've screwed up somehow. Will keep hammering at it.
For comparison, here are our profiles from the workspace deps.edn:
:+default {:extra-deps {;; by default, we use the real i18n and web server:
poly/i18n {:local/root "components/i18n"}
poly/web-server {:local/root "components/web-server"}}
:extra-paths ["components/i18n/test"
"components/web-server/test"]}
:+preview {:extra-deps {;; or the preview i18n and the real web server:
poly/i18n {:local/root "components/i18n-preview"}
poly/web-server {:local/root "components/web-server"}}
:extra-paths ["components/i18n-preview/test"
"components/web-server/test"]}yup, that is precisely the setup I've got
Do your separate impl nses share the same ns name in each component, or do they differ?
Same ns, but I wouldn't expect that to matter...
Yeah, it didn't in my experiments. Still the same error no matter what I attempt to do
I just deliberately broke my preview i18n component impl into another component -- so there's a dependency on a new i18n-sub component only in i18n-preview which is under that +preview alias -- and info only warns that the preview project is missing that dep (correct), and when I add i18n-sub to just that project then info is happy.
Are you sure your two project deps.edn really have the correct do-thing-<nnn> deps? And none of your bases or components have any components in their deps.edn?
I'm going to write up a nonsensitive example to see if I can reproduce and push to public GH.
Everything looks to be correct as asked above.
no bases/components in base/component deps.edn
and the projects are correctly referring to the correct do-thing-<n> deps.
I'll be interested to see how your setup is different to ours, and to the user profile example in the docs...
@seancorfield Here's a repo showing the issue: https://github.com/awebneck/polylith-shared-interface-example
And logs of some executions in the poly console:
bare info shows the error
shared-int-example$ info
stable since: 7be5074
projects: 3 interfaces: 2
bases: 1 components: 3
active profiles: default
project alias status dev dt2
------------------------------------- --------
do-thing-one-via-cli * dt1 --- --- --
do-thing-two-via-cli * dt2 --- --- --
development + dev s-- s-- --
interface brick dt1 dt2 dev dt2
------------------------------------------ -------- --------
maybe-depended-upon maybe-depended-upon * --- stx st- --
shared-interface do-thing-one * stx --- st- --
shared-interface do-thing-two * --- stx --- st
- cli * stx stx st- --
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
info + does not give the error
shared-int-example$ info +
stable since: 7be5074
projects: 3 interfaces: 2
bases: 1 components: 3
project alias status dev default dt2
------------------------------------- -----------------
do-thing-one-via-cli * dt1 --- --- -- --
do-thing-two-via-cli * dt2 --- --- -- --
development + dev s-- s-- -- --
interface brick dt1 dt2 dev default dt2
------------------------------------------ -------- -----------------
maybe-depended-upon maybe-depended-upon * --- stx st- -- --
shared-interface do-thing-one * stx --- --- st --
shared-interface do-thing-two * --- stx --- -- st
- cli * stx stx st- -- --
info +default does show the error
shared-int-example$ info +default
stable since: 7be5074
projects: 3 interfaces: 2
bases: 1 components: 3
active profiles: default
project alias status dev dt2
------------------------------------- --------
do-thing-one-via-cli * dt1 --- --- --
do-thing-two-via-cli * dt2 --- --- --
development + dev s-- s-- --
interface brick dt1 dt2 dev dt2
------------------------------------------ -------- --------
maybe-depended-upon maybe-depended-upon * --- stx st- --
shared-interface do-thing-one * stx --- st- --
shared-interface do-thing-two * --- stx --- st
- cli * stx stx st- --
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
as does info +dt2 (the other profile)
shared-int-example$ info +dt2
stable since: 7be5074
projects: 3 interfaces: 2
bases: 1 components: 3
active profiles: dt2
project alias status dev default
------------------------------------- ------------
do-thing-one-via-cli * dt1 --- --- --
do-thing-two-via-cli * dt2 --- --- --
development + dev s-- s-- --
interface brick dt1 dt2 dev default
------------------------------------------ -------- ------------
maybe-depended-upon maybe-depended-upon * --- stx st- --
shared-interface do-thing-one * stx --- --- st
shared-interface do-thing-two * --- stx st- --
- cli * stx stx st- --
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
test I cannot get to work under any invocation:
shared-int-example$ test
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
shared-int-example$ test +
Error 107: Missing components in the development project for these interfaces: shared-interface
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
shared-int-example$ test +default
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
shared-int-example$ test +dt2
Error 107: Missing components in the do-thing-one-via-cli project for these interfaces: maybe-depended-upon
I see the same behavior locally with that repo... but I can't see anything obviously wrong right now...
😞 Welp, thanks for looking just the same - the help is appreciated regardless.
I figured it out @awebneck! You're using an old version of Polylith. Update it to 0.2.21 and it will work (modulo a couple of incorrect names in the files).
That's why I couldn't see anything wrong -- there isn't anything wrong, but you're hitting a bug in Polylith 0.2.19 that was fixed in 0.2.20.
Your maybe-depended-upon component has `def` instead of `defn` in both interface and core. You do-thing-* tests both refer to `.do-thing-*.` in the required ns instead of `.shared-interface.`. But with those two fixes, all the tests pass on 0.2.21.
@seancorfield aw, I knew it was going to be something doofy. Thank you!