Git Product home page Git Product logo

mach's Introduction

Mach

Mach is a remake of make, striving to keep the good parts.

Design goals

  • Fast start-up (ideally sub-second)

  • Incremental builds (only do necessary work)

  • Sane language (avoid make’s horrible syntax and language features)

  • Support rules and extensibility

For the language, we have chosen ClojureScript because it is clean, consistent, expressive and powerful. Machfiles as data, using the EDN format.

Mach sits on the extensive nodejs eco-system. If you need to do anything remotely complex, feel free to pick from the quarter-million-plus modules available to you.

Status

Mach is in alpha status. You are encouraged to use it if you are prepared to accept some changes if you upgrade.

Installing Mach

Install Mach with NPM like this

$ sudo npm install -g @juxt/mach

Mach uses boot to resolve dependencies mentioned in the Machfile, so you might want to install boot-clj while your at it.

Mach ships with Lumo 1.7.0.

Getting started

Create a simple project and add a Machfile.edn file. The Machfile is a simple map, modelled in a similar fashion to the original Makefile, with targets as keys and dependencies/actions as values.

Your very first Machfile.edn might look like this:

{
 hallo (println "Guten Tag, Welt!")
}

You can invoke Mach with the following:

$ mach hallo

to get the following output:

Guten Tag, Welt!

Try it out

Clone the mach project.

$ git clone https://github.com/juxt/mach
$ cd mach/examples/app

Try the following:

$ mach target

This creates a directory called target.

Try again.

$ mach target

Since target already exists, you should get the following output:

Nothing to do!

Now try this:

$ mach css

If you have the SASS compiler installed, sassc, this will compile the sass files in sass to target/app.css.

Targets

Machfile entries have target names (the keys) and targets (actions or maps which describe when and how to build the target).

If you use a map, you can put anything you like in this map, but a few of these keys are special and are described below. Try to avoid using lowercase non-namespaced symbols, since these are reserved by Mach and some of these are discussed below.

depends

The depends entry contains a list of targets that must be updated (if stale) prior to this target being considered for update.

{jar {description "A jar file containing Java classes and CSS"
      depends [classes css]}}

A depends is simply a sequence of targets to check.

product

The product of a target is the file (or files) that it produces. If you declare this with the special symbol product it will assist the 'auto-clean' feature of Mach.

novelty

Deciding whether a target is stale (requiring a re-build) or fresh (no re-build is necessary) might be a simple procedure or a complex computation. Regardless, Mach asks you to provide a predicate, written in ClojureScript to determine whether or not a target is stale.

Mach provides a built-in predicate to determine if any files in a given directory have been modified with respect to a given file.

The signature of this function is:

(mach.core/modified-since [file dir])

The first argument is the file with which all files in the second argument (directory) are compared against. If any file in the directory has been modified more recently than the file in the first argument, the predicate returns true.

For example:

{css {novelty (mach.core/modified-since "target/app.css" "sass")}}

It is also possible to express this target like this:

{css {target "target/app.css"
      novelty (mach.core/modified-since target "sass")}}

This illustrates that symbols in ClojureScript expressions are resolved with respect to the given map, which defines the scope for all expressions. This allows you to surface key values as declarations, accessible from within local ClojureScript expressions and also exposed to other tools. These values are also accessible by other targets, via references (see below).

update!

If novelty is detected, a target is updated by calling the update! function. The terminology here is intended to align with our skip project.

The update! expression must do whatever is necessary to rebuild (freshen) the target.

{css {target "target/app.css"
      novelty (mach.core/modified-since target #ref [sass dir])
      update! (apply mach.core/sh (concat ["sassc"] novelty [">" target]))}}

In the update! expression can be side-effecting (and should be!). Often, an update! expression will reference the value of novelty to reduce work.

produce

As an alternative to update!, a target can declare a produce entry. This should produce output that is normally written to the product file.

Verbs

A target can optionally be called with a verb.

For example:

mach pdf:clean

clean

This calls the pdf target with the clean verb, which removes any files created by the target (declared in product).

update

This calls the update! (or produce) expressions, regardless of whether the target if fresh or not. No dependencies are called.

print

For targets that have a produce, this is called and output is sent to the console instead of the product.

Implicit clean

Since derived files are declared with product, Mach is able to automatically determine how to clean a target. Therefore, you don’t need to specify a special rule, conventionally called clean, to clean up derived files.

Additional Features

Calling out to the shell

One of the best design decisions in the original Make tool was to integrate closely with the Unix shell. There are countless operations that are accessible via the shell, and Mach strives to encourage this usage via its custom EDN tag literal #$.

clojure {hello-internal (println "Hello World!") hello-external #$ ["echo Hello!"]}

The #$ tag literal is a short-cut to the built-in Mach function mach.core/sh.

References

Make makes heavy use of variables, in the spirit of DRY (Don’t Repeat Yourself). Often, this leads to obfuscation, variables are defined in terms of other variables, and so on.

Mach achieves DRY without endless indirection by using references (the same way Aero does it) - key values can be declared in a target and referenced from other parts of the Machfile, via the #ref tag literal.

{
src {dir "src"}
classes {update! (compile #ref [src dir])}
}

The #ref tag must be followed by a vector of symbols which target the required value.

Using ClojureScript dependencies

You can use other ClojureScript libraries in your Machfile, for example

{
mach/dependencies [[aero "1.1.2"]]
print-config (println (aero.core/read-config "config.edn" {}))
}

The dependencies directive uses Boot to fetch Maven dependencies and to inject these dependencies directly onto the Lumo/Mach classpath. Note, Boot is only invoked when the declared dependencies vector has changed.

For this to work therefore you must have Boot installed (version 2.7.1 or above), and at least Lumo 1.3.0.

Note that Mach auto-requires namespaces, so in this example we do not need (require 'aero.core).

Add to the Lumo/Mach classpath

You can add artbitrary directories and files to the Mach/Lumo classpath using the cp literal, for example:

{
add-cp #cp "some-dir-containing-cljs"
}

Mach Extensions

Mach extensions allow us to create reusable tasks, using the mach/import directive. For example:

{
mach/import [["https://raw.githubusercontent.com/juxt/mach/master/extensions/aws.mach.edn" {profile "some-profile"}]]
}

Importing the AWS extension as above adds to Mach AWS utility targets such as 'ips' which lists the IPs of running EC2 instances. To execute this imported task, simply: mach ips.

For more examples of extensions, checkout the AWS extension for AWS utility tasks.

Aliasing Extensions

{
mach/import [["https://raw.githubusercontent.com/juxt/mach/master/extensions/aws.mach.edn" {profile "some-profile"} :as aws]]
}

The above will import all tasks under the namespace aws. From the command line you would now execute mach aws/ips.

You can also rename tasks when importing:

{
mach/import [["https://raw.githubusercontent.com/juxt/mach/master/extensions/aws.mach.edn" {profile "some-profile"} :rename ips ips2]]
}

From the command line you would now execute mach ips2.

Using local extension files

{
mach/import [[foo {}]]
}

In this case Mach will search this current directory - and also parent directories - for an extension file called foo.mach.edn. Once the extensions file is found Mach will load the extension targets. refer and rename can also be used to change the namespace/symbol of the imported target respectively.

Furthermore, any symbols in the target extension can be rewritten based on the supplied map of args. For example if the bar target was coded as such:

Acknowledgements

Mach is built on lumo by António Nuno Monteiro.

Sprichst Du Deutsch?

Since you ask, the name is from the German verb, machen (to do, to make), used in the imperative. Mach is as much about 'doing' as 'making', which the German verb captures well.

Influences

Mach is influenced by Make, particularly GNU Make, which has survived the test of time (but not without baggage).

I also looked at Jake, which is a worthy re-implementation of Make, sticking close to the original. Also, Ninja and Tup.

Paul deGrandis suggested it was a good idea to look at Mk, which has influenced the verbs and 'auto-clean' features.

Road map

The goal of Mach is to create something that is capable of building complex systems as well as running them. One option is to use Mach to generate a classpath from a project.clj (lein classpath) and use that to run Clojure applications with java directly, avoiding the use of lein and its associated memory costs. It might also be possible to make more judicious use of AOT to speed things are further - by utilising file-system dates, it is possible to detect staleness and fix it when necessary - say if a project.clj is determined to be newer then the classpath can be regenerated.

Development

To test locally set $MACH_HOME to the directory containing your local copy of this directory. If you’re in it, you can do this:

export MACH_HOME="$(pwd)"

If you have a globally installed mach, it will run the one in this directory whilst that environment variable is set.

If you have modified the bin/mach file, you will need to call it directly, as well as setting $MACH_HOME

mach's People

Contributors

agilecreativity avatar arichiardi avatar crimeminister avatar deduktion avatar jonpither avatar malcolmsparks avatar nberger avatar noonian avatar ordnungswidrig avatar severeoverfl0w avatar slipset avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mach's Issues

Cannot use output of `sh` to detect novelty

I may be misunderstanding something, but I would expect that I could call a command via sh and then use the stdout to detect novelty (my use case is using git to detect if a submodule is out of date).

However, in my testing, I can't seem to get the value of stdout after running a command.

Version: juxt/[email protected]

I've got a toy example below where I just try to print out the value of an echo.

Machfile.edn:

{
 example/example1 {novelty (do
                             (prn "result is:" (mach.core/sh ["echo" "hello"]))
                             false
                             )}

 }

Expected: The return value of sh is the value of standard out from running the "echo" command.
Actual: The return value of sh is nil.

Launch a shell repl from within mach

Hello again, again 😄 (and sorry to bother so much)

Today I tried to launch lumo straight from mach but failed. It looks like the main process shuts down as soon as the "pipeline" is done. So a task like this:

  repl {depends [js clj]
       ;; below is a temporary hack waiting for mach to include lumo.io
       update! #$ ["lumo" "-c" (.toString (js/$$LUMO_GLOBALS.fs.readFileSync "cp")) "-r"]}

prints the lumo preamble and then quits.

I know maybe mach has not designed for this purpose, but I felt I could ask your thoughts.

Feature request: Streaming Stdout/Stderr

Stream realtime stdout/stderr instead of waiting until command completion. Makes long-running tasks very opaque.

Example:

;; Machfile.edn
{foo #$ ["./test-this"]}
# test-this
#!/usr/bin/env sh

echo "Line 1"
sleep 10
echo "Line 2"

Prints nothing for 10s, instead of Line1 instantly, followed by Line2 in 10s.

Add a directive mach/require

Sometimes you need to require a namespace, even if you're not going to refer to it.

For example, you may want to require in a defmethod, extend-type, extend-protocol, clojure.spec/def etc.

Therefore it's convenient to be able to specify which namespaces must be required. This feature might one day evolve to be as feature rich as clojure.core/ns

Auto require does not always work?

Hello again folks!

I was trying this:

{
  mach/dependencies [[fipp "0.6.8"]]
  project (fipp.edn/pprint "teaee")
}

$ mach project
"teaee"

While:

{
  mach/dependencies [[fipp "0.6.8"]]
  project (-> "teaee" fipp.edn/pprint)
}

$ mach project
WARNING: No such namespace: fipp.edn, could not locate fipp/edn.cljs, fipp/edn.cljc, or Closure namespace ""
WARNING: Use of undeclared Var fipp.edn/pprint
Cannot read property 'pprint' of undefined

I did not have time to debug it today so I decided to just report it 😄

mach/props and mach/constant conflicting

Use case

Set an environment variable using mach/constant

mach/constant {environment "staging"}

You are not able to use this constant in mach/props

mach/props [config (aero.core/read-config "conf.edn" {:profile (keyword #ref [mach/constant environment])})]

This doesn't work as expected.

The reason for using mach/constant is the ability to pass in another value from the command-line with --constant '{environment "prod"}'.

Breaking build step should stop execution

If one build step breaks it should stop the build execution.
At least for shell this is broken:

Machfile.edn

{breaking
  {update! #$ ["exit" 1]}

 non-breaking
  {update! #$ ["exit" 0]}

 dependand
  {depends [breaking non-breaking]
   update! #$ ["echo" "should not be reached"]}}

mach dependand shows

$ exit 0
$ exit 1
$ echo should not be reached
should not be reached

Example can be found here: https://github.com/DomainDrivenArchitecture/dda-cloudspec/tree/master/test/mach/break_on_exit

npm install examples broken

This could well be my lumo/npm installation, but after checking out mach:

$ cd examples/npm-left-pad
$ mach pad-foo
npm installing left-pad 1.1.3
evalmachine.<anonymous>:98
throw ex;
^

Error: Cannot find module 'left-pad'
    at Function.Module._resolveFilename (module.js:489:15)
    at Function.Module._load (module.js:439:25)
    at Module.require (module.js:517:17)
    at require (internal/module.js:11:18)
    at evalmachine.<anonymous>:8:15
    at evalmachine.<anonymous>:32:43
    at cljs$user$state_machine__4__auto____1 (evalmachine.<anonymous>:53:4)
    at cljs$user$state_machine__4__auto__ (evalmachine.<anonymous>:69:46)
    at cljs$core$async$impl$ioc_helpers$run_state_machine (evalmachine.<anonymous>:90:74)
    at cljs$core$async$impl$ioc_helpers$run_state_machine_wrapped (evalmachine.<anonymous>:93:63)

lumo/npm versions:

Lumo 1.8.0-beta
ClojureScript 1.9.927
Node.js v8.5.0

mach fails with error on non-existent classpath dir

minimal Machfile.edn to reproduce the error

{mach/dependencies [[aero "1.1.2"]]
 hello (println "Hello")}

error

Writing Mach classpath to .mach/cp
evalmachine.<anonymous>:98
throw ex;
^

Error: ENOENT: no such file or directory, open '.mach/cp'
    at Object.fs.openSync (fs.js:652:18)
    at fs.readFileSync (fs.js:553:33)
    at evalmachine.<anonymous>:4299:43
    at evalmachine.<anonymous>:4346:43
    at mach$core$preprocess_dependencies_$_state_machine__4__auto____1 (evalmachine.<anonymous>:4367:4)
    at mach$core$preprocess_dependencies_$_state_machine__4__auto__ (evalmachine.<anonymous>:4383:72)
    at cljs$core$async$impl$ioc_helpers$run_state_machine (evalmachine.<anonymous>:90:74)
    at cljs$core$async$impl$ioc_helpers$run_state_machine_wrapped (evalmachine.<anonymous>:93:63)
    at evalmachine.<anonymous>:4398:67
    at Immediate.cljs$core$async$impl$dispatch$process_messages [as _onImmediate] (evalmachine.<anonymous>:16:6)

versions

  • node 8.7.0
  • mach 1.4.7
  • lumo 0.20.6

This is on OS X Sierra.

Cannot combine two conditions in novelty

Hey folks!
After conversation on Slack as well, I am opening this because it seems like the novelty key cannot accept functions (maybe, maybe there issue is something different). I have a repro here: https://github.com/arichiardi/lumo-repros

With:

novelty (fn [] (or (not (mach.core/file-exists? product))
                   (not (mach.core/modified-since product #ref [machfile]))))

This happens:

$ rm cp package.json
$ mach cp
Nothing to do!

I expect the classpath to be created (no file there).

Thanks as usual 😄

Document #import literal

Once it stabilises use the below as a basis.

Mach extension files

Currently you can add a target like this:

tar #import [foo/bar {}] 

And Mach will search this current directory - and also parent directories - for an extension file called foo.mach.edn. Once the extensions file is found Mach will load the extension targets. In the above example if foo.mach.edn contained:

bar #$ ["echo" "hello"] 

Then the target 'bar' in the extension file will be aliased to 'tar' in the main Mach file. So running mach tar from the command line would echo hello.

Furthermore, any symbols in the target extension can be rewritten based on the supplied map of args. For example if the bar target was coded as such:

bar #$ ["echo" fido]

And bar was imported as such:

tar #import [foo/bar {fido "greetings"}] 

then running mach tar from the command line would echo greetings.

Question: is there a bash abstraction?

As build steps get more complicated (at the moment I try to introduce a build-target dir in order to separate src from build artifacts) I want do modularize my bash-scripts. I think && is not enough ...

terraform-plan
  {product (str terraform-build-dir "/proposed.plan")
   update! #$ ["cd" terraform-build-dir "&&"
                      "terraform" "plan" "-out" product]

`lumo` not present in `.bin`

Repro:

  1. sudo npm install -g @juxt/mach lumo-cljs
  2. mach

Expected: Error message about missing Machfile
Actual: Error is /Users/bbrinck/.nvm/versions/node/v6.6.0/bin/mach: line 14: /Users/bbrinck/.nvm/versions/node/v6.6.0/lib/node_modules/@juxt/mach/node_modules/.bin/lumo: No such file or directory

Version info:

> node -v
v6.6.0
> npm -v
4.5.0
> npm -g ls @juxt/mach lumo-cljs
/Users/bbrinck/.nvm/versions/node/v6.6.0/lib
└─┬ @juxt/[email protected]
  └── [email protected]

Duplicate running of duplicate dependencies

In this example

 bar  (println "boo")

 tar {depends [bar]
      update! (println "boo")}

 foo {depends [tar bar]
      update! (println "SHO")}

running mach foo will lead to bar executing twice.

Require `lumo.io` for slurp

Hello again! 😄

I have noticed that there is a custom implementation for spit, but I have not found slurp and the fact that there is already a lumo.io makes me think that maybe mach could just require and take advantage of that namespace.

I tried:

(do (require 'lumo.io)
      (println (lumo.io/slurp "cp")))

...but it did not quite work

Suppress stdout

In Mach we have this tag literal #$ which does a shell from your Machfile (think Makefile) - i.e. #$ ["touch" "foo"]. It's cool.

Sometimes though you want to print the output stdout (as happens always now) but sometimes it's annoying and you want to suppress it.

Does an idiom shout out for this? For example we could add a new tag literal which is a quiet version... or change the contract of the literal to supply args... or add a Mach -v flag for verbose.

Thoughts welcome.

Exception: Your system's gstreamer libraries are out of date (we need at least 1.12).

I get this error when running the servo/servo project.

OS: OS X Mojave 10.14.5

My actual GStreamer version:

$ gst-inspect-1.0 --version
gst-inspect-1.0 version 1.16.0
GStreamer 1.16.0
Unknown package origin

mach output:

./mach run tests/html/about-mozilla.html
Error running mach:

    ['run', 'tests/html/about-mozilla.html']

The error occurred in code that was called by the mach command. This is either
a bug in the called code itself or in the way that mach is calling it.

You should consider filing a bug for this issue.

If filing a bug, please include the full output of mach, including this error
message.

The details of the failure are as follows:

Exception: Your system's gstreamer libraries are out of date (we need at least 1.12). If you're unable to install them, let us know by filing a bug!

  File "/Users/***/servo/python/servo/post_build_commands.py", line 83, in run
    env = self.build_env()
  File "/Users/***/servo/python/servo/command_base.py", line 612, in build_env
    if self.needs_gstreamer_env(target):
  File "/Users/***/servo/python/servo/command_base.py", line 560, in needs_gstreamer_env
    install them, let us know by filing a bug!")

Installing mach via instructions in readme fails

✘-127 ~/Documents/github.com/first-roll
12:02 $ sudo npm install -g @juxt/mach
/usr/local/bin/mach -> /usr/local/lib/node_modules/@juxt/mach/bin/mach

> [email protected] install /usr/local/lib/node_modules/@juxt/mach/node_modules/lumo-cljs
> node scripts/npm_install.js || nodejs scripts/npm_install.js

internal/streams/legacy.js:59
      throw er; // Unhandled stream error in pipe.
      ^

Error: EACCES: permission denied, open 'lumo_mac.zip'
sh: nodejs: command not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! [email protected] install: `node scripts/npm_install.js || nodejs scripts/npm_install.js`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the [email protected] install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/erik/.npm/_logs/2017-10-28T10_02_51_139Z-debug.log

Following tip from #47, things work:

12:03 $ sudo npm install --unsafe-perm -g @juxt/mach
/usr/local/bin/mach -> /usr/local/lib/node_modules/@juxt/mach/bin/mach

> [email protected] install /usr/local/lib/node_modules/@juxt/mach/node_modules/lumo-cljs
> node scripts/npm_install.js || nodejs scripts/npm_install.js


 Downloading [========================================] 2851270/bps 100% 0.0s

+ @juxt/[email protected]
added 132 packages in 19.268s
✔ ~/Documents/github.com/first-roll

directory as product throws exception upon completing produce step

Problem

When specifying both produce and product where the product is a directory, mach fails with the following exception:

Error: EISDIR: illegal operation on a directory, open '<YOUR_DIR>'
    at Object.fs.openSync (fs.js:652:18)
    at fs.writeFileSync (fs.js:1299:33)
    at mach$core$spit_product (evalmachine.<anonymous>:1198:35)
    at evalmachine.<anonymous>:1282:24
    at evalmachine.<anonymous>:1312:43
    at mach$core$state_machine__4__auto____1 (evalmachine.<anonymous>:1333:4)
    at mach$core$state_machine__4__auto__ (evalmachine.<anonymous>:1349:46)
    at cljs$core$async$impl$ioc_helpers$run_state_machine (evalmachine.<anonymous>:90:74)
    at cljs$core$async$impl$ioc_helpers$run_state_machine_wrapped (evalmachine.<anonymous>:93:63)
    at evalmachine.<anonymous>:112:67

This is due to https://github.com/juxt/mach/blob/master/src/mach/core.cljs#L265 calling fs.writeFileSync on the directory. I'm not really sure why this post-op is necessary.

Minimal Machfile.edn to reproduce

{
  task {
    product "some-dir"
    produce #$ ["mkdir" "-p" "some-dir"]
  }
}

Work-around

You can use update! instead of produce. I'm not sure if this is intended behavior. If that's the case, I think the docs should reflect this.

#cp - feels imperative

The #cp tag literal feels a bit too imperative - can we consider alternative solutions?

Unable to use shell return data as input to another shell task

Machfile.edn

{
  mach/props [x #$ ["echo" "test"]]
  info (println (str "This: " x))
  test #$ ["ls" "-alh" x]
  test2 #$ ["ls" "-alh" "test"]
}

Output of the commands

$ mach info
$ echo test
test
This: test

This shows that it looks like x is properly populated, however

$ mach test
$ echo test
test
$ ls -alh test
total 8
drwxr-xr-x   4 stijn  staff   136B Sep 11 14:59 .
drwxr-xr-x  11 stijn  staff   374B Sep 11 14:57 ..
drwxr-xr-x   3 stijn  staff   102B Sep 11 14:59 .mach
-rw-r--r--   1 stijn  staff   131B Sep 11 15:04 Machfile.edn

On line 4 of the output, it generates the correct command to send to the shell, but the parameter x is being ignored by the actual execution.

The output should have been what test2 returns

$ mach test2
$ echo test
test
$ ls -alh test
ls: test: No such file or directory

Missing Log-Handling

Parts like update! #$ ["terraform" "init" ">" "/dev/null"] are showing the need of some kind of log handling. As build-logs tend to contain credential informations some "Secret scrubbing hook" would be nice in addition.

As I come from the java world, I would integrate some kind of log4j - is there a good cljs or even a cljc logging solution?

destructuring in mach/props

Keys destructuring in mach/props doesn't create a globally accessible variable.

{mach/props [{:keys [datomic-user datomic-password aws-access-key aws-secret-key]} (aero.core/read-config "config.edn" {})]}

It is possible to use these local vars inside of mach/props, but not in other tasks defined in the Machfile.

execution of dependent tasks is asynchronous

It looks like dependent tasks are executed asynchronously, which violates the ordering of dependencies.

Minimal example

Machfile.edn

{
  task1 {
    product "task1.txt"
    novelty (not (mach.core/file-exists? product))
    produce #$ ["sleep" "5" "&&" "echo" "'test'" ">" product]
  }

  task2 {
    product "task2.txt"
    novelty (not (mach.core/file-exists? product))
    depends [task1]
    produce #$ ["sleep" "2" "&&" "cp" "task1.txt" "task2.txt"]
  }
}

Execute task2

$ mach task2

Output

$ sleep 5 && echo 'test' > task1.txt
$ sleep 2 && cp task1.txt task2.txt
cp: task1.txt: No such file or directory
Writing task2.txt
Writing task1.txt

Document that Aero needs to be a dependency and how to include it

I was trying mach target from the repo but it fails:

#error {:message No such namespace: aero.core, could not locate aero/core.cljs, aero/core.cljc, or Closure namespace "aero.core", :data {:tag :cljs/analysis-error}}

Probably now that the dependency is gone there will need to be a way to import it from clojars.

Thanks folks for this tool, I am going to experiment with it (on the previous tag) 😄

Use of reader literal ref unintuitive

When I use the ref literal pointing at the result of a ClojureScript expression, it doesn't work as expected. For example, what should happen in the below case:

{
config (aero.core/read-config "config.edn" {})
foo (println #ref [config :some-item])
}

Even if some-item exists in the config, the above will not print it out. This is because resolve-references happens against uneval'ed code.

Makes me think resolve-references is happening at an incorrect stage?

Do not bundle Lumo?

Need to ponder the idea of shipping Lumo with Mach, because the binary compiled download version of Mach is much faster to run (~400 ms).

"Try it out" produces a stacktrace

When following the instructions in Try it out I run the command mach target in the directory mach/examples/app and get the error message:

evalmachine.<anonymous>:98
throw ex;
^
Error: No reader function for tag ref.
    at new cljs.core.ExceptionInfo (<embedded>:1920:47)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (<embedded>:1923:72)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2 (<embedded>:1922:449)
    at Function.cljs.tools.reader.impl.errors.throw_ex.cljs$core$IFn$_invoke$arity$variadic (evalmachine.<anonymous>:53:25)
    at Function.cljs.tools.reader.impl.errors.reader_error.cljs$core$IFn$_invoke$arity$variadic (evalmachine.<anonymous>:91:47)
    at Object.cljs$tools$reader$impl$errors$throw_unknown_reader_tag [as throw_unknown_reader_tag] (evalmachine.<anonymous>:336:51)
    at Object.cljs$tools$reader$edn$read_tagged [as read_tagged] (evalmachine.<anonymous>:783:38)
    at evalmachine.<anonymous>:118:191
    at cljs$tools$reader$edn$read_dispatch (evalmachine.<anonymous>:119:3)
    at Object.cljs$tools$reader$edn$read_delimited [as read_delimited] (evalmachine.<anonymous>:320:106)

Tested on OS X: 10.9.5 with node v6.11.3 and v8.5.0

No such namespace with version 1.4.1

Hello folks!

I am receiving the following with version 1.4.1:

WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/file-exists?
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/modified-since
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/file-exists?
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/modified-since
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/file-exists?
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/modified-since
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/file-exists?
WARNING: No such namespace: mach.core, could not locate mach/core.cljs, mach/core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var mach.core/modified-since

I tried and it does not happen with 1.4.0 and master, only 1.4.1.

Hopefully just a quick new release would solve, thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.