Introducing Boot v2 with a streamlined CLJS workflow

879 views
Skip to first unread message

Micha Niskin

unread,
Nov 3, 2014, 3:40:58 PM11/3/14
to clo...@googlegroups.com
Hi!

Boot (http://github.com/boot-clj/boot) is a build tool for Clojure. We've pulled together lessons learned from a year or so using boot v1 in production and are now getting ready to release v2. To show what boot can do we present a very streamlined and awesome boot-based ClojureScript development workflow (http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/). 

Try it out, maybe you'll like it! We're hoping to get some feedback before committing to a stable release, so please if you have any comments or questions we'd be happy to hear them. Have fun!

Laurent PETIT

unread,
Nov 3, 2014, 5:36:07 PM11/3/14
to clo...@googlegroups.com
Tongue in cheek question: if Leiningen were the maven of clojure, would you say boot2 is gradle ? :-)
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Laurent Petit

Laurent PETIT

unread,
Nov 3, 2014, 5:46:08 PM11/3/14
to clo...@googlegroups.com
And more seriously, I remember reading that you put an emphasis on removing the need to use a clean task. 
If I'm right, then I'd be interested in knowing how one is encouraged / helped to pursue this good property in its own tasks ?


--
Laurent Petit

Micha Niskin

unread,
Nov 4, 2014, 8:00:00 PM11/4/14
to clo...@googlegroups.com

Hi, sorry for the late reply! Boot pretty much takes care of that part for you, as long as you follow a few basic rules (I will be adding a “how to be a good citizen of the boot-o-sphere” section to the wiki on github soon):

  1. Tasks don’t fish around in the filesystem directly to find things to compile or otherwise operate on. Instead, tasks use functions in boot.core that return immutable sets of java.io.File objects from boot-managed temp directories. These functions present a sort of overlay filesystem with files in anonymous temporary directories. This allows tasks to be completely decoupled from the filesystem layout. Additionally, this makes it possible for boot to shuffle files around and use hardlinks and such to craft the classpath and the build fileset in different ways during the build cycle. In this way boot can emulate immutability and lexical and dynamic scope for things on the filesystem.

  2. Tasks don’t create files in the filesystem directly. Instead, tasks use functions in boot.core that create various flavors of anonymous, boot-managed temp directories (the ones mentioned in item 1, in fact). An important concept in boot is that the output of any task is part of the input for the next task in the pipeline. This is the property that supports the amazing composition of tasks that is possible with boot, without needing to generate miles of boilerplate configuration.

  3. The boot-managed temp directory lifespan is one build session only. This means one JVM, basically. The temp directories are stored in the .boot directory in the project root. The next time you run boot it cleans out any old temp dirs in there (they are not cleaned up on exit because you may want to look in them if something goes wrong with the build; stack traces could be referencing source files in these temp dirs).

  4. The only directories that boot knows about that are not temp dirs it created are the ones you specify in the build.boot file via set-env! (i.e. the :src-paths, :rsc-paths, and :tgt-path keys). The source and resource paths are not molested by boot in any way (no files in there are ever deleted, moved, modified etc.). The target directory, on the other hand, is completely owned by boot—boot will overwrite files or delete them in there as it sees fit. Boot ensures that the target directory always contains only those files the build process emits for that specific run, and doesn’t allow any stale files to hang out in there.

What this all means is that there is something of a tradeoff: boot never persists files that could become stale, so there is no need for a clean task, but on the other hand some things then need to be rebuilt instead of just hanging out in the target dir. We think this is an okay tradeoff because boot’s composition capabilities make it really easy to incrementally run any build process at all using the built-in watch task. In return you get 100% deterministic builds.

We’ll be talking about the details of the whole temporary filesystem machinery soon. Have fun playing with boot!


--
Micha Niskin

You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/YAckwMSfZkY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

Laurent PETIT

unread,
Nov 5, 2014, 4:43:27 PM11/5/14
to clo...@googlegroups.com
Thanks Micha for the detailed explanation !

I started following the cljs example, but am stuck right after having launched the first boot command: I don't see file target/index.html

The command and output look like this (launched from the boot-cljs-example folder):

$ boot watch speak cljs-repl cljs -usO none reload
Retrieving tagsoup-1.2.1.jar from http://clojars.org/repo/
Retrieving enlive-1.1.5.jar from http://clojars.org/repo/
Retrieving jsoup-1.7.2.jar from http://repo1.maven.org/maven2/
Retrieving args4j-2.0.16.jar from http://repo1.maven.org/maven2/
Retrieving protobuf-java-2.4.1.jar from http://repo1.maven.org/maven2/
Retrieving clojurescript-0.0-2080.jar from http://repo1.maven.org/maven2/
Retrieving closure-compiler-v20130603.jar from http://repo1.maven.org/maven2/
Retrieving google-closure-library-0.0-20130212-95c19e7f0f5f.jar from http://repo1.maven.org/maven2/
Retrieving google-closure-library-third-party-0.0-20130212-95c19e7f0f5f.jar from http://repo1.maven.org/maven2/
Retrieving tools.reader-0.8.0.jar from http://repo1.maven.org/maven2/
<< started reload server on ws://localhost:8090 >>
Starting file watcher (CTRL-C to quit)...

nREPL server listening: 0.0.0.0:50352
Compiling main.js...
Adding <script> tags to html...
Elapsed time: 21,489 sec


Laurent PETIT

unread,
Nov 5, 2014, 5:07:04 PM11/5/14
to clo...@googlegroups.com
Alternatively, if I follow instructions from https://github.com/adzerk/boot-cljs-example ,

then there's no mention of target/index.html, so I directly jump to http://localhost:3000/ but I get an HTTP 404, so same problem there I think.

command is different than from the blog post:

$ boot serve -d target/ watch speak cljs-repl cljs -usO none reload
Retrieving ring-jetty-adapter-1.3.1.jar from http://clojars.org/repo/
Retrieving ring-core-1.3.1.jar from http://clojars.org/repo/
Retrieving clj-time-0.6.0.jar from http://clojars.org/repo/
Retrieving crypto-random-1.2.0.jar from http://clojars.org/repo/
Retrieving crypto-equality-1.0.0.jar from http://clojars.org/repo/
Retrieving ring-servlet-1.3.1.jar from http://clojars.org/repo/
Retrieving compojure-1.2.1.jar from http://clojars.org/repo/
Retrieving clout-2.0.0.jar from http://clojars.org/repo/
Retrieving instaparse-1.3.4.jar from http://clojars.org/repo/
Retrieving medley-0.5.3.jar from http://clojars.org/repo/
Retrieving ring-codec-1.0.0.jar from http://clojars.org/repo/
Retrieving tools.reader-0.8.1.jar from http://repo1.maven.org/maven2/
Retrieving commons-fileupload-1.3.jar from http://repo1.maven.org/maven2/
Retrieving jetty-server-7.6.13.v20130916.jar from http://repo1.maven.org/maven2/
Retrieving javax.servlet-2.5.0.v201103041518.jar from http://repo1.maven.org/maven2/
Retrieving joda-time-2.2.jar from http://repo1.maven.org/maven2/
Retrieving jetty-continuation-7.6.13.v20130916.jar from http://repo1.maven.org/maven2/
Retrieving jetty-http-7.6.13.v20130916.jar from http://repo1.maven.org/maven2/
Retrieving jetty-io-7.6.13.v20130916.jar from http://repo1.maven.org/maven2/
Retrieving jetty-util-7.6.13.v20130916.jar from http://repo1.maven.org/maven2/
Retrieving tools.macro-0.1.5.jar from http://repo1.maven.org/maven2/
Retrieving commons-codec-1.6.jar from http://repo1.maven.org/maven2/
<< started reload server on ws://localhost:8090 >>
2014-11-05 22:59:51.865:INFO:oejs.Server:jetty-7.6.13.v20130916
2014-11-05 22:59:51.928:INFO:oejs.AbstractConnector:Started SelectChann...@0.0.0.0:3000
<< started web server on http://localhost:3000 (serving: target/) >>
Starting file watcher (CTRL-C to quit)...

nREPL server listening: 0.0.0.0:50475
Compiling main.js...
Adding <script> tags to html...
Elapsed time: 21,374 sec

--
Laurent Petit

Alan Dipert

unread,
Nov 5, 2014, 6:28:54 PM11/5/14
to clo...@googlegroups.com
Hi Laurent,
The boot-cljs-example has started to move ahead of the blog post, and includes an optional 'serve' task.

There was a bug in the boot-cljs task that was deleting index.html erroneously; I pushed a new version and updated boot-cljs-example.

If you `boot -u` to update boot (which was also updated today) and fetch latest from boot-cljs-example, there's a decent chance it will actually work :-)
Alan

--
Micha Niskin


For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
Laurent Petit



--
Laurent Petit

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/YAckwMSfZkY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Laurent Petit



--
Laurent Petit

Laurent PETIT

unread,
Nov 6, 2014, 4:13:55 AM11/6/14
to clo...@googlegroups.com
yes, it's working now, thanks


For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Laurent Petit

Henrik Eneroth

unread,
Nov 6, 2014, 12:31:13 PM11/6/14
to clo...@googlegroups.com
Hello Micha!


I'm trying to tuck Reagent in there to take it for a spin, and it seems reluctant to comply:

boot -d reagent/reagent:0.4.3
java.lang.NullPointerException:
             boot.main/dep-ns-decls  main.clj:   36
boot.main/export-task-namespaces/fn  main.clj:   49
                clojure.core/map/fn  core.clj: 2557
                                ...
                   clojure.core/seq  core.clj:  133
                 clojure.core/apply  core.clj:  624
                clojure.core/mapcat  core.clj: 2586
                                ...
   boot.main/export-task-namespaces  main.clj:   51
                    boot.main/-main  main.clj:  111
                                ...
                   boot.App.runBoot  App.java:  217
                      boot.App.main  App.java:  309


Any feedback on what I (or it) may be doing wrong?


Thanks!

Henrik

Micha Niskin

unread,
Nov 6, 2014, 2:30:55 PM11/6/14
to clo...@googlegroups.com
Hi Henrik,

You found a bug! We just fixed it though. Boot was confused by `reagent/reagent` when it tried to match that against the artifact ids returned by Pomegranate, because Pomegranate collapses it to just `reagent` in that case. If you do `boot -u` you should be updated to boot version `2.0.0-pre20`, and your command line will work.

Henrik Eneroth

unread,
Nov 6, 2014, 5:50:14 PM11/6/14
to clo...@googlegroups.com
Thanks for looking into it, Micha! 


I'm getting -pre19 with boot -u, though. Did you forget to cut a release or should I set BOOT_CHANNEL to dev?

Micha Niskin

unread,
Nov 6, 2014, 6:11:25 PM11/6/14
to clo...@googlegroups.com

I don’t understand why Aether isn’t finding -pre20 via the coordinates [boot "RELEASE"]. I can see the jar file and pom in the repo: https://clojars.org/repo/boot/boot/2.0.0-pre20/. Do you have any idea why Pomegranate wouldn’t be fetching that? Is there some subtlety of the sorting order that I’m missing, do you think?

Micha Niskin

unread,
Nov 6, 2014, 6:13:01 PM11/6/14
to clo...@googlegroups.com

Does adding BOOT_CHANNEL=DEV boot -u do the trick? (We aren’t pushing snapshots currently so it should be the same…in theory.)

Micha Niskin

unread,
Nov 6, 2014, 6:18:41 PM11/6/14
to clo...@googlegroups.com

It looks like Clojars is doing what I thought it would do: https://clojars.org/repo/boot/boot/maven-metadata.xml

<release>2.0.0-pre20</release>

Henrik Eneroth

unread,
Nov 7, 2014, 4:16:05 AM11/7/14
to clo...@googlegroups.com
I tried now, just running boot -u, and it worked perfectly. It's was probably some caching thing with Clojars. Currently at pre21

Now the command runs without errors, but it also doesn't seem to do all that much.

Running 
> boot -d reagent/reagent:0.4.3
gives the exact same output as running 
> boot -h
currently.

Laurent PETIT

unread,
Nov 7, 2014, 6:01:14 AM11/7/14
to clo...@googlegroups.com
Really looking forward to a couple more blog posts:

- an instructive / provocative one which could be named after "how to replace leiningen with boot 2". Would be very practical, showing how all major usecases done with lein translate to boot.
- an tutorial / documenting one on how to write new task and be good citizens of boot (what to do, what not to do, and then how)

:-)


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Laurent Petit

Henrik Eneroth

unread,
Nov 7, 2014, 6:46:48 AM11/7/14
to clo...@googlegroups.com
Agreed, because it seems like a good tool. :-)


On that vein; what's the syntax for add-src? 

I'm trying to include helper.cljs in the project, a file with a bunch of convenience functions that I use. However, I get the following error:

<< stopping Jetty... >>             clojure.lang.ExceptionInfo: clojure.lang.ExceptionInfo: Could not locate helpers__init.class or helpers.clj on classpath:  at line 1  {:tag :cljs/analysis-error, :file nil, :line 1, :column 1}

It seems enamoured with the idea that the file should end with ".clj". I'm guessing that boot has to be told of the existence of the file, but I'm not sure how to do this. For the purposes of this experiment, the namespace of helpers.cljs is simply (ns helpers).

Micha Niskin

unread,
Nov 7, 2014, 10:22:35 AM11/7/14
to clo...@googlegroups.com

Henrik, the -d option simply adds dependencies to the project. The main use case for this option is to pull in dependencies when you have no formal “project” and no build.boot file. Mainly it’s used in concert with the repl task so you can quickly and easily try something out:

$ boot -d aysylu/loom repl
boot.user=> (use 'loom.graph)
nil
boot.user=> (graph [1 2] [2 3] {3 [4] 5 [6 7]} 7 8 9)
...

However, if a dependency pulled in via -d (not transitive deps) contains namespaces in which tasks are defined, these namespaces may be tagged with ^:boot/export-tasks metadata. Boot will find these namespaces and refer all public vars into your build.boot environment.

So if the reagent jar contained task namespaces you should see them when you do

$ boot -d reagent

Note that you don’t need to supply the group-id for reagent, and if you want the latest release you can also omit the version.


--
Micha Niskin

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/YAckwMSfZkY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

Micha Niskin

unread,
Nov 7, 2014, 10:25:51 AM11/7/14
to clo...@googlegroups.com

Oh, I forgot to say, the ^:boot/export-tasks convention makes boot into a sort of application container. You can use boot to pull code from the internet and run it. This is really nice when combined with Docker, for example, but I’m sure we haven’t even found the coolest uses for this yet. We’re pretty excited about this aspect of boot in particular and would love to see how people find ways to use it in their workflows.


--
Micha Niskin

Henrik Eneroth

unread,
Nov 7, 2014, 10:26:21 AM11/7/14
to clo...@googlegroups.com
Gotcha! Thanks!

Micha Niskin

unread,
Nov 7, 2014, 11:00:10 AM11/7/14
to clo...@googlegroups.com

Henrik, can you make a github repo with what you were trying to do in your second question? It would help to be able to see your whole setup.

The add-src task is perhaps confusingly named (Names Are Hard). Its purpose is to shuffle files around in the file set, moving files that would normally be considered “source” files into the stream of artifacts that end up being packaged. It’s roughly equivalent to setting Leiningen’s :omit-source key to false (but it’s a composable task, not a global setting).

I’ll try to explain how this works. To model all the filesystem side effects that building software entails we must establish some types of files, aligned along some basis of user intent. We ended up with two categories: input and output files (again, Names Are Hard, so please bear with me).

  • input – files that MUST be processed further before being packaged or emitted to the project target directory (eg. Java source files, CLJS source files, etc.)

  • output – files that MAY be processed further, but can be included in the packaged artifact or emitted to the project target directory (eg. compiled JavaScript, Java bytecode, etc.). Note that this also includes files that might pass through the build system completely unmolested to end up in the final result, like your index.html file for instance. These are also called “resources” in Java parlance, I believe.

A major concept in boot has that the output of a task is always part of the input of subsequent tasks. Tasks shouldn’t know or care what is to be done to the artifacts they emit; they shouldn’t know or care who or what might be further processing them. Thus, both input and output files are on the classpath. This means that both types serve as input for tasks, which is, I admit, somewhat confusing.

When you set up your environment in boot you use the :src-paths and :rsc-paths arguments to set-env!. The :src-paths denote input dirs, :rsc-paths output dirs.

This brings us to tempdirs. Tasks that emit files do so in anonymous temp dirs they obtain from boot core. These temp dirs come in a few flavors, but there are two main classes of temp dir a task may create: input or output, naturally. The choice is left to the task writer, who decides based on his intent. For example, the cljs-repl task emits a CLJS namespace containing the websocket connection code the client needs to run to connect to the REPL server. This namespace is emitted into an input type temp dir. Thus the CLJS namespace is compiled into the application JS file, but the CLJS source does not appear in the app webroot.

Finally, we arrive at add-src. This task creates a temp dir of the output type. It then obtains a list of input type files from boot core and moves them into this dir. Then when the jar task for example runs later in the pipeline, these source files will be included in the jar.

I’m not sure how clear this is, I’m trying to figure out the best way to explain this stuff and this is one of the first iterations :)


--
Micha Niskin

You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/YAckwMSfZkY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

Laurent PETIT

unread,
Nov 7, 2014, 12:15:55 PM11/7/14
to clo...@googlegroups.com
Just to check that I correctly understood the concepts :

- it's upfront, in the task itself, that the decision of whether what the task produces is of type "input" or "output".
- flagging part of its output as "input" type is a way to declare to boot that the files there MUST be processed further, at some point, or else there's an error somewhere?

- the granularity of input / output files is the directory (it's at the directory level that content is flagged as "input" or "output"). Is it recursive (I guess so), for subdirectories of the tagged directory?

- add-src somehow pipelines some files tagged as "input" in the input of the task as "output" for the rest of the pipeline, thus ensuring those files will reach the target/ directory (and they may or may not be subsequently modified on their way to target/, this is somewhat an orthogonal concern). Right?

Some remarks (I know that Names Are Hard):
- :src-paths and :rsc-paths are already difficult to distinguish when one does not have diseases related to ordering of letters. Maybe falling back to longer names could fix this: :source-paths and :resource-paths

Cheers,

--
Laurent


Micha Niskin

unread,
Nov 7, 2014, 12:37:15 PM11/7/14
to clo...@googlegroups.com
I'll answer inline below:

On Friday, November 7, 2014 12:15:55 PM UTC-5, Laurent PETIT wrote:
Just to check that I correctly understood the concepts :

- it's upfront, in the task itself, that the decision of whether what the task produces is of type "input" or "output".
- flagging part of its output as "input" type is a way to declare to boot that the files there MUST be processed further, at some point, or else there's an error somewhere?

Tasks are "stateful transducers", which we used to call "middleware factories". Basically a function that returns middleware. The middleware can be composed to obtain a handler, like in Ring. By adding the factory level of abstraction we end up with a place to initialize local state for our handler. This is usually achieved in a let binding that wraps the middleware that will be returned, with the local state included in its closure. It is here where the task would obtain temp dirs from the boot system. The engineer writing the task is able to express their intent by choosing an appropriate type of directory.

Files in input directories do not raise exceptions if they're not processed. They just don't end up in the final product of the build. Perhaps a good name for them is something like "dev files"? These are files that are only relevant to the build process itself, basically. Boot doesn't make assumptions about what you want to do though, so there are very few things that boot itself will raise exceptions about.
 
- the granularity of input / output files is the directory (it's at the directory level that content is flagged as "input" or "output"). Is it recursive (I guess so), for subdirectories of the tagged directory?

Yes, exactly right.
 
- add-src somehow pipelines some files tagged as "input" in the input of the task as "output" for the rest of the pipeline, thus ensuring those files will reach the target/ directory (and they may or may not be subsequently modified on their way to target/, this is somewhat an orthogonal concern). Right?

Precisely. In addition it removes them from the input directories (the exact implementation is in flux right now; we'll be landing some changes here that preserve a clean class path such that there are not duplicate files in different directories) and moves them to the anonymous output directory it created.
 
Some remarks (I know that Names Are Hard):
- :src-paths and :rsc-paths are already difficult to distinguish when one does not have diseases related to ordering of letters. Maybe falling back to longer names could fix this: :source-paths and :resource-paths

Yes, I like this! Perhaps even some better way to describe these things than "source" and "resource" exists, even. I'm all ears with respect to naming conventions!

Micha Niskin

unread,
Nov 7, 2014, 12:46:14 PM11/7/14
to clo...@googlegroups.com
One thing I forgot to mention is that tasks all agree to not know or care about where any of these directories are actually located on the filesystem. Boot provides functions by which the set of files (input or output) can be obtained. The tasks, when they operate on these files, pay attention only to the path relative to the temp dir. There is a function that boot provides to resolve these relative paths. This presents a sort of overlay filesystem the tasks can operate on, so the specific places in the filesystem are decoupled from the task logic.
...

Catonano

unread,
Dec 26, 2014, 7:49:06 PM12/26/14
to clojure mailing list
Micha,

2014-11-07 16:25 GMT+01:00 Micha Niskin <micha....@gmail.com>:

Oh, I forgot to say, the ^:boot/export-tasks convention makes boot into a sort of application container. You can use boot to pull code from the internet and run it. This is really nice when combined with Docker, for example, but I’m sure we haven’t even found the coolest uses for this yet. We’re pretty excited about this aspect of boot in particular and would love to see how people find ways to use it in their workflows.


--
Micha Niskin


would you mind to expand on this ?

I'm not sure I understand what you mean and I'm especially curious about the relationship between this and Docker


Reply all
Reply to author
Forward
0 new messages