Fork me on GitHub
#boot
<
2017-03-20
>
hit02307:03:25

Can Anyone link an easy-to-understand resource on Maven? Have been reading this: https://github.com/boot-clj/boot/wiki/Boot-Environment , which uses the term extensively!

martinklepsch07:03:31

@hit023 Maven is a bit like npm for JS, it’s Java’s package manager and has been adopted in the Clojure world too

hit02308:03:58

Any quickstart of sorts to understand Maven ?

martinklepsch08:03:50

@hit023 do you have any particular problem? Usually you don’t need to know much about Maven

hit02308:03:14

Oh! No. Just wanted to know if there was anything significant to be learnt. Now I know! Thanks.

martinklepsch08:03:37

But there’s nothing “important to know” really (at least as far as I’m concerned 😄)

micha14:03:34

@hit023 one thing i think is good to know is how maven resolves transitive dependencies and how it deals with conflicting versions of transitive dependencies

micha14:03:18

in the JVM you can't have multiple versions with the same class name at the same time

micha14:03:22

if that makes sense

micha14:03:03

like you can't have class Foo from the foo-1.2.3.jar jar at the same time as the Foo class from the foo-2.3.4.jar jar

micha14:03:31

so maven has a simple strategy for choosing which version of a dependency to use when there is a conflict

hit02314:03:34

Oh! Thanks. @micha and @martinklepsch . Will keep posting if in doubt!

micha14:03:35

generally you will look at any dependency conflicts with boot show -p and resolve them yourself, overriding what maven does if you need to

micha14:03:57

also boot show -d will show the dependency graph that maven came up with

micha14:03:33

so you will see with boot show -d the result of the dependency resolution process, after conflicts have been resolved

micha14:03:38

you can resolve dependency conflicts yourself in one of 2 ways, generally

micha14:03:05

1. you can specify the desired version of the contested transitive dependency yourself as a direct dependency of your project

micha14:03:56

2. you can add :exclusions to the "coordinates" of the direct dependency of your project that itself depends on the version of the transitive dependency that you don't want

micha14:03:36

i think 1. is probably the simplest method

hit02314:03:57

Okay, so where does Aether fall into all this. I saw this in the repository: https://github.com/boot-clj/boot/blob/master/boot/aether/src/boot/aether.clj

hit02314:03:08

I know it is a common API for dependency management

hit02314:03:14

But that is all

micha14:03:38

yeah aether is the underlying machinery

micha14:03:48

it knows how to interact with maven repositories

micha14:03:55

maven also uses it

micha14:03:10

that's wrapped in a clojure library called "pomegranate"

micha14:03:35

then boot wraps that with its own stuff

micha14:03:47

most of which is in the boot.aether namespace

micha14:03:04

the user-level functions are in the boot.pod namespace though

micha14:03:34

usually you won't need to interact with maven directly yourself

micha14:03:50

but it does help to have an idea of what it's doing

micha14:03:04

especially with respect to dependency resolution and conflicts

hit02314:03:35

Okay, so I'll look into it in the repo. Now, what is Maven Artifact Resolution ? Stumbled upon this: https://maven.apache.org/resolver/index.html . As a person understanding/contributing to boot, do I need to worry about it?

micha14:03:10

i think it's good to know

micha14:03:30

i mean the basics

micha14:03:49

like an artifact is a thing that has "coordinates" in a repository

micha14:03:07

coordinates are like [boot/foop "1.2.3"]

micha14:03:38

that's [<groupid>/<artifactid> "<version>"]

micha14:03:58

the groupid is namespacing of artifacts

hit02314:03:15

Okay. Read this http://www.braveclojure.com/appendix-a/ . But need a more comprehensive resource giving important info.

micha14:03:16

so like in maven you can have the com.me.something group id

micha14:03:31

but it's way more than you would want to actually read

micha14:03:39

a lot of it is specific to the maven build tool also

hit02314:03:05

very comprehensive, indeed.

micha14:03:05

it's a little bit of an unfortunate thing the way it evolved

micha14:03:30

maven the build tool paved the way and established the repo structure and so on

micha14:03:47

which is generally useful even without maven the build tool

micha14:03:16

but there are many things in the POM spec that are related to maven the build tool implementation details

micha14:03:21

which you can just ignore

micha14:03:46

really all you need to care about is the resolution strategy

micha14:03:51

which is very simple

micha14:03:03

your project has a vector of coordinates

micha14:03:14

these are your project's direct dependencies

micha14:03:35

but one of the main affordances of the maven stuff is automatic resolution of transitive deps

micha14:03:44

so like your dependencies may have dependencies of their own

micha14:03:57

so aether will loop over your project's dependencies

micha14:03:11

for each one it fetches the associated pom.xml file

micha14:03:22

that's the descriptor for the artifact

micha14:03:36

it contains information about what that artifact's dependencies are, etc

micha14:03:04

so it loops over your dependencies, fetches their poms, and downloads the artifacts to your local maven repo

micha14:03:17

~/.m2/repository by default

micha14:03:32

then it builds a graph of transitive dependencies

hit02314:03:51

Ah! Now I see it. (the .m2 folder)

micha14:03:04

to do this it recursively downloads pom.xml files for the dependencies of your dependencies, and for their dependencies, and so on

micha14:03:18

yes your .m2 directory is itself a maven repository

micha14:03:21

like clojars

micha14:03:41

you can deploy artifacts to it in the same way you'd deploy to clojars

micha14:03:08

so after aether has fetched all the pom.xml files for all the dependencies of dependencies

micha14:03:33

it might be the case that dependency A depends on version 1 of some other artifact, C

micha14:03:45

and dependency B depends on version 2 of C

micha14:03:56

but aether can't load both versions

micha14:03:11

because there can only be one class with a given name on the class path

micha14:03:21

so it uses the simplest strategy it can

micha14:03:55

it picks the transitive dependency that has the shortest path to a dependency that you selected in your project's dependencies

micha14:03:11

so like suppose your project depends directly on A and B

micha14:03:34

and A depends on C via the chain A -> X -> Y -> C

micha14:03:40

where -> means "depends on"

hit02314:03:47

oh! this: "nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0 ?

micha14:03:54

and B depends on C via B -> Z -> C

micha15:03:05

it will choose the version of C that Z depends on

micha15:03:20

yes what you said 🙂

micha15:03:42

and the part about explicitly adding the dependency is also exactly right

hit02315:03:48

copied from the site you linked 🙂

micha15:03:11

you can also add :exclusions to the coordinates of A

micha15:03:24

like [A "1.2.3" :exclusions [C]]

micha15:03:44

that will prune the C dependency from any transitive deps of A

micha15:03:56

so it won't consider them

hit02315:03:15

Ohh! That is clean!

micha15:03:38

i think i prefer the way you said above

micha15:03:43

with the explicit dependency

micha15:03:03

because i prefer explicit resolution to implicit exclusion

micha15:03:10

but it's 50/50

micha15:03:25

both ways have their drawbacks and strengths

hit02316:03:48

Where can I see calls to the JVM being made by boot to manage filesets? Which file in the repo ? Any help/pointers would be great.

hiredman20:03:32

strace is always terrifying

hiredman20:03:07

well, I guess that wouldn't just show jvm fileset related calls

mobileink20:03:37

@hit023 what is your goal?

ag20:03:02

hey guys, if I have some task that uses pandeiro.boot-http/serve and it's essentially blocking, how do I call it (from command line) so it wouldn't block the repl? I know how to do in when you're already in the repl (just wrap it in a future - the way it explained in cljs-repl's readme)

mobileink20:03:28

@hit023 just spend some quality time snooping around the source. it's worth the trouble, in my experience

mobileink20:03:53

@ag: show us your task code? is there a (wait) in there?

ag21:03:20

so if I have dev task like this:

(deftask dev []
  (comp
    (dev-env)
    (serve :reload true)
    (watch)
    (notify)
    (npm-install)
    (sassc)
    (reload)
    (cljs-repl)
    (cljs)))
how do I run it from command line and make sure it’s not blocking

mobileink21:03:21

heh, not an expert, but not sure what exactly u mean by "blocking".

mobileink21:03:34

what exactly is the behavior you're seeing?

mobileink21:03:07

and what do you expect to see?

mobileink21:03:19

fwiw this sort of thing has been a big pain in the arse to me too. simple_smile

ag21:03:46

so, if you run that task while you already in repl: (boot (dev)) - after it done compiling, it will block the repl. If you wrap everything in a future, e.g.: (future (boot (dev)) - it won't

ag21:03:07

now, I need to find a way to execute it from the command line and without blocking the repl

mobileink21:03:53

stick a (repl) at the beginning of your pipeline?

ag21:03:38

not helping,

(deftask some-t []
  (comp
   (repl)
   (dev)))

ag21:03:43

still blocks the repl

mobileink21:03:07

so "blocks the repl" means what exactly? you try to eval some code and nothing happens?

ag21:03:04

“blocks the repl” means you can’t type anything into the repl

mobileink21:03:20

damn. you got me. i'd try divide and conquer - get rid of everything after notify, then add back one by one? at least to isolate what's causing the prob.

geoffs21:03:52

Can you not just execute it from the command line, and use the future wrapping when running from the repl?

mobileink21:03:56

btw, you do grok that the boot "pipeline" is actually a circuit? i worked with boot for months before i began to grasp the significance of that.

mobileink21:03:08

try repl -s?

ag21:03:10

@geoffs I certainly can, you do boot repl and then in the repl (future (boot (dev)), but I want to do it from the command line - whole thing

mobileink21:03:42

i.e.

(deftask some-t []
  (comp
   (repl :server true)
   (dev)))

ag21:03:06

nope, still blocks

ag21:03:22

currently only way to get it non-blocking - is to have it in a future. I thought I could create a task that essentially does that - wraps dev in a future, but still can’t get it to work

ag21:03:54

I think I had it before, then at some point something changed - boot updated or maybe something else, I dunno.

ag21:03:00

maybe I never had it

ag21:03:05

¯\(ツ)

geoffs21:03:15

You don't need to wrap it in a future if it's part of the pipeline.

geoffs21:03:58

The pain with doing a repl -s, is that you need another 'boot repl -c' to actually use the repl

mobileink21:03:21

i'm flummoxed. i do sth similar, but w/o reload and the cljs stuff. i suspect cljs-repl. 😉

ag21:03:58

@mobileink I think it’s serve since it actually runs jetty server

mobileink21:03:39

could be. i use cider; your just running a cli repl client?

mobileink21:03:28

this is boot-http?

ag21:03:07

that’s the thing - I use cider too, and it just works. I overlooked the fact that it works for me, but I need other people to be able to use it too

ag21:03:36

asking them to type too many things in correct order with certain time intervals - not a good way to sell boot

mobileink21:03:45

well that sux. 😉

ag21:03:05

already having to defend decision to switch from lein

mobileink21:03:23

other people - how i hate them! heh.

ag21:03:15

well, I hate people in general - I think dogs are much better.

ag21:03:48

I bet if I had to convince my dog, he would’ve given me “woofff” for Emacs and CIDER

mobileink21:03:28

we'll figger this sucker out, dammit! i'm away from my machine, but when i get back i will bend boot to my will!

mobileink21:03:38

any chance you could share the code you're trying to run with this, so we can test?

ag21:03:33

remove irrelevant stuff like npm and sass

mobileink21:03:52

@ag: no, i mean the code you're trying to run. maybe it's hanging? in any case we cannot reproduce without it

ag21:03:11

@mobileink it’s not “hanging” - I think it’s a normal behavior of serve - check out boot-cljs-repl’s readme - it explicitly says to wrap dev task in a future

mobileink22:03:53

cljs-repl starts an nrepl, no? the readme says "To start evaluating forms in the browser you must first connect to the running Clojure nREPL server (started by the cljs-repl task above)" so you're running 2 nrepl servers?

mobileink22:03:14

try (repl :client true)?

mobileink22:03:42

u start with $ boot repl, which starts an nrepl server and an nrepl cli client. then you run your dev task. it contains cljs-repl, which starts another nrepl server.

mobileink22:03:44

dunno what happens then but it seems unpromising.

qqq22:03:12

@mobileink : do you want a working build.boot file to play with, or are you trying to understand each piece in great detail?

mobileink22:03:19

i no wan nuthin. just tryin to help @ag.

mobileink22:03:23

at this point i'm guessing that @ag is having a prob because of multiple nrepls. pure speculation.

qqq22:03:01

@mobileink: a spell checker may be useful

mobileink22:03:25

fuk speling.

ag22:03:51

nooo, @mobileink just run pandeiro.boot-http/serve in a task and it will block repl

mobileink22:03:09

example? i do that with no prob, but w/o cljs.

ag22:03:08

Oh really? You're saying running boot repl serve not blocking?

ag22:03:26

Let me actually try

ag22:03:27

yup, boot repl serve runs it and doesn’t not return you to boot.user> prompt

ag23:03:50

oh, wait actually it did.. just takes long time

ag23:03:25

so I was wrong… it is probalby cljs-repl

ag23:03:25

or something else

mobileink23:03:01

here’s something I use:

(deftask dev
  "repl development."
  []
  (comp (cider)
        (repl :server true)
        (serve :dir "target")
        (watch)
        (notify :audible true)
        (target)))

geoffs23:03:29

Oh, yeah. There's another task for cljs-repl that doesn't start an nrepl server which is probably what you want to use

geoffs23:03:47

cljs-repl-env I think

mobileink23:03:10

this assume that I have in ~/.boot/profile.boot:

(deftask cider "CIDER profile"
  []
  (require 'boot.repl)
  (swap! @(resolve 'boot.repl/*default-dependencies*)
         concat '[[org.clojure/tools.nrepl "0.2.12"]
                  [cider/cider-nrepl "0.14.0"]
                  [refactor-nrepl "2.2.0"]])
  (swap! @(resolve 'boot.repl/*default-middleware*)
         concat '[cider.nrepl/cider-middleware
                  refactor-nrepl.middleware/wrap-refactor])
  identity)

mobileink23:03:34

i don’t see anything explicit about future. all i see is a very lame example that uses future for no apparent reason.

ag23:03:22

I tried replacing cljs-repl with cljs-repl-env… still the same

ag23:03:29

ah dammit… it’s not cljs-repl either… something else is blocking repl… ;(

qqq23:03:09

I have a boot task that says:

(comp
  (watch)
  (garden ...)
  (reload ...)
  (cljs-repl ...)
  (cljs ...)
  (target ...))
is there a way I can add another task to inject a repl into it?

qqq23:03:29

i.e. something I can emacs + cider-connect into

ag23:03:15

@qqq you mean (repl). I don’t think I understand the question

ag23:03:45

@mobileink it’s turned out to be (watch) - that thing is blocking repl

ag23:03:57

maybe I need to move it around, order sometimes is important

ag23:03:32

so, guys, now how do I force (watch) to not to block? 😉

mobileink23:03:41

try moving cljs-repl in front of watch? i dunno. cljs-repl is starting to look like a very badly designed bit of sw to me.

mobileink23:03:41

i don’t see how watch could block a repl.