Fork me on GitHub
#tools-deps
<
2021-04-10
>
henrik4210:04:38

Hi! I'm doing my first experiments with clj and noticed that I can put this into my deps.edn:

:aliases {:foo {:main-opts ["-e" (let [x :foo] (println x))]}
and then use -Mfoo to run. Is this ok? Can I use any form in there? I found https://clojurians-log.clojureverse.org/tools-deps/2018-06-11 and I'm wondering, what came out of it.

practicalli-johnny10:04:20

clojure -M:foo should run that expression. Unless you really use an expression a great deal or need it for some kind of work-around, I don't see the value myself. It seems simpler to use the -e flag on the command line.

henrik4210:04:18

I'd like to put clojure forms into the aliases as examples. Putting them on the command line would make them platform dependent. So I just wanted to check that putting them there is fine.

Alex Miller (Clojure team)12:04:28

That embedded Clojure form there is not valid syntax in deps.edn

Alex Miller (Clojure team)12:04:05

So putting that there is not fine

Alex Miller (Clojure team)12:04:02

:main-opts is a vector of strings

henrik4212:04:19

@U064X3EF3 thanks for the clarification

zalky19:04:04

Hi all, wondering if there's a way to retrieve the resolved deps environment, specifically the fully resolved :paths attribute after all the aliases have been merged and a main function has been launched? Thanks!

seancorfield19:04:09

@zalky Not really. By the time your code is actually running, a lot of that information has been merged away.

seancorfield19:04:20

You can use tools.deps.alpha as a library to compute the “project basis” which is a superset of everything in the root deps.edn, user deps.edn, and project deps.edn files but you can’t tell which aliases were used to invoke your code — only what different paths/deps combinations would be computed from any given aliases.

seancorfield19:04:47

You can get the classpath though — which might be enough for your needs — via a JVM system property.

seancorfield19:04:17

(System/getProperty "java.class.path")
will produce a very long string of JAR files and directories separated by (System/getProperty "path.separator") (which is different on Windows vs macOS/Linux).

zalky19:04:48

Thanks @seancorfield, this is very helpful. If I filter that list for directories, would that be equivalent to the fully resolved paths? Might there be anything else thrown in? My motivation is that I'm doing some work with clojure.tools.namespace and I need to know all the directories I might have source in.

seancorfield19:04:32

You’ll get directories for the equivalents of src, resources, and maybe test plus any git deps or local/root deps in play.

👍 3
seancorfield19:04:27

You could probably filter out any absolute paths and what is left should be just your own project’s stuff (depending on how you have your project set up).

zalky19:04:06

Gotcha, thanks!

Alex Miller (Clojure team)19:04:48

what's your actual goal? project paths?

zalky20:04:23

Hi @U064X3EF3, I have a clojure.tools.namespace based reloaded workflow, which requires as input a set of directories to watch for changes. While I can supply a list of hard-coded directories in :main-opts , my understanding is that project paths is dynamically computed from all the active aliases.

Alex Miller (Clojure team)20:04:58

it is, but there is not an explicit place to get just the paths

Alex Miller (Clojure team)20:04:24

the classpath computed by tools.deps will put all paths at the front of the classpath though

Alex Miller (Clojure team)20:04:23

So you could just walk the (System/getProperty "java.class.path") while it's directories. To be more righter, could probably only take the paths in your project (local or git deps could also be dirs and happen to be at the front)

👍 3
zalky20:04:34

Thanks, I'll give the classpath approach a go.

seancorfield20:04:36

Why are you using c.t.n / reloaded? I've never felt the need for that sort of thing (and my REPLs run for weeks, sometimes months).

seancorfield20:04:24

I'm always curious when I find folks using this workflow and -- as in your case -- jumping through hoops to make it work...?

zalky14:04:12

@seancorfield, I am working with a component based system, and the particular reloaded workflow I am using automatically restarts the running application when reloading a namespace would otherwise leave stale objects to gum up the works. c.t.n is the thing that determines when such a namespace has changed. Do you have any alternatives workflows that you recommend for working with a stateful application? I'm not sure I immediately see a way around it when working with component. At least the reloading task is fairly straightforward. The bigger picture is that we're in the process of migrating our build framework from boot to deps, which has been great in many respects. But because deps is much narrower in scope, the work has been figuring out how to stitch our previous build and development workflows back together.

seancorfield16:04:02

We use Component very heavily at work - we also migrated from Boot to the CLI - we do not use any sort of reloaded workflow. We evaluate every change we make into the running program with no restarts.

zalky17:04:39

@seancorfield, interesting, I think most of the justification for the reloaded workflow comes down to stale records not implementing newer instances of a protocol. Do you just take special care to make sure protocol namespaces are only ever loaded once?

seancorfield17:04:14

We don’t change records/protocols much after the initial work on them. We also tend to use protocol implementation via metadata these days (since Component supports that).

seancorfield17:04:18

If you find you are changing protocols so much that you are forced to remove + reload namespaces a lot, I would take a harder look at how you’re using protocols (or records) and see if you can optimize how you design/build them.

zalky17:04:45

I agree, it's like you say: they don't change too much after the initial design, and the need for them is not very common to begin with, but it was nice to have even that edge case covered. Maybe it's worth revisiting at some point during our build migration. Thanks again this was very helpful.

seancorfield17:04:16

I mean, we do have RCFs (“Rich Comment Forms”) with component/start / component/stop forms in them so we can eval code to start and stop systems when we need to but mostly I start the REPL (outside the editor — because it lives longer than my editor, in general) and just leave it running for weeks, and then eval the main ns for an app and then eval a component/start form and just work on a feature until I’m done, evaluating every single change I make (often without even bothering to save files). If I need to switch to another app in our monorepo, I may stop the first app before starting the second app, but I often just have multiple apps running in my REPL (I tend to make sure tests start/stop components as needed and use different ports to the dev port).

dominicm18:04:56

ugh, sorry. I have code for this I can share

dominicm18:04:26

https://git.sr.ht/~severeoverfl0w/wedge/tree/master/item/src/io/dominic/wedge/user.clj#L48-86 I intentionally leave in :local/root deps in case you are doing development on them, but you can use exclude-libs-refresh to remove those libraries manually.

zalky14:04:15

Thanks @U09LZR36F for sharing, that's a useful example!