polylith

https://polylith.gitbook.io/ and https://github.com/polyfy/polylith
seancorfield 2021-03-29T01:07:28.215500Z

I have brick tests generating and running correctly now but when I try to run the project tests, I get a weird pathing error on the bases/components:

(! 762)-> clojure -X:new :template polylith :name seancorfield/polyex
Generating a project called polyex based on the 'polylith' template.
(! 763)-> (cd polyex/; clojure -M:deps:poly test :all :dev)
Projects to run tests from: development, polyex

Running tests from the development project, including 2 bricks and 1 project: greeter, cli, polyex

Testing seancorfield.polyex.cli.main-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Test results: 1 passes, 0 failures, 0 errors.

Testing seancorfield.polyex.greeter.interface-test

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.

Test results: 2 passes, 0 failures, 0 errors.
Couldn't resolve libraries for the polyex project: clojure.lang.ExceptionInfo: Manifest type not detected when finding deps for net.clojars.seancorfield/component-greeter in coordinate #:local{:root "/Developer/workspace/components/greeter"} {:lib net.clojars.seancorfield/component-greeter, :coord #:local{:root "/Developer/workspace/components/greeter"}}
Manifest type not detected when finding deps for net.clojars.seancorfield/component-greeter in coordinate #:local{:root "/Developer/workspace/components/greeter"}
My projects/polyex/deps.edn file:
{:paths [] ; no src or resources

 :deps {org.clojure/clojure {:mvn/version "1.10.1"}
        net.clojars.seancorfield/component-greeter {:local/root "../../components/greeter"}
        net.clojars.seancorfield/base-cli {:local/root "../../bases/cli"}}

 :aliases {:test {:extra-paths ["test"]
                  :extra-deps {org.clojure/test.check {:mvn/version "1.1.0"}}}

           :uberjar {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.206"}}
                     :exec-fn hf.depstar/uberjar
                     :exec-args {:jar polyex.jar
                                 :aot true
                                 :main-class seancorfield.polyex.cli.main}}}}
Note that I can build the project just fine, so the :deps work when I’m in the project:
(! 767)-> (cd polyex/projects/polyex/; clojure -X:uberjar)
[main] INFO hf.depstar.uberjar - Compiling seancorfield.polyex.cli.main ...
[main] INFO hf.depstar.uberjar - Building uber jar: polyex.jar
[main] INFO hf.depstar.uberjar - Processing pom.xml for {net.clojars.seancorfield/polyex {:mvn/version "0.1.0-SNAPSHOT"}}
and that runs just fine too.

seancorfield 2021-03-29T01:08:28.216300Z

(I’ll take a look at the poly source on the issue-66 branch to see if I can debug this maybe later tonight or tomorrow)

tengstrand 2021-03-29T04:25:42.217200Z

Yes, we also think that depstarsolves the problem in a better way, so we plan to update the examples to use that instead!

1
tengstrand 2021-03-29T04:28:01.217500Z

Sounds great!

seancorfield 2021-03-29T04:32:07.218900Z

If you want to try the wip version: {:git/url "<https://github.com/seancorfield/clj-new>" :sha "5a63e5b1786cb1dda28eb00b79f5c8ff91f277b3"}

seancorfield 2021-03-29T04:34:26.220100Z

clojure -Sdeps '{:deps {seancorfield/clj-new {:git/url "<https://github.com/seancorfield/clj-new>" :sha "5a63e5b1786cb1dda28eb00b79f5c8ff91f277b3"}}}' -X clj-new/create :template polylith :name seancorfield/polyex

tengstrand 2021-03-29T04:36:31.221900Z

Okay, I will check it out and see if I can reproduce the problem.

seancorfield 2021-03-29T04:40:12.222100Z

Hopefully these three commands will repro for you:

$  clojure -Sdeps '{:deps {seancorfield/clj-new {:git/url "<https://github.com/seancorfield/clj-new>" :sha "5a63e5b1786cb1dda28eb00b79f5c8ff91f277b3"}}}' -X clj-new/create :template polylith :name seancorfield/polyex
 $  cd polyex/
 $  clojure -M:poly test :all :dev 

tengstrand 2021-03-29T04:42:46.222300Z

Yes, I got the same error. Will have a look.

tengstrand 2021-03-29T05:15:03.222500Z

Found the problem @seancorfield. You should remove the dependency to the greeter component in bases/cli/deps.edn:

{:paths ["src" "resources"]

 :deps {}

 :aliases {:test {:extra-paths ["test"]
                  :extra-deps {}}}}
You only need to add dependencies to libraries in bases and components. Bases and components only know about interfaces, and should not know about what concrete implementations (components) they depend on. This is decided by the projects.

seancorfield 2021-03-29T05:52:32.222800Z

Ah, OK. Will update the template stuff…

seancorfield 2021-03-29T05:55:24.223Z

Yup, that was it:

(! 726)-&gt; clojure -X:new :template polylith :name seancorfield/polyex
Generating a project called polyex based on the 'polylith' template.
Initialized the project for use with 'git'.
(! 727)-&gt; (cd polyex/; clojure -Sforce -M:poly test :all :dev)
Projects to run tests from: development, polyex

Running tests from the development project, including 2 bricks and 1 project: greeter, cli, polyex

Testing seancorfield.polyex.cli.main-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Test results: 1 passes, 0 failures, 0 errors.

Testing seancorfield.polyex.greeter.interface-test

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.

Test results: 2 passes, 0 failures, 0 errors.
Running tests from the polyex project, including 2 bricks and 1 project: greeter, cli, polyex

Testing seancorfield.polyex.cli.main-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Test results: 1 passes, 0 failures, 0 errors.

Testing seancorfield.polyex.greeter.interface-test

Ran 1 tests containing 2 assertions.
0 failures, 0 errors.

Test results: 2 passes, 0 failures, 0 errors.

Testing seancorfield.polyex.polyex-test
{:result true, :num-tests 100, :seed 1616997235595, :time-elapsed-ms 50, :test-var "greeting-test"}

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

Test results: 1 passes, 0 failures, 0 errors.
Execution time: 3 seconds
That runs a generative test in the project folder just as example of non-unit style tests not being in the bricks.

🙌 1
seancorfield 2021-03-29T05:57:08.223300Z

That needs to be a bit clearer in the documentation I think — but it does also make the whole projects thing a bit more obvious to me now!

seancorfield 2021-03-29T06:17:24.226500Z

The fixed version of clj-new is available on this SHA for anyone who wants to try it out and provide feedback:

$ clojure -Sdeps '{:deps {seancorfield/clj-new {:git/url "<https://github.com/seancorfield/clj-new>" :sha "07309e06893c35de6bf1418c05b453c02a796cc4"}}}' -X clj-new/create :template polylith :name seancorfield/polyex
Checking out: <https://github.com/seancorfield/clj-new> at 3ecda39da612c2ee2069c372b3a935e4a78804fd
Generating a project called polyex based on the 'polylith' template.
Initialized the project for use with 'git'.
$ cd polyex
$ clojure -M:poly info
  ...
$ clojure -M:poly test :all :dev
Projects to run tests from: development, polyex
  ...
$ (cd projects/polyex/ &amp;&amp; clojure -X:uberjar)
[main] INFO hf.depstar.uberjar - Synchronizing pom.xml
Skipping coordinate: #:local{:root ../../components/greeter}
Skipping coordinate: #:local{:root ../../bases/cli}
[main] INFO hf.depstar.uberjar - Compiling seancorfield.polyex.cli.main ...
[main] INFO hf.depstar.uberjar - Building uber jar: polyex.jar
[main] INFO hf.depstar.uberjar - Processing pom.xml for {net.clojars.seancorfield/polyex {:mvn/version "0.1.0-SNAPSHOT"}}
$ java -jar projects/polyex/polyex.jar 
Hello, World!
$ java -jar projects/polyex/polyex.jar Lisa
Hello, Lisa!
(esp. the README and the structure/correctness of the generated example project)

👍 2
tengstrand 2021-03-29T06:27:10.226800Z

Okay, good to hear! I will add a note about that in the doc.

seancorfield 2021-03-29T06:30:50.229300Z

Something that is missing from the docs is an example of building a library as a deployable artifact from the workspace. Am I right that it would be “just” another project that specified maybe a base for the library API and the necessary components, and then have a :jar alias to build something that could be deployed to Clojars (via a :deploy alias).

seancorfield 2021-03-29T06:31:21.229800Z

If so, I’ll add that to the clj-new template as well (tomorrow).

tengstrand 2021-03-29T06:32:18.229900Z

The api project does that in the Polylith repo.

tengstrand 2021-03-29T06:33:36.230100Z

The api (the functions that you expose) will go into a component of that library - the api component in this case.

tengstrand 2021-03-29T06:36:32.230500Z

Because the final artifact (the library) is only consumed as code, we don’t add a base to it, because bases are used to expose code/functionality to the outside world via a public API. Libraries are just “frozen code” and that’s why we expose it as a component.

tengstrand 2021-03-29T06:53:12.230800Z

Another thing @seancorfield. I would recommend you to prefix the Polylith dependencies like this (prefix them with poly):

:deps {org.clojure/clojure {:mvn/version "1.10.1"}
       poly/component-greeter {:local/root "../../components/greeter"}
       poly/base-cli {:local/root "../../bases/cli"}}
This will communicate that it’s an “internal” Polylith brick . It would be good if you follow the same pattern in your example application that we recommend in the Polylith documentation (because people will probably copy it).

👍 1
seancorfield 2021-03-29T17:29:31.233200Z

clj-new has been updated, based on feedback from @tengstrand and can be tested at this :sha "9ee232b94b3d6b7e00ab6e6ad58e0f3c7bf5487d" — it now contains a library project as well as an application project, which is set up for deployment to Clojars out of the box, just like the regular lib template that clj-new has had for a while.

👍 5
4
🎉 4
seancorfield 2021-03-29T17:57:44.236400Z

@pez Since you sent a PR about .gitignore stuff, when that’s resolved however it turns out, if you want to send a similar PR to clj-new that would be awesome (there’s a gitignore template in each of app, lib, polylith, and template — as well as an hgignore which I may drop, certainly from the polylith template since it seems pretty opinionated about using git, but maybe from the others too… does anyone use Mercurial these days?).

pez 2021-03-29T18:37:51.237500Z

Will do!

pez 2021-03-29T18:38:29.238200Z

(I think mercurial is dead.)

seancorfield 2021-03-29T18:40:43.238600Z

Hah! Maybe I’ll just excise those files then.

🙂 1
dharrigan 2021-03-29T19:23:00.239800Z

Hi. Just familiarising myself with Polylith. Read the documentation and watched the "Polylith - last architecture...." video. This may have been asked, apologies (happy to be pointed to the relevant discussion).

dharrigan 2021-03-29T19:24:13.240800Z

Would it play nicely with something like component, or integrant, clip or mount? Is the idea not to use these types of lifecycle managment libraries?

pez 2021-03-29T19:30:16.244800Z

@dharrigan I think you are pointing to a need for the Polylith documentation to state what it is not about. Saying this because as far as I have understood things, Polylith has no opinion about the choice of life cycle management. (I could of course be wrong, I am quite new to the concept).

dharrigan 2021-03-29T19:31:52.247100Z

Right. For example, I have an embyronic application that I've started to put together. As a bit of an experiment I reordered it to "fit" nearly into the polylith directory structure/architecture. I also use JUXT Clip and I'm still able to "wire" together my namespaces/functions (i.e., to spin up a connection to a database, and a redis server and the ring handler and do a bit of pre-start, application boot type of thing)

seancorfield 2021-03-29T19:39:38.253900Z

Although the documentation suggests Mount I would expect it’s easy to use Polylith with Component or Integrant (both of which I would prefer over Mount).

dangercoder 2021-03-29T19:40:36.255700Z

I’m porting an integrant project to use polylith right now. I keep the integrant system definition in the “base” and its working just fine right now

tengstrand 2021-03-29T19:41:38.257300Z

We plan to add a section at the first page where we describe what Polylith is not. @pez is right. Polylith itself doesn’t “write”/provide any code for you, so it’s not what e.g. Spring is for Java. @furkan3ayraktar is the one of us in the Polylith team that has worked with most Polylith systems (around five) and he uses a forked Mount and has adjusted it to work nicely with Datomic Ions. We have discussed if we should add a section about this in the documentation, but hesitated, because we haven’t used so many of the different alternatives ourselves, and Polylith doesn’t care if you use any or what you use. Mount has served us well, but it’s possible that other alternatives could be as good or even better.

furkan3ayraktar 2021-03-29T19:42:14.258500Z

I use my own version of https://github.com/tolitius/mount where I tweaked it a bit to play nicely with Datomic Cloud. I think it’s totally fine to do lifecycle management when needed and Polylith doesn’t prevent that.

dangercoder 2021-03-29T19:42:28.259100Z

still work in progress though, not 100% done with this experiment.

seancorfield 2021-03-29T19:43:59.262100Z

I might make a Polylith version of my “usermanager” example app and see how that works out, with Component…

👍 3
furkan3ayraktar 2021-03-29T19:44:47.264100Z

Yeah, exactly, I haven’t experimented with others so I wouldn’t say mount is the best. I just picked it since it felt lightweight/straightforward at the time.

dharrigan 2021-03-29T19:46:47.266300Z

Right. You see, when I was looking at it, I was confused. - but now, I'm like okay, I have this directory structure, with components and bases okay. So, now I have my application "main" in a base, which is the gen-class-ified class used for depstar. That main function (when used via java -jar... invokes JUXT clip which now pulls together all the component interfaces (i.e., creating a connection to a database via a ....database.interface/create-connection function call, and spinning up the ring/jetty by a ....rest-api.interface/start-jetty function call). So JUXT Clip is still "managing" the lifecycle in the sense of starting (including post-starting, like migrating my database) and stopping the application.

dharrigan 2021-03-29T19:50:13.268500Z

clip, which uses aero underneath, gives me the ability to merge in different configuration values and runtime, i.e., a set of values for local development, a set of values for test environment and a set of values for production environment. I say that because I noticed in the real-world example the use of env and a env.edn file in the realworld example on github. So I suppose I get that functionality already.