Fork me on GitHub
#boot
<
2016-02-14
>
grounded_sage01:02:56

Hi I'm curious as to whether there is a comman to generate a generic boot project template. Similar to 'lein new app'

akiva01:02:32

Yep. Hold on one sec.

seancorfield01:02:00

It’ll get integrated into Boot itself at some point. Micha and I have had brief discussions about that already.

micha01:02:24

man, boot-new is looking great!

seancorfield01:02:52

I want to get all the basic functionality in place and well-tested, and incorporate some community feedback, so I can feel happy that it’s "ready" to go into core...

micha01:02:17

yeah that sounds great

seancorfield01:02:56

While I have your attention… simple_smile

seancorfield01:02:20

What’s your thinking on util/exit-error vs just throwing an exception?

micha02:02:04

ah ok one sec

seancorfield02:02:42

The problem (from my point of view) is that throwing an exception that the BootApp catches leads to a horribly ugly experience for end users.

seancorfield02:02:30

So it feels like there needs to be a distinction between "OMG! I has errorz!" and "I’m sorry, I can’t do that Hal!" in terms of exiting the Boot pipeline with a non-zero status code to the shell.

seancorfield02:02:37

For example:

(! 502)-> boot -d seancorfield/boot-new new -n funjure
Sorry, names such as clojure or *jure are not allowed. 
If you intend to use this name ironically, please set the 
BOOT_IRONIC_JURE environment variable and try again.
             clojure.lang.ExceptionInfo: boot.App$Exit: 1
    data: {:file
           "/var/folders/p1/30gnjddx6p193frh670pl8nh0000gn/T/boot.user3176105402114756413.clj",
           :line 17}
java.util.concurrent.ExecutionException: boot.App$Exit: 1
                          boot.App$Exit: 1
       boot.new/create/invokeStatic   new.clj:   88
                    boot.new/create   new.clj:   80
      boot.new/eval1120/fn/fn/fn/fn   new.clj:  182
         boot.new/eval1120/fn/fn/fn   new.clj:  175
                boot.core/run-tasks  core.clj:  794
                  boot.core/boot/fn  core.clj:  804
clojure.core/binding-conveyor-fn/fn  core.clj: 1938
                                …                

seancorfield02:02:34

Aside from anything else, that data: {:file …} stuff is bewildering (line 17 of what? Do I care?) and the stacktrace really isn’t useful either.

micha02:02:19

you might want to look at that file though

micha02:02:42

it might have been generated by a task

seancorfield02:02:10

(! 504)-> cat /var/folders/p1/30gnjddx6p193frh670pl8nh0000gn/T/boot.user3176105402114756413.clj
cat: /var/folders/p1/30gnjddx6p193frh670pl8nh0000gn/T/boot.user3176105402114756413.clj: No such file or directory

seancorfield02:02:32

So… not helpful simple_smile

micha02:02:55

hah, yes sometimes they're created by clojure, and clojure uses temp files that are set to delete on exit

micha02:02:18

but anything in boot temp dirs will hang around until the next time you run boot

micha02:02:23

so you can debug problems like that

micha02:02:30

but back to the exit-error thing

micha02:02:53

the reason that macro exists is to support boot running in boot

micha02:02:12

yes the stack trace printing seems like a bug

seancorfield02:02:15

In particular, there seem to be four exit cases...

micha02:02:36

if the exit status is 0 then it seems like we're wrong if we print a stack trace

micha02:02:43

because that indicates success

seancorfield02:02:47

Well, more to the point, there’s (at least) three types of errors: a real exception ("OMG! I haz errorz!"), a failure due to argument validation ("I can’t even run because option X is not valid"), a failure in the task due to bad input ("I started to run but failed to generate a project from the template you specified").

seancorfield02:02:00

Only the first one really needs a stack trace shown to the end user.

micha02:02:23

i see, yes that makes sense

seancorfield02:02:24

Argument validation should mostly occur before the pipeline even runs and shouldn’t display a stack trace.

micha02:02:43

or stack traces could be suppressed based on verbosity level

seancorfield02:02:46

The last one is a grey area but I think there’s a good case for a task to make the decision.

micha02:02:55

so if you're in verbose mode it could print all stack traces

seancorfield02:02:57

But right now, all three have to be exceptions.

micha02:02:07

yeah i agree

micha02:02:19

so perhaps we want an abort function

micha02:02:26

to standardize this

seancorfield02:02:38

I think there definitely needs to be a way to throw an exception that Boot recognizes as "Do not print this exception’s stacktrace"

seancorfield02:02:14

And maybe it’s just a matter of throwing (ex-info "Message" {:stacktrace false …}) and having Boot respect that?

seancorfield02:02:45

I don’t know that we need an abort function per se — because the normal flow of exceptions through the pipeline is fine (although some tasks really might not want certain exceptions to be caught by a task that wraps them… but that’s a separate issue).

seancorfield02:02:53

so (when (or (nil? (:stacktrace (ex-data e))) (:stacktrace (ex-data e))) (print-stack-trace e)) ?

seancorfield02:02:42

i.e., print it if it’s not an ex-info, or it’s an ex-info without :stacktrace, or when it’s explicitly :stacktrace truthy...

seancorfield02:02:52

It would probably be cleaner to have :no-stacktrace true simple_smile

micha02:02:23

i think what you pasted is good

micha02:02:03

i'm just trying to refresh my brain on the big picture

seancorfield02:02:56

Currently boot-expectations exits via an exception where it does want the ex-data printed but the stacktrace is not relevant so I’d suppress it there. But boot-new would work better with being able to print a user-level error message and just exit (with a non-zero status code)… so I think only printing ex-data if it contains something other than :stacktrace false / :no-stacktrace true / whatever you think is appropriate… i.e., check (seq (dissoc (ex-data e) :stacktrace))… after all, printing {:stacktrace false} is every bit as confusing / useless as a stacktrace simple_smile

seancorfield02:02:29

Anyways, wanted to put that bug in your ear while you’re here simple_smile

micha02:02:08

yeah i think perhaps this is similar to a logging process

micha02:02:18

like which information the user sees

micha02:02:33

seems like a good idea to make that somehow related to the verbosity level

micha02:02:55

sometimes you do want to see a stack trace that would normally be considered useless

micha02:02:41

so some way for tasks to categorize exceptions, like you can with log levels, is perhaps a suitable approach

micha02:02:45

we want to suppress that

seancorfield02:02:55

If the stacktrace was suppressed in the first case, it would be a much better user experience.

seancorfield02:02:53

Mind you, even in the second case, if the concurrent exception was unwrapped(!) and we could suppress the stacktrace in ex-info and still have the exception itself printed, that would be fine.

seancorfield02:02:19

The nesting is… ugly and unnecessary… So we get the error message three times.

micha02:02:21

yes i think we should always unwrap exceptions that come from futures

micha02:02:31

i think that's a best practices type of thing

micha02:02:43

so the places where that's not done should be updated i think

micha02:02:52

what do you think about adding a :severity key to the ex-info, or something along those lines?

seancorfield02:02:55

So if :severity was present it would be print less / more of the exception / stacktrace depending on the value?

micha02:02:22

i was thinking to suppress the trace unless severity is above some threshold

micha02:02:33

corresponding to the verbosity level

seancorfield02:02:58

Like I say I think there’s three types of exceptions here, regardless of the verbosity level.

seancorfield02:02:56

Although I guess I could live with two (if the ex-data was suppressed when it was empty aside from :severity).

micha02:02:25

yeah that sounds reasonable on its own

micha02:02:39

pruning stack traces is always good

micha02:02:25

i need to think about the situation where tasks want to completely terminate the pipeline

seancorfield02:02:37

So essentially: 1. Exit with an error message (no exception information) 2. Exit with an exception (and maybe ex-data, but no stacktrace) 3. Exit with an exception and full stacktrace

micha02:02:44

that seems like something we want to think about, not sure it's a good thing

seancorfield02:02:14

If argument validation throws an exception before the task fn starts, don’t you already have that case handled?

micha02:02:42

yes, that's true

micha02:02:17

i'd like to separate the notification part of error handling in the pipeline

seancorfield02:02:26

I’d be OK with 1. and 2. above being merged into a single severity but I’d really prefer to have them separate for more control over the user experience.

micha02:02:34

like have a task that implements the notification policies

micha02:02:57

this way you can have tasks that just send exceptions the way you have the general logging facility

micha02:02:06

like for example boot-expectations

seancorfield02:02:17

But whose responsibility would it be to add such a task to the pipeline?

micha02:02:21

if tests fail it could attach metadata to the fileset

micha02:02:29

well i think it could work like this

micha02:02:43

if tests fail you attach metadata to the fileset

micha02:02:51

that any downstream task can see

micha02:02:17

you may make a task that just logs the error or plays a sound or prints to the screen the stack trace, whatever

micha02:02:24

and put that downstream

micha02:02:32

that task would remove the error metadata from the fileset

seancorfield02:02:35

That’s no use if a task just returns the fs it was given instead of what the wrapped task returned tho’…

micha02:02:10

so boot-expectations could have both pre-wrap where it does the tests

micha02:02:24

and post-wrap where it looks at the fileset that's bubbling back up the pipeline

micha02:02:38

if the metadata is still there that means no notification task handled the exception

micha02:02:47

so you can do whatever default thing your task does

micha02:02:25

but if the metadata has been removed then that means that the notification task handled it, and boot-expectations can just continue and do nothing

micha02:02:00

so you could have a notification task that exits with error when an exception is thrown in the pipeline

micha02:02:08

or it could just print a message

micha02:02:34

otherwise every task needs to have its own policies for handling exceptions

richiardiandrea02:02:36

@micha @seancorfield I have done a couple of things in the conversation

richiardiandrea02:02:58

For example there is a PR waiting for unwrapping exceptions

richiardiandrea02:02:15

Just saying, so that we reduce duplications

micha02:02:27

it would make sense to merge those first

richiardiandrea02:02:39

Also the patch for parallel tests can be useful :))

seancorfield02:02:30

The metadata approach just feels like far too much subtle magic to me — especially for a task that doesn’t (currently) touch the fileset...

seancorfield02:02:50

Boot new for example completely ignores the fileset.

micha02:02:51

i think we could design it so that it would Just Work

micha02:02:28

but with certain guidelines about how to throw exceptions if you want to achieve more precise error behavior

micha02:02:45

or probably functions in boot.core

micha02:02:59

haha skeptical is good

micha02:02:07

i'm skeptical of everything

seancorfield02:02:32

As long as whatever ends up in there supports the three levels I mentioned above simple_smile

seancorfield02:02:09

OK, time to feed kitties.

seancorfield03:02:24

(looks like it's a PR based on changes to 2.6.0-SNAPSHOT but made against master instead?) /cc @richiardiandrea

seancorfield03:02:46

And, hey, feeding kitties is serious business here @micha !

richiardiandrea03:02:50

@seancorfield it is revased on 0.2.6 so that @micha can easily merge it in

richiardiandrea03:02:09

But i don't have that power

onetom04:02:23

@alandipert: im aware of the musl vs glibc binary compatibility issue. i find it a bit daring to switch, but on the other hand i welcome the change big time. it's crazy how much garbage and complexity has accreted in glibc, just because it supports so many architectures which so few people or devices use... that's one of the reasons why does it take forever to recompile a whole system, which in turn leads to the need of binary distributions, etc etc. whole lot of complexity...

onetom04:02:25

Can someone help pls? @danielsz for example? I always used boot watch test, so I'm not sure how to do it with lein. I see there is a lein-auto plugin, but it's not included in danielsz/system/project.clj, so I'm not sure how is he running his tests. Just with lein test occasionally? (which runs of course. with a lot of errors because the way the various components are tested i guess...)

onetom04:02:56

I'm asking because I'm trying to contribute an http://docs.caudate.me/adi/ component (which we use in production, but want to share with our other projects instead of copy-pasting simple_smile

onetom04:02:04

I settled with lein test :only system.components.adi-test since I only had to run it a couple of times, but I would be still interested to know how are you testing it, @danielsz? do u have the lein-auto plugin in your system-wide lein profile?

seancorfield05:02:13

It's kinda early in his morning according to his profile... hopefully he'll drop in and provide insight in a couple of hours?

seancorfield05:02:17

Looking at the repo, it looks like there are all sorts of environmental dependencies for those tests... databases, network libraries, web servers... I can barely imagine what his test environment looks like simple_smile

grounded_sage05:02:06

Cool got it working. Didn't realise -d and seancorfield/boot-new was a dependency (not part of core). Will have to go through the Boot documentation more thoroughly now so I can build my static website simple_smile

seancorfield05:02:58

@grounded_sage: Yeah, until it becomes part of code you’ll have to follow the instructions here: https://github.com/seancorfield/boot-new/blob/master/README.md

amonks05:02:05

I’m using boot-cljs. I want to put a (println) in a macro, so that it prints at compile time (when I run the (cljs) task in a boot repl).

amonks05:02:06

right now it isn’t printing. Is that expected? am I missing a step?

danielsz09:02:28

@onetom: I run tests manually, exactly the same way you ended up doing. I typically run tests before uploading a new version, making sure everything works. Once a component is written, it will not often change. I'm pretty sure there's a host of test runners available for Leiningen should you need one after all. Can't be more specific cos I'm not using Leiningen much anymore. simple_smile

danielsz09:02:17

@seancorfield: Yes, you are correct, to make all tests pass you need a machine with all those external resources installed. And I have them installed for the most part simple_smile

onetom10:02:10

@danielsz: thx. how come system.boot is still using lein then, not boot?

danielsz10:02:58

@onetom That's solely historical.

grounded_sage12:02:22

Cheers @martinklepsch I was actually planning on using Stasis because I have used it before and enjoyed it. Will see how I go.

mobileink15:02:23

@onetom: sorry for the late response - I think a few simple examples or just a blurb would be appropriate on the boot wiki, but the bulk of the docs should be on the project site. or maybe some generic webapp patterns with recipes from a variety of boot libs - here's how you do it with boot-http, here's how with boot-gae, etc.

micha16:02:52

@amonks: you want to debug the macro?

onetom16:02:39

@danielsz: this (alter-var-root #'prod-system component/start) on https://github.com/danielsz/system seems incorrect because prod-system is a system factory function, not an instance of a system:

(ns my-app.core
  (:gen-class)
  (:require [my-app.systems :refer [prod-system]]))

(defn -main 
  "Start the application"
  []
  (alter-var-root #'prod-system component/start)

onetom16:02:41

@micha: what's the main benefit of having boot.user the default ns for the repl task? i keep hitting issues regarding various symbols being already bound, like boot.core/rm was colliding with a protocol definition of mine. then system.boot/system is used to define my dev task, but then i want to access the actual running system from the repl, which is reloaded.repl/system.

danielsz16:02:25

@onetom: Possible. Do you want to make an alternate suggestion?

micha16:02:34

how does boot.core/rm collide?

micha16:02:59

@onetom: you can do this:

jethroksy16:02:13

if you want to access reloaded.repl/system you could require it in the boot.user namespace

micha16:02:22

(task-options!
  repl {:init-ns 'some.other.namespace})

micha16:02:33

in your build.boot

micha16:02:37

the boot.user namespace was created because the user namespace has special significance in clojure, and referring in vars makes it possible to use many tasks without a build.boot

onetom16:02:46

i know how to change to other ns, that was not the question

onetom17:02:28

@jethroksy: i had to NOT [system.boot :refer [system]] just so I can [reloaded.repl :refer [system]] but it makes my dev boot task look a bit unorthogonal:

(comp
    (environ :env {:http-port 3001})
    (watch :verbose false)
    (system.boot/system :sys #'sys/dev-system
                        :hot-reload true
                        :auto-start true)
    (repl :server true))

onetom17:02:10

i see this unorthogonality as a sign of something being wrong...

jethroksy17:02:43

I too use daniel's system

mobileink17:02:44

@micha: Hmm, I'm inclined to prefer a global :target-path. What happens if I want to use it in another task defn?

micha17:02:00

@mobileink: then you can define a var:

jethroksy17:02:21

didn't have a problem with that though

micha17:02:40

(def target-path #{"foop"})
(task-options!
  target {:dir target-path})
...

onetom17:02:11

@jethroksy: i would be curious to see how does your build.boot look like then 😕

micha17:02:15

@mobileink: using the env as a namespace isn't a good way to do it

jethroksy17:02:32

this is not an issue with boot either way, it's the inconvenient naming of system and reloaded.repl

micha17:02:34

if you want a var you can reference you can make one in boot.user or any namespace

mobileink17:02:22

@micha: ah, makes sense when you put it that way. IOW prefer genuine namespaces over the env.

jethroksy17:02:23

sorry i don't have my code with me right now

micha17:02:12

@mobileink: yeah, if we have the env being like a databag of configuration options we will soon end up with all tasks tightly coupled to it, and you end up with a leiningen type project map

onetom17:02:18

@jethroksy: i agree. unfortunate naming. i dont have any better idea though... and i didnt say it's boot's problem. i was just asking why is it good to start the repl in boot.user...

micha17:02:54

@mobileink: the alternative is to pass options to tasks via their constructors (when you build the pipeline) and via the fileset

micha17:02:12

which is more functional because the names are scoped lexically then

onetom17:02:15

since when im developing MY app, i don't really need boot facilities... or do I?

micha17:02:22

instead of having a global bag of data

micha17:02:20

@onetom: the repl task needs some default, and boot.user is created for that purpose. Otherwise what namespace could the repl choose to start in?

micha17:02:43

you can make a different repl default namespace via task-options! in your build.boot

mobileink17:02:29

@micha: glad I asked! I just finished implementing a rough version of boot-gae that uses a big :gae map in the global set-env! it works, but like a lot of the implementation I'll have to work on it a bit to make it act like a real boot lib.

jethroksy17:02:37

You could require reloaded.repl and rename system to sys or something to prevent clashes

onetom17:02:08

@micha: my question is, what do i lose - which i miss badly - if i pick some other namespace instead? i won't miss the various boot tasks because i dont need that in my dev repl since im not developing boot itself

micha17:02:53

@onetom: you don't lose anything, the repl will just start in your namespace

onetom17:02:56

@jethroksy: i can hack around, i know, but that would just confuse my colleagues, so it's not acceptable

jethroksy17:02:13

it's not a hack

micha17:02:22

@onetom: nothing else will be affected other than the repl task

jethroksy17:02:32

I forgot what the equivalent of :rename is without the ns macro

jethroksy17:02:44

but i think it's perfectly reasonable

onetom17:02:07

;;; Copied from boot-test:
;;; This prevents a name collision WARNING between the test task and
;;; clojure.core/test, a function that nobody really uses or cares
;;; about.
(if ((loaded-libs) 'boot.user)
  (ns-unmap 'boot.user 'test))

(require
  '[reloaded.repl :refer [system start stop go reset]]
  '[sys]
  '[danielsz.boot-environ :refer [environ]]
  '[system.boot]
  '[zilti.boot-midje :refer [midje] :rename {midje test}])

onetom17:02:15

i already have such a mess

onetom17:02:30

im asking these questions because i would like to have cleaner defaults

micha17:02:51

if you make your own namespace you can set it up how you like it without needing to unmap anything

onetom17:02:11

@micha: sure, except i should exclude it from production, no?

onetom17:02:31

should i have an extra source dir just for that purpose?

micha17:02:31

if you want, but i don't see any real need to

micha17:02:46

one more clojure source file isn't going to break anything

onetom17:02:56

well, it might do some dev-env specific initialization, print some shit, etc

micha17:02:14

yeah you just don't require that namespace in your production entrypoint

onetom17:02:33

what it does for sure, is it slows down startup, if i pull in convenience libraries...

onetom17:02:58

hmm... it still gets compiled though 😕

micha17:02:17

not sure why it would get compiled if you don't require it

mobileink17:02:36

@micha: regarding boot.user, is it guaranteed that symbols defined in build.boot will always be in the boot.user namespace?

micha17:02:23

@mobileink: you can do boot -vb in a directory that has a build.boot file, and see the generated boot.user namespace source

micha17:02:44

it will have comments showing where parts of it came from

onetom17:02:47

@micha good question... i think im getting confused because boot-test and midje was requiring everything somehow

mobileink17:02:04

So instead of requiring that the user put :gae in set-env!, I can require that build.boot must contain a (def gae {...}) and I can always get it at boot.user/gae. Yeah?

micha17:02:34

hmm that sounds strange

micha17:02:44

can you show an example of what you have now?

micha17:02:05

the normal task options don't work for your use case?

micha17:02:14

that's normally how tasks are configured

jethroksy17:02:18

@mobileink: I think environment variables would be nice in profile.boot

jethroksy17:02:35

I do all my environ stuff there

mobileink17:02:47

gimme a sec and I'll make my test app available on github

onetom17:02:50

@micha: they might work. i will prep some minimal examples, but as a preview, imagine this: src/user.clj has (println :running-user.clj) when i run boot watch midje, i see:

:running-user.clj
Starting pod...

Starting file watcher (CTRL-C to quit)...

Running tests...

======================================================================
Loading (route53 utils route53-test system.components.route53 datomic.mock system.components.adi schema admin admin-test systems user)
:running-user.clj
All checks (8) succeeded.
[Completed at 01:19:54]

Elapsed time: 3.659 sec

onetom17:02:52

and i've experienced similar "eager loading" with boot-test iirc

onetom17:02:13

i don't want my test suite load this file

micha17:02:29

you can configure boot-test to ignore certain namespaces

micha17:02:39

you can do that in a number of different ways

micha17:02:04

there are whitelists, blacklists, there is a filter function you can supply

nberger17:02:07

@onetom I remember having to deal with midje requiring everything... It was one of the reasons I removed midje from that project

micha17:02:07

maybe more

onetom17:02:59

@nberger: thanks for the acknowledgement

onetom17:02:07

@nberger: what do u use instead of midje?

jethroksy17:02:57

I use expectations

onetom17:02:59

@micha: thanks for the thoughts! i will ponder more about it.

jethroksy17:02:38

but i've never had the need for a user.clj

jethroksy17:02:47

so I can't confirm that you won't face the same problem

nberger17:02:39

@onetom I use clojure.test

onetom17:02:57

@nberger: can u recommend any libs which help a, verifying more complex return values? b, mocking?

mobileink17:02:31

@jethroksy: what goes in profile.boot? the wiki just says scripts. Clojure code?

jethroksy17:02:12

any clojure code

jethroksy17:02:38

i define my stuff inside: (def token "foo")

jethroksy17:02:56

try adding something like that inside, and run boot -vb

micha17:02:06

@onetom: expectations is really nice for verifying complex return values

onetom17:02:10

@micha: i was making this little protocol so i can create a minimal mock route53 stuartsierra component for my very specific use case:

(ns system.components.route53
  (:require [amazonica.aws.route53 :refer :all]
           [com.stuartsierra.component :as component]))

(defprotocol IRoute53
  (ls [this])
  (ch [this action host ips]))

(defn add [this host ips]  (ch this :upsert host ips))
(defn rm [this host ips]  (ch this :delete host ips))
when i wanted to try it on the repl, i got:
(use 'system.components.route53)
java.lang.IllegalStateException: rm already refers to: #'boot.core/rm in namespace: boot.user
and it happened with other functions too which are only useful within build.boot itself but not in a repl where i want to talk about my app itself

mobileink17:02:38

The strategy is to use boot to do all the config stuff. So instead of maintaining web.xml and appengine-web.xml, you put the config stuff in the :gae map and boot-gae does the right thing.

nberger17:02:21

@onetom sound like good discussion starters for #C08LK2DH7 :). Anyways, I like juxt/iota but perhaps you have really complex return values. And for mocking I try to survive with with-redefs

jethroksy17:02:39

shrubbery is good for mocking

mobileink17:02:50

This means I need to access the config map from different tasks. As an example, the config data used to generate web.xml is also used to generate the clojure file that is aot compile to create the servlet bootstrap class files.

mobileink17:02:46

I could make a bunch of the config map specific to task, but I'll admit it, I'm lazy.

mobileink17:02:45

Plus I think that would be an additional burden on the user. Having to figure out which config data goes with which task. Maybe better to just have one config map and let boot figure out which data are used by which task.

onetom17:02:47

@nberger: ah, #C08LK2DH7! sweet; i was not aware of it. i see u created it simple_smile https://github.com/juxt/iota <= wow, thx!

jethroksy17:02:40

@mobileink: you could just (def gae {:foo "bar"}) instead of putting it in set-env!

mobileink17:02:55

the namespace for profile.boot is also boot.user? that would work, i reckon.

jethroksy17:02:25

stuff in profile.boot gets added before your build.boot stuff

onetom17:02:33

what i liked about boot-midje is it's reloading is hyper fast. can't tell the same about boot-test, even though it warms up pods in advance... but im will revisit all these now that i got a better grasp on component and system and datomic forking.

jethroksy17:02:26

notice the ;start local profile

jjttjj17:02:50

is the lack of a "target" directory due to me being on windows or is that the norm for boot 2.6.0-SNAPSHOT ?

mobileink17:02:22

@jethroksy: got it, thanks. I also see ;; start global profile in my boot -vb , from ~/.boot/profile.boot. now its making sense.

onetom18:02:09

@jethroksy: thanks a lot for your b.b file! (that's what i type in intellij to find build.boot simple_smile

onetom18:02:24

it looks like some modern smiley simple_smile

danielsz19:02:39

Use weavejester's. Mine has been merged there, and from now on weavejester's is the official one.

onetom19:02:07

thx. maybe yours could/should mention this, no?

danielsz19:02:58

Yes, PRs welcome by the way.

danielsz19:02:28

@onetom: Awesome. Thanks!

onetom19:02:49

micha, just for the record, here is another name collision in boot.user:

(let [{:keys [db r53] :as u} (-> (systems/mock) component/start)]
  (ls r53))

java.lang.IllegalArgumentException: No implementation of method: :ls of protocol: #'boot.tmpdir/ITmpFileSet found for class: system.components.route53.MockRoute53

micha19:02:40

yes, boot.user refers all the vars in boot.core and boot.util

richiardiandrea19:02:40

Hello! Is there a :injections key in boot? a way to have simbols in clojure.core similar to -> https://github.com/zcaudate/vinyasa#installation ?

micha20:02:41

you can just put them in your boot.profile

micha20:02:37

you have access to the intern function

micha20:02:04

(intern (the-ns 'clojure.core) something)

micha20:02:30

no need for a framework for that simple_smile

richiardiandrea20:02:44

I wonder why I was thinking of some other magic

richiardiandrea20:02:05

probably because is Sunday morning 😄

bendy20:02:03

noobie question for y’all - I’m working on a boot task to port over postcss & css modules. The latter localizes css so .foo {…} becomes .file__foo___hash {…} and then gives you a json file with something like {“foo”: “file__foo___hash”}

bendy20:02:33

I’ve got most of it working, I’m just trying to tie it all together. The question I have now is what would be the most appropriate way to retrieve that mapping in a clojurescript/clojure file? I’m thinking I would have to make a json/edn file in the boot task and add it to the classpath..? Maybe that’s a thing maybe it’s not

bendy20:02:03

I’m sure I could hack something together I just want to try and get it to work ‘the clojure way ™️simple_smile

micha20:02:29

@bendy: i recommend making an edn file and add it to the classpath

micha20:02:40

then you have a macro you can use in cljs to read the file

richiardiandrea20:02:42

yes edn is the easiest way

micha20:02:03

so when you compile your cljs program it will have access to the edn data, in a cljs namespace

micha20:02:45

(def the-css-mappings (extract-css-module-edn 'module-name))

richiardiandrea20:02:21

I don't know exacly the processing pipeline but if you have just a simple string to add to your processed file you can add metadata to a TmpFile and that's it

bendy20:02:46

awesome, so my thinking was correct, that’s a good start. unfortunately I have no idea how to do that. Does anyone have any resources that come to mind, or examples of (simpler preferably) tasks that add files to the class path at least?

bendy20:02:06

I’m sure I good google around, but thought I’d ask while y’all are here

richiardiandrea20:02:47

any Clojure data structure can be dumped with pr-str

richiardiandrea20:02:18

(edn/read-string (slurp "your.edn")

bendy20:02:04

ah sorry I meant adding somethign to the class path in a boot task

micha20:02:15

pre1 is the template you'll probably want to use

richiardiandrea20:02:41

oh ok, there is boot.core/add-resource I guess you can use that

micha20:02:42

in the let binding in that example you would allocate a temporary directory in which you create your edn file

micha20:02:49

like this

bendy20:02:02

ah perfect, I’ll take a look at add resource

bendy20:02:18

I’m assuming commit!ing a fileset doesn’t add anything to the calsspath, right?

richiardiandrea20:02:19

(but wait, micha knows better :D)

bendy20:02:47

haha I’m all ears simple_smile

micha20:02:48

(deftask pre1
  [...] ; task args
  (let [tmp (tmp-dir!)]
    (with-pre-wrap [fileset]
      (let [edn (compute here)]
        (spit (io/file tmp "thing.edn") (pr-str edn))
        (-> fileset (add-resource tmp) commit!)))))

richiardiandrea20:02:51

commit! just does what it says...it commits you changes

richiardiandrea20:02:04

ok that's what you want 😄

micha20:02:11

well something like that

micha20:02:20

you can get more involved from there

micha20:02:23

make more files, etc

micha20:02:42

the main idea is that your task makes a boot-managed temp dir where it puts the files it creates

micha20:02:48

boot will clean that up for you etc

micha20:02:00

your task writes files to that directory

micha20:02:17

then at the end you add the directory to the fileset the previous task passed to your task

micha20:02:27

and you return that to pass it to the next task

micha20:02:41

the fileset is like a mini git repo or something

micha20:02:03

you can add things to it, then commit to sync the working set with the filesystem

bendy20:02:08

ok, cool, that all makes sense!

bendy20:02:10

super helpful

micha20:02:15

you need to do that before you pass the fileset to the next thing

bendy20:02:27

only thing I’m still unclear on from your example is what the namespace name would be?

micha20:02:40

namespace name for what?

bendy20:02:58

you create a tmp-dir, create a file in that dir

bendy20:02:00

and oh nevermind

bendy20:02:06

I just figured it out by typing it

bendy20:02:09

silly question

micha20:02:28

when you add a temp dir to the fileset the files in it are added relative to the temp dir root

micha20:02:47

like in the example you'd have thing.edn on the classpath

bendy20:02:07

yeah, I was thinking tmp-dir was one level lower, and then you would have tmp-dir.thing in the classpath

micha20:02:12

if instead you did like (spit (io/file tmp "css-modules" "thing.edn") ...

bendy20:02:18

but I realized thats not the case

micha20:02:22

you'd have css-modules/thing.edn on the classpath

bendy20:02:38

yeah, perfect

bendy20:02:57

great! I’m excited. this was super helpful!

micha20:02:13

later when you get that working you can do fileset diffing to cache your work and avoid recomputing things that don't need to be recomputed

micha20:02:55

oh right, presumably the output edn depends on some file that was generated in a previous task?

bendy20:02:57

yeah, I’m going to have to figure out quite a bit of that, because I decided to run postcss (js) in nashorn instead of requiring a node env

bendy20:02:17

and I know there’s a bunch of ways to speed that up, but that’s a problem for future me

micha20:02:48

yeah many things can be done, don't worry

micha20:02:25

i do syntax highlighting with pygments in jython, which is similar

bendy20:02:42

haha well I’m sure I’ll be posting back in one of these channels when I come across that!

bendy20:02:31

out of curiosity, did you have to work around any node libraries (fs, path) or async js (promises, callbacks)?

micha20:02:51

i work on some nodejs apps at work

bendy20:02:03

sorry, work around any of those in nashorn

micha20:02:11

oh, sorry

micha20:02:15

haven't done that

bendy20:02:30

alright, no worries!

bendy20:02:44

I worked around them and got nashorn to do everything I needed it to

micha20:02:49

there is a thing i was researching at one point

micha20:02:57

a nodejs environment in nashorn

bendy20:02:59

but I’m just curious how other people would approach those problems

micha20:02:00

parsec or something

bendy20:02:05

avatar-js?

micha20:02:08

i forget exactly what it was called

micha20:02:11

oh yeah that's the one

bendy20:02:30

yeah, it doesn’t seem to have been maintained

micha20:02:52

lol emscripten compile nodejs and run that in nashorn

bendy20:02:01

95% of node I run across in OSS js projects though is path and fs.readFileSync which I think can both easily be polyfilled

bendy20:02:14

emscripten?

micha20:02:27

that thing that compiles C -> JavaScript

bendy20:02:42

oh hahaha

bendy20:02:04

I’m just being a nub/lazy and browserifying any builds

bendy20:02:15

¯\(ツ)

bendy20:02:25

get’s the job done!

bendy20:02:18

anyways I got to jet but thanks a bunch! I’ll tackle it tonight simple_smile