diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 86c991bb..90f40ec0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -116,6 +116,6 @@ jobs: with: files: trunk-*/trunk-* body_path: RELEASE_LOG.md - prerelease: true + draft: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index fda209c1..28ef6f87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ changelog This changelog follows the patterns described here: https://keepachangelog.com/en/1.0.0/. ## Unreleased +- Made a lot of refactoring progress to be able to support [#28](https://github.com/thedodd/trunk/issues/28) & [#46](https://github.com/thedodd/trunk/issues/46). More work remains to be done, but the foundation to be able to knock these items out is now in place. + +### changed +- All assets which are to be processed by trunk must now be declared as HTML `link` elements as such: ``. The links may appear anywhere in the HTML and Trunk will process them and replace them or delete them based on the associated pipeline's output. If the link element does not have the `data-trunk` attribute, it will not be processed. + +### fixed +- Fixed [#50](https://github.com/thedodd/trunk/issues/50): the ability to copy a file or an entire dir into the dist dir is now supported with two different pipeline types: `` and `` respectively. + +### removed +- The `manifest-path` option has been removed from all Trunk subcommands. The path to the `Cargo.toml` is now specified in the source HTML as ``. The `href="..."` attribute may be omitted, in which case Trunk will look for a `Cargo.toml` within the same directory as the source HTML. If the `href` attribute points to a directory, Trunk will look for the `Cargo.toml` file in that directory. ## 0.6.0 ### added diff --git a/Cargo.lock b/Cargo.lock index 913ba2ef..3ede0d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,7 +93,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,8 +103,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-task 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "vec-arena 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -115,8 +115,8 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-executor 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-io 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -128,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-std 1.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "byte-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "http-types 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -143,9 +143,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -159,14 +159,14 @@ dependencies = [ [[package]] name = "async-io" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "nb-connect 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nb-connect 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "polling 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -191,7 +191,7 @@ dependencies = [ "blocking 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -237,14 +237,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "async-global-executor 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-io 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "async-mutex 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "blocking 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "gloo-timers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "kv-log-macro 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,8 +282,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -353,23 +353,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-channel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "atomic-waker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "blocking" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-channel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "async-task 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "atomic-waker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -426,7 +426,7 @@ name = "chrono" version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", @@ -463,7 +463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -476,7 +476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -585,7 +585,7 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl-sys 0.4.36+curl-7.71.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.58 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -599,7 +599,7 @@ version = "0.4.36+curl-7.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "libnghttp2-sys 0.1.4+1.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.58 (registry+https://github.com/rust-lang/crates.io-index)", @@ -682,8 +682,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fastrand" -version = "1.3.5" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "instant 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "femme" @@ -706,7 +709,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -744,7 +747,7 @@ name = "fsevent-sys" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -772,55 +775,55 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-lite" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -829,7 +832,7 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -840,12 +843,12 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -853,17 +856,17 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.18 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -893,7 +896,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -910,8 +913,8 @@ name = "gloo-timers" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", @@ -927,10 +930,10 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1042,7 +1045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1050,7 +1053,7 @@ name = "inotify-sys" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1066,12 +1069,20 @@ dependencies = [ "serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "instant" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1084,9 +1095,9 @@ dependencies = [ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.33 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.4.36+curl-7.71.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1138,7 +1149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1147,7 +1158,7 @@ version = "0.1.4+1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1156,7 +1167,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1234,7 +1245,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1266,10 +1277,10 @@ dependencies = [ [[package]] name = "nb-connect" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1279,7 +1290,7 @@ version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1315,7 +1326,7 @@ dependencies = [ "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "inotify 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1344,8 +1355,8 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1388,7 +1399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1454,15 +1465,15 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pin-project-internal 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pin-project-internal" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1491,7 +1502,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "wepoll-sys-stjepang 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1503,7 +1514,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "wepoll-sys-stjepang 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1582,7 +1593,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1671,7 +1682,7 @@ name = "sass-rs" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "sass-sys 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1681,7 +1692,7 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1780,17 +1791,6 @@ dependencies = [ "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde_urlencoded" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -1844,7 +1844,7 @@ name = "signal-hook" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook-registry 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1854,7 +1854,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arc-swap 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1872,10 +1872,10 @@ name = "sluice" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1889,7 +1889,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2009,14 +2009,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "surf" -version = "2.0.0-alpha.7" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-std 1.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "async-trait 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.24 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "http-client 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "http-types 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2025,8 +2025,6 @@ dependencies = [ "pin-project-lite 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2055,7 +2053,7 @@ name = "terminal_size" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2064,7 +2062,7 @@ name = "termios" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2109,7 +2107,7 @@ dependencies = [ "async-std 1.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "async-trait 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "femme 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "http-types 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "kv-log-macro 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2123,7 +2121,7 @@ name = "time" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2134,7 +2132,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "const_fn 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", "standback 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "time-macros 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2211,13 +2209,13 @@ name = "tracing-futures" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pin-project 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", "tracing 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trunk" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "async-process 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2226,7 +2224,7 @@ dependencies = [ "console 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs_extra 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "http-types 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "indicatif 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2238,7 +2236,7 @@ dependencies = [ "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "structopt-derive 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "surf 2.0.0-alpha.7 (registry+https://github.com/rust-lang/crates.io-index)", + "surf 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tide 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2512,7 +2510,7 @@ dependencies = [ "checksum async-global-executor 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fefeb39da249f4c33af940b779a56723ce45809ef5c54dad84bb538d4ffb6d9e" "checksum async-h1 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ca2b5cfe1804f48bb8dfb1b2391e6e9a3fbf89e07514dce3bddb03eb4d529db" "checksum async-io 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c9424bb88867b003ca32a1d99cf64595c5a310c7322891795f38aa061860d0af" -"checksum async-io 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6e727cebd055ab2861a854f79def078c4b99ea722d54c6800a0e274389882d4c" +"checksum async-io 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b5bfd63f6fc8fd2925473a147d3f4d252c712291efdde0d7057b25146563402c" "checksum async-mutex 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" "checksum async-process 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23d510baf319291a41e6c3363df4408a3b196ad18fcb1305ae4e500f2eabe260" "checksum async-session 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f" @@ -2531,7 +2529,7 @@ dependencies = [ "checksum block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" "checksum block-cipher 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa136449e765dc7faa244561ccae839c394048667929af599b5d931ebe7b7f10" "checksum blocking 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f30e08a950487f80d2de5cbb72772c8bbaed6002dc8d979722dabd034ede18d" -"checksum blocking 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2640778f8053e72c11f621b0a5175a0560a269282aa98ed85107773ab8e2a556" +"checksum blocking 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c5aba2c74d15fe950254784fe497a999345606169c2288ccb771b72acdf41241" "checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" "checksum byte-pool 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e38e98299d518ec351ca016363e0cbfc77059dcd08dfa9700d15e405536097a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" @@ -2568,7 +2566,7 @@ dependencies = [ "checksum encoding_rs 0.8.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" "checksum envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9" "checksum event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" -"checksum fastrand 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5c85295147490b8fcf2ea3d104080a105a8b2c63f9c319e82c02d8e952388919" +"checksum fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" "checksum femme 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034" "checksum filetime 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" "checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" @@ -2579,23 +2577,23 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" -"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" -"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" -"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" -"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" -"checksum futures-lite 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0db18c5f58083b54b0c416638ea73066722c2815c1e54dd8ba85ee3def593c3a" -"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" -"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" -"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +"checksum futures 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" +"checksum futures-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" +"checksum futures-core 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" +"checksum futures-executor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" +"checksum futures-io 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" +"checksum futures-lite 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7c48d23e382e1f50ad68d16cd23dd3c467f420d4933b629c3f183f33e9f560d8" +"checksum futures-macro 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" +"checksum futures-sink 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" +"checksum futures-task 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" +"checksum futures-util 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" "checksum generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" "checksum ghash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531" "checksum gloo-timers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151" +"checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" "checksum hkdf 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe1149865383e4526a43aee8495f9a325f0b806c63ce6427d06336a590abbbc9" "checksum hmac 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" "checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" @@ -2609,6 +2607,7 @@ dependencies = [ "checksum inotify 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum insta 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee" +"checksum instant 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum isahc 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ac245314704d62c121785203fb4d6f41f137167fcc91beec0b55bd6c4bb8c800" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" @@ -2617,7 +2616,7 @@ dependencies = [ "checksum kv-log-macro 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -"checksum libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)" = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98" +"checksum libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)" = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" "checksum libnghttp2-sys 0.1.4+1.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03624ec6df166e79e139a2310ca213283d6b3c30810c54844f307086d4488df1" "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" "checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" @@ -2632,7 +2631,7 @@ dependencies = [ "checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" "checksum mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum nb-connect 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "701f47aeb98466d0a7fea67e2c2f667c33efa1f2e4fd7f76743aac1153196f72" +"checksum nb-connect 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" "checksum net2 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" "checksum new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" "checksum nipper 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "576d0e437aa08b447a207584463febe639d00b26b63121a9c038eff8371e0050" @@ -2655,8 +2654,8 @@ dependencies = [ "checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" "checksum phf_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" "checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -"checksum pin-project 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2b9e280448854bd91559252582173b3bd1f8e094a0e644791c0628ca9b1f144f" -"checksum pin-project-internal 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c8b352676bc6a4c3d71970560b913cea444a7a921cc2e2d920225e4b91edaa" +"checksum pin-project 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "13fbdfd6bdee3dc9be46452f86af4a4072975899cf8592466668620bebfbcc17" +"checksum pin-project-internal 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "c82fb1329f632c3552cf352d14427d57a511b1cf41db93b3a7d77906a82dcc8e" "checksum pin-project-lite 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" @@ -2695,7 +2694,6 @@ dependencies = [ "checksum serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" "checksum serde_json 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" "checksum serde_qs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9408a61dabe404c76cec504ec510f7d92f41dc0a9362a0db8ab73d141cfbf93f" -"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" "checksum serde_urlencoded 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" "checksum serde_yaml 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5" "checksum servo_arc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" @@ -2720,7 +2718,7 @@ dependencies = [ "checksum structopt 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a33f6461027d7f08a13715659b2948e1602c31a3756aeae9378bfe7518c72e82" "checksum structopt-derive 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c92e775028122a4b3dd55d58f14fc5120289c69bee99df1d117ae30f84b225c9" "checksum subtle 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" -"checksum surf 2.0.0-alpha.7 (registry+https://github.com/rust-lang/crates.io-index)" = "187577a5f02b0156cb5dcc69504fb57a3f8247361dca07864a30dd294ee9a698" +"checksum surf 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d38339c05d2bc84595d56e27aa07566e7b59767ea5cb5c78991b499cd188060" "checksum syn 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" "checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" "checksum terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13" diff --git a/Cargo.toml b/Cargo.toml index 29c6d93b..be039ee4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trunk" -version = "0.6.0" +version = "0.7.0" edition = "2018" description = "Build, bundle & ship your Rust WASM application to the web." license = "MIT/Apache-2.0" @@ -34,7 +34,7 @@ seahash = "4.0.1" serde = { version="1", features=["derive"] } structopt = "0.3.18" structopt-derive = "0.4.11" -surf = "=2.0.0-alpha.7" +surf = "2.0.0" tide = { version="0.13.0", features=["unstable"] } toml = "0.5.6" diff --git a/README.md b/README.md index e51190b6..5a64e07b 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,15 @@ Trunk is a WASM web application bundler for Rust. Trunk uses a simple, zero-conf ### install First, install Trunk via one of the following options. ```bash -# Install via cargo. -cargo install trunk +# Install via homebrew on Mac, Linux or Windows (WSL). +brew install trunk # Install a release binary (great for CI). VERSION=v0.6.0 wget -qO- https://github.com/thedodd/trunk/releases/download/${VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -# Install via homebrew on Mac, Linux or Windows (WSL). -# (coming soon) -brew install trunk +# Install via cargo. +cargo install trunk ``` Release binaries can be found on the [Github releases page](https://github.com/thedodd/trunk/releases). @@ -55,7 +54,7 @@ Trunk uses a source HTML file to drive all asset building and bundling. Trunk al ```html - + ``` @@ -95,19 +94,36 @@ Trunk leverages Rust's powerful concurrency primitives for maximum build speeds `trunk config show` prints out Trunk's current config, before factoring in CLI arguments. Nice for testing & debugging. ## assets +Declaring assets to be processed by Trunk is simple and extensible. All assets to be processed by Trunk must follow these three rules: +- must be declared as a valid HTML `link` tag. +- must have the attribute `data-trunk`. +- must have the attribute `rel="{type}"`, where `{type}` is one of the asset types listed below. + +This will typically look like: ``. Each asset type described below specifies the required and optional attributes for its asset type. All `` HTML elements will be replaced with the output HTML of the associated pipeline. + +Currently supported asset types: +- ✅ `rust`: Trunk will compile the specified Cargo project as the main WASM application. This is optional. If not specified, Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file. + - `href`: (optional) the path to the `Cargo.toml` of the Rust project. If a directory is specified, then Trunk will look for the `Cargo.toml` in the given directory. If no value is specified, then Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file. + - `data-bin`: (optional) the name of the binary to compile and use as the main WASM application. If the Cargo project has multiple binaries, this value will be required for proper functionality. +- ✅ `sass`, `scss`: Trunk ships with a [built-in sass/scss compiler](https://github.com/compass-rs/sass-rs). Just link to your sass files from your source HTML, and Trunk will handle the rest. This content is hashed for cache control. The `href` attribute must be included in the link pointing to the sass/scss file to be processed. +- ✅ `css`: Trunk will copy linked css files found in the source HTML without content modification. This content is hashed for cache control. The `href` attribute must be included in the link pointing to the css file to be processed. + - In the future, Trunk will resolve local `@imports`, will handle minification (see [trunk#7](https://github.com/thedodd/trunk/issues/3)), and we may even look into a pattern where any CSS found in the source tree will be bundled, which would enable a nice zero-config "component styles" pattern. See [trunk#3](https://github.com/thedodd/trunk/issues/3) for more details. +- ✅ `icon`: Trunk will copy the icon image specified in the `href` attribute to the `dist` dir. This content is hashed for cache control. +- ✅ `copy-file`: Trunk will copy the file specified in the `href` attribute to the `dist` dir. This content is copied exactly, no hashing is performed. +- ✅ `copy-dir`: Trunk will recursively copy the directory specified in the `href` attribute to the `dist` dir. This content is copied exactly, no hashing is performed. +- ⏳ `rust-worker`: (in-progress) Trunk will compile the specified Rust project as a WASM web worker. The following attributes are required: + - `href`: (optional) the path to the `Cargo.toml` of the Rust project. If a directory is specified, then Trunk will look for the `Cargo.toml` in the given directory. If no value is specified, then Trunk will look for a `Cargo.toml` in the parent directory of the source HTML file. + - `data-bin`: (optional) the name of the binary to compile and use as the web worker. If the Cargo project has multiple binaries, this value will be required for proper functionality. + Trunk is still a young project, and new asset types will be added as we move forward. Keep an eye on [trunk#3](https://github.com/thedodd/trunk/issues/3) for more information on planned asset types, implementation status, and please contribute to the discussion if you think something is missing. -Currently supported assets: -- ✅ `sass`: Trunk ships with a [built-in sass/scss compiler](https://github.com/compass-rs/sass-rs). Just link to your sass files from your source HTML, and Trunk will handle the rest. This content is hashed for cache control. -- ✅ `css`: Trunk will copy linked css files found in the source HTML without content modification. This content is hashed for cache control. - - In the future, Trunk will resolve local `@imports`, will handle minification (see [trunk#7](https://github.com/thedodd/trunk/issues/3)), and we may even look into a pattern where any CSS found in the source tree will be bundled, which would enable a nice zero-config "component styles" pattern. See [trunk#3](https://github.com/thedodd/trunk/issues/3) for more details. -- ✅ `icon`: Trunk will automatically copy referenced icons to the `dist` dir. This content is hashed for cache control. -- ✅ `js snippets`: [wasm-bindgen JS snippets](https://rustwasm.github.io/docs/wasm-bindgen/reference/js-snippets.html) are automatically copied to the dist dir, hashed and ready to rock. +### js snippets +JS snippets generated from the [wasm-bindgen JS snippets feature](https://rustwasm.github.io/docs/wasm-bindgen/reference/js-snippets.html) are automatically copied to the dist dir, hashed and ready to rock. No additional setup is required. Just use the feature in your application, and Trunk will take care of the rest. ### images & other resources -Images and other resource types can be copied into the `dist` dir by adding a link like this to your source HTML: `` (note the `rel="trunk-dist"` attribute). This will cause Trunk to find the target resource, and copy it to the `dist` dir unmodified. No hashing will be applied. The link itself will be removed from the HTML. +Images and other resource types can be copied into the `dist` dir by adding a link like this to your source HTML: ``. Any normal file type is supported. This will cause Trunk to find the target resource, and copy it to the `dist` dir unmodified. No hashing will be applied. The link itself will be removed from the HTML. To copy an entire directory of assets/images, you can use the following HTML: ``. -This will allow your WASM application to reference images directly from the `dist` dir, and Trunk will ensure that the images are available in the `dist` dir to be served. You will need to be sure to use the correct public URL in your code, which can be configured via the `--public-url` CLI flag to Trunk. +This will allow your WASM application to reference images directly from the `dist` dir, and Trunk will ensure that the images are available in the `dist` dir to be served. **NOTE:** as Trunk continues to mature, we will find better ways to include images and other resources. Hashing content for cache control is great, we just need to find a nice pattern to work with images referenced in Rust components. Please contribute to the discussion over in [trunk#9](https://github.com/thedodd/trunk/issues/9)! See you there. diff --git a/Trunk.toml b/Trunk.toml index f2998352..c35545cd 100644 --- a/Trunk.toml +++ b/Trunk.toml @@ -7,8 +7,6 @@ target = "index.html" release = false # The output dir for all final assets. dist = "dist" -# Path to Cargo.toml. -manifest = "Cargo.toml" # The public URL from which assets are to be served. public_url = "/" diff --git a/examples/yew/Trunk.toml b/examples/yew/Trunk.toml index f0007b70..842cc2f7 100644 --- a/examples/yew/Trunk.toml +++ b/examples/yew/Trunk.toml @@ -1,4 +1,3 @@ [build] target = "index.html" dist = "dist" -manifest = "Cargo.toml" diff --git a/examples/yew/index.html b/examples/yew/index.html index 0ffcb4d8..919e4a03 100644 --- a/examples/yew/index.html +++ b/examples/yew/index.html @@ -5,12 +5,14 @@ Trunk | Yew | YBC - - - - + + + + + + diff --git a/examples/yew/src/main.rs b/examples/yew/src/main.rs index 6050c636..eeb2f85d 100644 --- a/examples/yew/src/main.rs +++ b/examples/yew/src/main.rs @@ -27,7 +27,7 @@ impl Component for App { } fn view(&self) -> Html { - html!{ + html! { <> , - /// Cargo build pipeline system. - cargo_build_pipeline: Arc, - /// WASM bindgen build pipeline system. - wasm_bindgen_pipeline: Arc, - /// HTML build pipeline system. + /// HTML build pipeline. html_pipeline: Arc, /// The build system progress bar for displaying the state of the build system overall. progress: ProgressBar, @@ -36,18 +32,10 @@ impl BuildSystem { /// /// Reducing the number of assumptions here should help us to stay flexible when adding new /// commands, rafctoring and the like. - pub async fn new(cfg: Arc, progress: ProgressBar) -> Result { - let mode_segment = if cfg.release { "release" } else { "debug" }; - let bindgen_out = Arc::new(cfg.manifest.metadata.target_directory.join("wasm-bindgen").join(mode_segment)); - - let cargo_build_pipeline = Arc::new(CargoBuild::new(cfg.clone(), progress.clone())); - let wasm_bindgen_pipeline = Arc::new(WasmBindgen::new(cfg.clone(), bindgen_out, progress.clone())); - let html_pipeline = Arc::new(HtmlPipeline::new(cfg.clone(), progress.clone())?); - + pub async fn new(cfg: Arc, progress: ProgressBar, ignore_chan: Option>) -> Result { + let html_pipeline = Arc::new(HtmlPipeline::new(cfg.clone(), progress.clone(), ignore_chan)?); Ok(Self { cfg, - cargo_build_pipeline, - wasm_bindgen_pipeline, html_pipeline, progress, }) @@ -71,26 +59,20 @@ impl BuildSystem { Err(err) => { self.progress.set_prefix(&format!("{}", ERROR)); self.progress.finish_with_message("error"); - self.progress.println(err.to_string()); Err(err) } } } async fn do_build(&mut self) -> Result<()> { - // Spawn cargo build. It will run concurrently without polling. - let cargo_handle = self.cargo_build_pipeline.clone().spawn(); + // TODO: delete the contents of the `dist/.current` dir (currently in flight elsewhere). // Ensure the output dist directory is in place. fs::create_dir_all(self.cfg.dist.as_path()).await?; - // Spawn the wasm-bindgen call, it will await the cargo build. - let wasmbg_handle = self.wasm_bindgen_pipeline.clone().spawn(cargo_handle); - - // Spawn the source HTML pipeline. This will spawn all other asset pipelines derived from - // the source HTML, and will await the cargo build & wasm-bindgen build in order to - // generate the final HTML. - self.html_pipeline.clone().spawn(wasmbg_handle).await?; + // Spawn the source HTML pipeline. This will spawn all other pipelines derived from + // the source HTML, and will ultimately generate and write the final HTML. + self.html_pipeline.clone().spawn().await?; Ok(()) } } diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 2ab2bd9c..f939ccc1 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -18,7 +18,7 @@ pub struct Build { impl Build { pub async fn run(self, config: Option) -> Result<()> { let cfg = ConfigOpts::rtc_build(self.build, config).await?; - let mut system = BuildSystem::new(cfg, spinner()).await?; + let mut system = BuildSystem::new(cfg, spinner(), None).await?; system.build().await?; Ok(()) } diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index 0fb4fbd7..87a50fac 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use anyhow::Result; +use anyhow::{ensure, Result}; use async_process::{Command, Stdio}; use async_std::fs; use structopt::StructOpt; @@ -26,9 +26,7 @@ impl Clean { .stderr(Stdio::piped()) .output() .await?; - if !output.status.success() { - eprintln!("{}", String::from_utf8_lossy(&output.stderr)); - } + ensure!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); } Ok(()) } diff --git a/src/common.rs b/src/common.rs index e6b88b1b..98d5bebd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use async_std::path::PathBuf as AsyncPathBuf; use async_std::task::spawn_blocking; @@ -24,7 +24,7 @@ pub fn parse_public_url(val: &str) -> String { /// A utility function to recursively copy a directory. pub async fn copy_dir_recursive(from_dir: PathBuf, to_dir: PathBuf) -> Result<()> { if !AsyncPathBuf::from(&from_dir).exists().await { - return Ok(()); + return Err(anyhow!("directory can not be copied as it does not exist {:?}", &from_dir)); } spawn_blocking(move || { let opts = fs_extra::dir::CopyOptions { diff --git a/src/config/manifest.rs b/src/config/manifest.rs index d922ddcc..381ca5b5 100644 --- a/src/config/manifest.rs +++ b/src/config/manifest.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::Path; use anyhow::{anyhow, Result}; use async_std::task::spawn_blocking; @@ -16,16 +16,11 @@ pub struct CargoMetadata { } impl CargoMetadata { - /// Get the project's cargo metadata of the CWD, or of the project specified by the given manifest path. - pub async fn new(manifest: &Option) -> Result { - // Fetch the cargo project's metadata. + // Create a new instance from the Cargo.toml at the given path. + pub async fn new(manifest: &Path) -> Result { let mut cmd = MetadataCommand::new(); - if let Some(manifest) = manifest.as_ref() { - cmd.manifest_path(manifest); - } + cmd.manifest_path(manifest); let metadata = spawn_blocking(move || cmd.exec()).await?; - - // Get a handle to this project's package info. let package = metadata .root_package() .cloned() diff --git a/src/config/models.rs b/src/config/models.rs index 5b86fd43..db776ab6 100644 --- a/src/config/models.rs +++ b/src/config/models.rs @@ -7,7 +7,7 @@ use serde::Deserialize; use structopt::StructOpt; use crate::common::parse_public_url; -use crate::config::{CargoMetadata, RtcBuild, RtcClean, RtcServe, RtcWatch}; +use crate::config::{RtcBuild, RtcClean, RtcServe, RtcWatch}; /// Config options for the build system. #[derive(Clone, Debug, Default, Deserialize, StructOpt)] @@ -25,9 +25,6 @@ pub struct ConfigOptsBuild { /// The public URL from which assets are to be served [default: /] #[structopt(long, parse(from_str=parse_public_url))] pub public_url: Option, - /// Path to Cargo.toml [default: Cargo.toml] - #[structopt(long = "manifest-path", parse(from_os_str))] - pub manifest: Option, } /// Config options for the watch system. @@ -104,8 +101,7 @@ impl ConfigOpts { let base_layer = Self::file_and_env_layers(config)?; let build_layer = Self::cli_opts_layer_build(cli_build, base_layer); let build_opts = build_layer.build.unwrap_or_default(); - let manifest = CargoMetadata::new(&build_opts.manifest).await?; - Ok(Arc::new(RtcBuild::new(manifest, build_opts)?)) + Ok(Arc::new(RtcBuild::new(build_opts)?)) } /// Extract the runtime config for the watch system based on all config layers. @@ -115,8 +111,7 @@ impl ConfigOpts { let watch_layer = Self::cli_opts_layer_watch(cli_watch, build_layer); let build_opts = watch_layer.build.unwrap_or_default(); let watch_opts = watch_layer.watch.unwrap_or_default(); - let manifest = CargoMetadata::new(&build_opts.manifest).await?; - Ok(Arc::new(RtcWatch::new(manifest, build_opts, watch_opts)?)) + Ok(Arc::new(RtcWatch::new(build_opts, watch_opts)?)) } /// Extract the runtime config for the serve system based on all config layers. @@ -130,8 +125,7 @@ impl ConfigOpts { let build_opts = serve_layer.build.unwrap_or_default(); let watch_opts = serve_layer.watch.unwrap_or_default(); let serve_opts = serve_layer.serve.unwrap_or_default(); - let manifest = CargoMetadata::new(&build_opts.manifest).await?; - Ok(Arc::new(RtcServe::new(manifest, build_opts, watch_opts, serve_opts, serve_layer.proxy)?)) + Ok(Arc::new(RtcServe::new(build_opts, watch_opts, serve_opts, serve_layer.proxy)?)) } /// Extract the runtime config for the clean system based on all config layers. @@ -152,7 +146,6 @@ impl ConfigOpts { target: cli.target, release: cli.release, dist: cli.dist, - manifest: cli.manifest, public_url: cli.public_url, }; let cfg_build = ConfigOpts { @@ -244,11 +237,6 @@ impl ConfigOpts { *dist = parent.join(&dist); } }); - build.manifest.iter_mut().for_each(|manifest| { - if !manifest.is_absolute() { - *manifest = parent.join(&manifest); - } - }); }); cfg.watch.iter_mut().for_each(|watch| { watch.ignore.iter_mut().for_each(|ignores_vec| { @@ -292,7 +280,6 @@ impl ConfigOpts { (Some(l), Some(mut g)) => { g.target = g.target.or(l.target); g.dist = g.dist.or(l.dist); - g.manifest = g.manifest.or(l.manifest); g.public_url = g.public_url.or(l.public_url); // NOTE: this can not be disabled in the cascade. if l.release { diff --git a/src/config/rt.rs b/src/config/rt.rs index 7aefb1ea..b48bae0f 100644 --- a/src/config/rt.rs +++ b/src/config/rt.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use anyhow::{Context, Result}; use http_types::Url; -use crate::config::{CargoMetadata, ConfigOptsBuild, ConfigOptsClean, ConfigOptsProxy, ConfigOptsServe, ConfigOptsWatch}; +use crate::config::{ConfigOptsBuild, ConfigOptsClean, ConfigOptsProxy, ConfigOptsServe, ConfigOptsWatch}; /// Runtime config for the build system. #[derive(Clone, Debug)] @@ -15,29 +15,24 @@ pub struct RtcBuild { pub release: bool, /// The output dir for all final assets. pub dist: PathBuf, - /// The metadata of the associated cargo project being processed. - pub manifest: CargoMetadata, /// The public URL from which assets are to be served. pub public_url: String, } impl RtcBuild { /// Construct a new instance. - pub(super) fn new(manifest: CargoMetadata, opts: ConfigOptsBuild) -> Result { + pub(super) fn new(opts: ConfigOptsBuild) -> Result { let target = opts.target.clone().unwrap_or_else(|| "index.html".into()); + let target_parent_dir = target + .parent() + .map(|path| path.to_owned()) + .unwrap_or_else(|| PathBuf::from(std::path::MAIN_SEPARATOR.to_string())); Ok(Self { target: target .canonicalize() .with_context(|| format!("error getting canonical path to source HTML file {:?}", &target))?, release: opts.release, - // Use a config defined value. - dist: opts.dist.unwrap_or_else(|| - // Else fallback to the parent dir of the cargo target dir. - manifest.metadata.target_directory - .parent().map(|path| path.join("dist")) - // Else fallback to the "dist" dir of the CWD (this will practically never be hit). - .unwrap_or_else(|| "dist".into())), - manifest, + dist: opts.dist.unwrap_or_else(|| target_parent_dir.join("dist")), public_url: opts.public_url.unwrap_or_else(|| "/".into()), }) } @@ -53,8 +48,8 @@ pub struct RtcWatch { } impl RtcWatch { - pub(super) fn new(manifest: CargoMetadata, build_opts: ConfigOptsBuild, opts: ConfigOptsWatch) -> Result { - let build = Arc::new(RtcBuild::new(manifest, build_opts)?); + pub(super) fn new(build_opts: ConfigOptsBuild, opts: ConfigOptsWatch) -> Result { + let build = Arc::new(RtcBuild::new(build_opts)?); Ok(Self { build, ignore: opts.ignore.unwrap_or_default(), @@ -81,10 +76,9 @@ pub struct RtcServe { impl RtcServe { pub(super) fn new( - manifest: CargoMetadata, build_opts: ConfigOptsBuild, watch_opts: ConfigOptsWatch, opts: ConfigOptsServe, - proxies: Option>, + build_opts: ConfigOptsBuild, watch_opts: ConfigOptsWatch, opts: ConfigOptsServe, proxies: Option>, ) -> Result { - let watch = Arc::new(RtcWatch::new(manifest, build_opts, watch_opts)?); + let watch = Arc::new(RtcWatch::new(build_opts, watch_opts)?); Ok(Self { watch, port: opts.port.unwrap_or(8080), diff --git a/src/pipelines/assets/mod.rs b/src/pipelines/assets/mod.rs deleted file mode 100644 index 6e4a081c..00000000 --- a/src/pipelines/assets/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::ffi::OsString; -use std::path::PathBuf; - -use anyhow::{anyhow, bail, ensure, Result}; -use async_std::fs; -use indicatif::ProgressBar; - -use crate::common::ERROR; - -/// An asset type descriptor extracted from the source HTML. -pub enum AssetType { - Link { - /// The `rel` attribute of the HTML link. - rel: String, - }, -} - -/// An asset file to be processed by some build pipeline. -pub struct AssetFile { - /// The canonicalized path to the target file. - pub path: PathBuf, - /// The name of the file itself. - pub file_name: OsString, - /// The file stem of the asset file. - pub file_stem: OsString, - /// The extension of the file. - pub ext: String, - /// The asset's type. - pub atype: AssetType, - /// The ID which this asset should use. - pub id: String, -} - -impl AssetFile { - /// Create a new instance. - /// - /// The given path will be validated to ensure the following: - /// - that the full canonicalized path points to a file on the FS. - /// - that the file has a filename. - /// - that the file has an extension. - /// - /// Any errors returned from this constructor indicate that one of these invariants was not - /// upheld. - pub async fn new(path: PathBuf, atype: AssetType, id: String, progress: &ProgressBar) -> Result { - // Take the path to referenced resource, if it is actually an FS path, then we continue. - let path = match fs::canonicalize(&path).await { - Ok(path) => path, - Err(_) => { - if !path.to_string_lossy().contains("://") { - progress.println(format!("{}skipping invalid path: {}", ERROR, path.to_string_lossy())); - } - return Err(anyhow!("skipping asset which is not a valid path")); - } - }; - ensure!(path.is_file().await, "target file does not exist on the FS"); - let file_name = match path.file_name() { - Some(file_name) => file_name.to_owned(), - None => bail!("asset has no file name"), - }; - let file_stem = match path.file_stem() { - Some(file_stem) => file_stem.to_owned(), - None => bail!("asset has no file name stem"), - }; - let ext = match path.extension() { - Some(ext) => ext.to_string_lossy().to_lowercase(), - None => bail!("asset has no file extension"), - }; - Ok(Self { - path: path.into(), - file_name, - file_stem, - ext, - atype, - id, - }) - } -} - -/// The output of an asset pipeline. -pub struct AssetPipelineOutput { - /// The ID of the asset pipeline. - pub id: String, - /// The file name of the output file written to the dist dir (not a full path). - pub file_name: String, - /// A bool indicating if the HTML node associated with this pipeline should be removed. - pub remove: bool, -} diff --git a/src/pipelines/cargo.rs b/src/pipelines/cargo.rs deleted file mode 100644 index 1e120240..00000000 --- a/src/pipelines/cargo.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Cargo pipelines. - -use std::path::PathBuf; -use std::sync::Arc; - -use anyhow::{anyhow, ensure, Context, Result}; -use async_process::{Command, Stdio}; -use async_std::task::{spawn, JoinHandle}; -use indicatif::ProgressBar; - -use crate::config::RtcBuild; - -/// A cargo build pipeline. -pub struct CargoBuild { - /// Runtime config. - cfg: Arc, - /// The progress bar used by this pipeline. - progress: ProgressBar, -} - -impl CargoBuild { - /// Create a new instance. - pub fn new(cfg: Arc, progress: ProgressBar) -> Self { - Self { cfg, progress } - } - - /// Spawn a new pipeline. - pub fn spawn(self: Arc) -> JoinHandle> { - spawn(self.build()) - } - - /// Perform the build routine of this pipeline. - async fn build(self: Arc) -> Result { - self.progress.set_message(&format!("building {}", &self.cfg.manifest.package.name)); - - // Spawn the cargo build process. - let mut args = vec![ - "build", - "--target=wasm32-unknown-unknown", - "--manifest-path", - &self.cfg.manifest.manifest_path, - ]; - if self.cfg.release { - args.push("--release"); - } - let build_output = Command::new("cargo") - .args(args.as_slice()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context("error spawning cargo build")? - .output() - .await - .context("error during cargo build execution")?; - ensure!( - build_output.status.success(), - "bad status returned from cargo build: {}", - String::from_utf8_lossy(&build_output.stderr) - ); - - // Perform a final cargo invocation on success to get artifact names. - self.progress.set_message("fetching artifacts"); - args.push("--message-format=json"); - let artifacts_out = Command::new("cargo") - .args(args.as_slice()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context("error spawning cargo build artifacts task")? - .output() - .await - .context("error getting cargo build artifacts info")?; - ensure!( - artifacts_out.status.success(), - "bad status returned from cargo artifacts request: {}", - String::from_utf8_lossy(&build_output.stderr) - ); - - // Stream over cargo messages to find the artifacts we are interested in. - let reader = std::io::BufReader::new(artifacts_out.stdout.as_slice()); - let artifact = cargo_metadata::Message::parse_stream(reader) - .filter_map(|msg| if let Ok(msg) = msg { Some(msg) } else { None }) - .fold(Ok(None), |acc, msg| match msg { - cargo_metadata::Message::CompilerArtifact(art) if art.package_id == self.cfg.manifest.package.id => Ok(Some(art)), - cargo_metadata::Message::BuildFinished(finished) if !finished.success => Err(anyhow!("error while fetching cargo artifact info")), - _ => acc, - })? - .ok_or_else(|| anyhow!("cargo artifacts not found for target crate"))?; - - // Get a handle to the WASM output file. - let wasm = artifact - .filenames - .into_iter() - .find(|path| path.extension().map(|ext| ext == "wasm").unwrap_or(false)) - .ok_or_else(|| anyhow!("could not find WASM output after cargo build"))?; - - // Hash the built wasm app, then use that as the out-name param. - self.progress.set_message("processing WASM"); - let wasm_bytes = async_std::fs::read(&wasm).await.context("error reading wasm file for hash generation")?; - let hashed_name = format!("index-{:x}", seahash::hash(&wasm_bytes)); - Ok(CargoBuildOutput { wasm, hashed_name }) - } -} - -/// The output of a cargo build pipeline. -pub struct CargoBuildOutput { - /// The path to the build WASM file. - pub wasm: PathBuf, - /// The hashed name to use for the WASM file. - pub hashed_name: String, -} diff --git a/src/pipelines/copydir.rs b/src/pipelines/copydir.rs new file mode 100644 index 00000000..979de3aa --- /dev/null +++ b/src/pipelines/copydir.rs @@ -0,0 +1,71 @@ +//! Copy-dir asset pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, Context, Result}; +use async_std::task::{spawn, JoinHandle}; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::TrunkLinkPipelineOutput; +use super::ATTR_HREF; +use crate::common::copy_dir_recursive; +use crate::config::RtcBuild; + +/// A CopyDir asset pipeline. +pub struct CopyDir { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime build config. + cfg: Arc, + /// The progress bar to use for this pipeline. + progress: ProgressBar, + /// The path to the dir being copied. + path: PathBuf, +} + +impl CopyDir { + pub const TYPE_COPY_DIR: &'static str = "copy-dir"; + + pub async fn new(cfg: Arc, progress: ProgressBar, html_dir: Arc, el: Selection<'_>, id: usize) -> Result { + // Build the path to the target asset. + let href_attr = el + .attr(ATTR_HREF) + .ok_or_else(|| anyhow!("required attr `href` missing for element: {}", el.html()))?; + let mut path = PathBuf::new(); + path.extend(href_attr.as_ref().split('/')); + if !path.is_absolute() { + path = html_dir.join(path); + } + Ok(Self { id, cfg, progress, path }) + } + + /// Spawn the pipeline for this asset type. + pub fn spawn(self) -> JoinHandle> { + spawn(async move { + self.progress.set_message("copying directory"); + let canonical_path = async_std::path::Path::new(&self.path) + .canonicalize() + .await + .with_context(|| format!("error taking canonical path of directory {:?}", &self.path))?; + let dir_name = canonical_path + .file_name() + .ok_or_else(|| anyhow!("could not get directory name of dir {:?}", &canonical_path))?; + let dir_out = self.cfg.dist.join(dir_name); + copy_dir_recursive(canonical_path.into(), dir_out).await?; + self.progress.set_message("finished copying directory"); + Ok(TrunkLinkPipelineOutput::CopyDir(CopyDirOutput(self.id))) + }) + } +} + +/// The output of a CopyDir build pipeline. +pub struct CopyDirOutput(usize); + +impl CopyDirOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + dom.select(&super::trunk_id_selector(self.0)).remove(); + Ok(()) + } +} diff --git a/src/pipelines/copyfile.rs b/src/pipelines/copyfile.rs new file mode 100644 index 00000000..8c0ebb11 --- /dev/null +++ b/src/pipelines/copyfile.rs @@ -0,0 +1,60 @@ +//! Copy-file asset pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, Result}; +use async_std::task::{spawn, JoinHandle}; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::ATTR_HREF; +use super::{AssetFile, TrunkLinkPipelineOutput}; +use crate::config::RtcBuild; + +/// A CopyFile asset pipeline. +pub struct CopyFile { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime build config. + cfg: Arc, + /// The progress bar to use for this pipeline. + progress: ProgressBar, + /// The asset file being processed. + asset: AssetFile, +} + +impl CopyFile { + pub const TYPE_COPY_FILE: &'static str = "copy-file"; + + pub async fn new(cfg: Arc, progress: ProgressBar, html_dir: Arc, el: Selection<'_>, id: usize) -> Result { + // Build the path to the target asset. + let href_attr = el + .attr(ATTR_HREF) + .ok_or_else(|| anyhow!("required attr `href` missing for element: {}", el.html()))?; + let mut path = PathBuf::new(); + path.extend(href_attr.as_ref().split('/')); + let asset = AssetFile::new(&html_dir, path).await?; + Ok(Self { id, cfg, progress, asset }) + } + + /// Spawn the pipeline for this asset type. + pub fn spawn(self) -> JoinHandle> { + spawn(async move { + self.progress.set_message("copying file"); + let _ = self.asset.copy(&self.cfg.dist).await?; + self.progress.set_message("finished copying file"); + Ok(TrunkLinkPipelineOutput::CopyFile(CopyFileOutput(self.id))) + }) + } +} + +/// The output of a CopyFile build pipeline. +pub struct CopyFileOutput(usize); + +impl CopyFileOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + dom.select(&super::trunk_id_selector(self.0)).remove(); + Ok(()) + } +} diff --git a/src/pipelines/css.rs b/src/pipelines/css.rs new file mode 100644 index 00000000..77a0eeb0 --- /dev/null +++ b/src/pipelines/css.rs @@ -0,0 +1,69 @@ +//! CSS asset pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, Result}; +use async_std::task::{spawn, JoinHandle}; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::ATTR_HREF; +use super::{AssetFile, HashedFileOutput, TrunkLinkPipelineOutput}; +use crate::config::RtcBuild; + +/// A CSS asset pipeline. +pub struct Css { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime build config. + cfg: Arc, + /// The progress bar to use for this pipeline. + progress: ProgressBar, + /// The asset file being processed. + asset: AssetFile, +} + +impl Css { + pub const TYPE_CSS: &'static str = "css"; + + pub async fn new(cfg: Arc, progress: ProgressBar, html_dir: Arc, el: Selection<'_>, id: usize) -> Result { + // Build the path to the target asset. + let href_attr = el + .attr(ATTR_HREF) + .ok_or_else(|| anyhow!("required attr `href` missing for element: {}", el.html()))?; + let mut path = PathBuf::new(); + path.extend(href_attr.as_ref().split('/')); + let asset = AssetFile::new(&html_dir, path).await?; + Ok(Self { id, cfg, progress, asset }) + } + + /// Spawn the pipeline for this asset type. + pub fn spawn(self) -> JoinHandle> { + spawn(async move { + self.progress.set_message("copying & hashing css"); + let hashed_file_output = self.asset.copy_with_hash(&self.cfg.dist).await?; + self.progress.set_message("finished copying & hashing css"); + Ok(TrunkLinkPipelineOutput::Css(CssOutput { + id: self.id, + file: hashed_file_output, + })) + }) + } +} + +/// The output of a CSS build pipeline. +pub struct CssOutput { + /// The ID of this pipeline. + pub id: usize, + /// Data on the finalized output file. + pub file: HashedFileOutput, +} + +impl CssOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + dom.select(&super::trunk_id_selector(self.id)) + .replace_with_html(format!(r#""#, self.file.file_name)); + Ok(()) + } +} diff --git a/src/pipelines/html.rs b/src/pipelines/html.rs index f264e28c..fe4eb598 100644 --- a/src/pipelines/html.rs +++ b/src/pipelines/html.rs @@ -3,22 +3,21 @@ use std::path::PathBuf; use std::sync::Arc; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, ensure, Context, Result}; use async_std::fs; -use async_std::task::{spawn, spawn_blocking, spawn_local, JoinHandle}; +use async_std::task::{spawn_local, JoinHandle}; +use futures::channel::mpsc::Sender; use futures::stream::{FuturesUnordered, StreamExt}; use indicatif::ProgressBar; use nipper::Document; use crate::config::RtcBuild; -use crate::pipelines::assets::{AssetFile, AssetPipelineOutput, AssetType}; -use crate::pipelines::wasmbg::WasmBindgenOutput; +use crate::pipelines::rust_app::RustApp; +use crate::pipelines::{TrunkLink, TrunkLinkPipelineOutput, TRUNK_ID}; -const HREF_ATTR: &str = "href"; const PUBLIC_URL_MARKER_ATTR: &str = "data-trunk-public-url"; -const TRUNK_ID: &str = "__trunk-id"; -type AssetPipelineHandles = FuturesUnordered>>; +type AssetPipelineHandles = FuturesUnordered>>; /// An HTML assets build pipeline. /// @@ -32,97 +31,80 @@ pub struct HtmlPipeline { /// The path to the source HTML document from which the output `index.html` will be built. target_html_path: PathBuf, /// The parent directory of `target_html_path`. - target_html_dir: PathBuf, + target_html_dir: Arc, + /// An optional channel to be used to communicate ignore paths to the watcher. + ignore_chan: Option>, } impl HtmlPipeline { /// Create a new instance. - pub fn new(cfg: Arc, progress: ProgressBar) -> Result { + pub fn new(cfg: Arc, progress: ProgressBar, ignore_chan: Option>) -> Result { let target_html_path = cfg.target.canonicalize().context("failed to get canonical path of target HTML file")?; - let target_html_dir = target_html_path - .parent() - .ok_or_else(|| anyhow!("failed to determine parent dir of target HTML file"))? - .to_owned(); + let target_html_dir = Arc::new( + target_html_path + .parent() + .ok_or_else(|| anyhow!("failed to determine parent dir of target HTML file"))? + .to_owned(), + ); Ok(Self { cfg, progress, target_html_path, target_html_dir, + ignore_chan, }) } /// Spawn a new pipeline. - pub fn spawn(self: Arc, wasmbg: JoinHandle>) -> JoinHandle> { - spawn_local(self.build(wasmbg)) + pub fn spawn(self: Arc) -> JoinHandle> { + spawn_local(self.build()) } /// Perform the build routine of this pipeline. - async fn build(self: Arc, wasmbg: JoinHandle>) -> Result<()> { + async fn build(self: Arc) -> Result<()> { self.progress.set_message("spawning asset pipelines"); - // TODO: this needs to be refactored a bit to work in a more generic fashion. - // See #50, #46, #28, #3 - // Open the source HTML file for processing. let raw_html = fs::read_to_string(&self.target_html_path).await?; let mut target_html = Document::from(&raw_html); - // Spawn pipelines for any links in the HTML head which need to be processed. - let asset_links = target_html - .select(r#"html head link"#) - .iter() - .filter_map(|node| { - // Be sure our link has an href to process, else skip. - let href = match node.attr(HREF_ATTR) { - Some(href) => href, - None => return None, - }; - // Skip if there is an obvious protocol segment. This filters out `file://` - // patterns as well. Just don't use the `file://` pattern, it is not needed. - if href.contains("://") { - return None; - } - Some((node, href)) - }) - .enumerate(); - - // Update the DOM for each extracted asset as long as it is a valid FS path. + // Iterator over all `link[data-trunk]` elements, assigning IDs & building pipelines. let mut assets = vec![]; - for (idx, (mut node, href)) in asset_links { - // Handle given paths in a platform agnostic manner. - let mut path = PathBuf::new(); - path.extend(href.as_ref().split('/')); // This handles conversion to Windows paths when needed. - if !path.is_absolute() { - path = self.target_html_dir.join(path); - } - - // Take the path to referenced resource, if it is a valid asset, then we continue. - let rel = node.attr_or("rel", "").to_string().to_lowercase(); - let id = format!("link-{}", idx); - let asset = match AssetFile::new(path, AssetType::Link { rel }, id, &self.progress).await { - Ok(asset) => asset, - Err(_) => continue, - }; - // Update the DOM with an ID for async processing. - node.set_attr(TRUNK_ID, &asset.id); + for (id, mut link) in target_html.select(r#"link[data-trunk]"#).iter().enumerate() { + link.set_attr(TRUNK_ID, &id.to_string()); + let asset = TrunkLink::from_html( + self.cfg.clone(), + self.progress.clone(), + self.target_html_dir.clone(), + self.ignore_chan.clone(), + link, + id, + ) + .await?; assets.push(asset); } - // Route assets over to the appropriate pipeline handler. - let pipelines: AssetPipelineHandles = FuturesUnordered::new(); - for asset in assets { - if let Some(handle) = self.spawn_asset_bundle(asset) { - pipelines.push(handle); - } + // Ensure we have a Rust app pipeline to spawn. + let rust_app_nodes = target_html.select(r#"link[data-trunk][rel="rust"]"#).length(); + ensure!(rust_app_nodes <= 1, r#"only one link may be specified"#); + if rust_app_nodes == 0 { + let app = RustApp::new_default( + self.cfg.clone(), + self.progress.clone(), + self.target_html_dir.clone(), + self.ignore_chan.clone(), + ) + .await?; + assets.push(TrunkLink::RustApp(app)); } + // Spawn all asset pipelines. + let mut pipelines: AssetPipelineHandles = FuturesUnordered::new(); + pipelines.extend(assets.into_iter().map(|asset| asset.spawn())); + // Finalize asset pipelines. - self.progress.set_message("awaiting asset pipelines"); - self.finalize_asset_pipelines(&mut target_html, pipelines).await; - self.progress.set_message("awaiting wasm-bindgen pipeline"); - let wasmbg_out = wasmbg.await?; - self.insert_wasm_module(&wasmbg_out, &mut target_html); + self.finalize_asset_pipelines(&mut target_html, pipelines).await?; self.finalize_html(&mut target_html); // Assemble a new output index.html file. @@ -134,122 +116,19 @@ impl HtmlPipeline { } /// Finalize asset pipelines & prep the DOM for final output. - async fn finalize_asset_pipelines(&self, target_html: &mut Document, mut pipelines: AssetPipelineHandles) { + async fn finalize_asset_pipelines(&self, target_html: &mut Document, mut pipelines: AssetPipelineHandles) -> Result<()> { while let Some(asset_res) = pipelines.next().await { - // Unpack the asset pipeline result. - let asset = match asset_res { - Ok(asset) => asset, - Err(err) => { - self.progress.println(format!("{}", err)); - continue; - } - }; - // Update the DOM based on asset output. - let mut node = target_html.select(&format!("[{}={}]", TRUNK_ID, &asset.id)); - if asset.remove { - node.remove(); - } else { - node.remove_attr(TRUNK_ID); - node.remove_attr(HREF_ATTR); - node.set_attr(HREF_ATTR, &format!("{}{}", &self.cfg.public_url, &asset.file_name)); - } + let asset = asset_res?; + asset.finalize(target_html).await?; } - // Remove any additional trunk IDs from the DOM. - target_html.select(&format!("[{}]", TRUNK_ID)).remove_attr(TRUNK_ID); + Ok(()) } /// Prepare the document for final output. fn finalize_html(&self, target_html: &mut Document) { - // write public_url to base elements + // Write public_url to base element. let mut base_elements = target_html.select(&format!("html head base[{}]", PUBLIC_URL_MARKER_ATTR)); base_elements.remove_attr(PUBLIC_URL_MARKER_ATTR); base_elements.set_attr("href", &self.cfg.public_url); } - - /// Insert the finalized WASM into the output HTML. - fn insert_wasm_module(&self, wasm: &WasmBindgenOutput, target_html: &mut Document) { - let script = format!( - r#""#, - base = self.cfg.public_url, - js = &wasm.js_output, - wasm = &wasm.wasm_output, - ); - target_html.select("head").append_html(script); - } - - /// Spawn an build pipeline for the given asset based on its file extension. - fn spawn_asset_bundle(&self, asset: AssetFile) -> Option>> { - match &asset.atype { - AssetType::Link { rel } => match rel.as_ref() { - "stylesheet" => match asset.ext.as_ref() { - "scss" | "sass" => Some(self.spawn_sass_pipeline(asset)), - "css" => Some(self.spawn_copy_pipeline(asset, true, false)), - _ => Some(self.spawn_copy_pipeline(asset, false, false)), - }, - "icon" => Some(self.spawn_copy_pipeline(asset, true, false)), - "trunk-dist" => Some(self.spawn_copy_pipeline(asset, false, true)), - _ => None, - }, - } - } - - /// Spawn a concurrent build pipeline for a SASS/SCSS asset. - fn spawn_sass_pipeline(&self, asset: AssetFile) -> JoinHandle> { - let (dist, release, progress) = (self.cfg.dist.clone(), self.cfg.release, self.progress.clone()); - spawn(async move { - // Compile the target SASS/SCSS file. - let path_str = asset.path.to_string_lossy().to_string(); - let mut opts = sass_rs::Options::default(); - if release { - opts.output_style = sass_rs::OutputStyle::Compressed; - } - let css = spawn_blocking(move || match sass_rs::compile_file(&path_str, opts) { - Ok(css) => Ok(css), - Err(err) => { - progress.println(err); - Err(anyhow!("error compiling sass for {}", &path_str)) - } - }) - .await?; - // Hash the contents to generate a file name, and then write the contents to the dist dir. - let hash = seahash::hash(css.as_bytes()); - let file_name = asset.file_stem.to_string_lossy(); - let out_file_name = format!("{}-{:x}.css", file_name, hash); - let out_file = dist.join(&out_file_name); - fs::write(out_file, css).await.context("error writing SASS pipeline output")?; - Ok(AssetPipelineOutput { - id: asset.id, - file_name: out_file_name, - remove: false, - }) - }) - } - - /// Spawn a concurrent build pipeline which simply copies the source to the destination, unchanged. - fn spawn_copy_pipeline(&self, asset: AssetFile, hash: bool, remove: bool) -> JoinHandle> { - let dist = self.cfg.dist.clone(); - spawn(async move { - let bytes = fs::read(&asset.path) - .await - .with_context(|| format!("error reading file for hashing in copy pipeline {:?}", &asset.path))?; - let new_file_name = if hash { - let hash = seahash::hash(bytes.as_ref()); - let orig_file_name = asset.file_stem.to_string_lossy(); - format!("{}-{:x}.{}", orig_file_name, hash, &asset.ext) - } else { - asset.file_name.to_string_lossy().to_string() - }; - - let out_file_name = dist.join(&new_file_name); - fs::write(out_file_name, bytes) - .await - .with_context(|| format!("error copying file in copy pipeline {:?}", &asset.path))?; - - Ok(AssetPipelineOutput { - id: asset.id, - file_name: new_file_name, - remove, - }) - }) - } } diff --git a/src/pipelines/icon.rs b/src/pipelines/icon.rs new file mode 100644 index 00000000..8f0c0ae2 --- /dev/null +++ b/src/pipelines/icon.rs @@ -0,0 +1,69 @@ +//! Icon asset pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, Result}; +use async_std::task::{spawn, JoinHandle}; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::ATTR_HREF; +use super::{AssetFile, HashedFileOutput, TrunkLinkPipelineOutput}; +use crate::config::RtcBuild; + +/// An Icon asset pipeline. +pub struct Icon { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime build config. + cfg: Arc, + /// The progress bar to use for this pipeline. + progress: ProgressBar, + /// The asset file being processed. + asset: AssetFile, +} + +impl Icon { + pub const TYPE_ICON: &'static str = "icon"; + + pub async fn new(cfg: Arc, progress: ProgressBar, html_dir: Arc, el: Selection<'_>, id: usize) -> Result { + // Build the path to the target asset. + let href_attr = el + .attr(ATTR_HREF) + .ok_or_else(|| anyhow!("required attr `href` missing for element: {}", el.html()))?; + let mut path = PathBuf::new(); + path.extend(href_attr.as_ref().split('/')); + let asset = AssetFile::new(&html_dir, path).await?; + Ok(Self { id, cfg, progress, asset }) + } + + /// Spawn the pipeline for this asset type. + pub fn spawn(self) -> JoinHandle> { + spawn(async move { + self.progress.set_message("copying & hashing icon"); + let hashed_file_output = self.asset.copy_with_hash(&self.cfg.dist).await?; + self.progress.set_message("finished copying & hashing icon"); + Ok(TrunkLinkPipelineOutput::Icon(IconOutput { + id: self.id, + file: hashed_file_output, + })) + }) + } +} + +/// The output of an Icon build pipeline. +pub struct IconOutput { + /// The ID of this pipeline. + pub id: usize, + /// Data on the finalized output file. + pub file: HashedFileOutput, +} + +impl IconOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + dom.select(&super::trunk_id_selector(self.id)) + .replace_with_html(format!(r#""#, self.file.file_name)); + Ok(()) + } +} diff --git a/src/pipelines/mod.rs b/src/pipelines/mod.rs index f7c20353..c20d20cb 100644 --- a/src/pipelines/mod.rs +++ b/src/pipelines/mod.rs @@ -1,4 +1,218 @@ -pub mod assets; -pub mod cargo; -pub mod html; -pub mod wasmbg; +mod copydir; +mod copyfile; +mod css; +mod html; +mod icon; +mod rust_app; +mod rust_worker; +mod sass; + +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use anyhow::{anyhow, bail, ensure, Context, Result}; +use async_std::fs; +use async_std::task::JoinHandle; +use futures::channel::mpsc::Sender; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use crate::config::RtcBuild; +use crate::pipelines::copydir::{CopyDir, CopyDirOutput}; +use crate::pipelines::copyfile::{CopyFile, CopyFileOutput}; +use crate::pipelines::css::{Css, CssOutput}; +use crate::pipelines::icon::{Icon, IconOutput}; +use crate::pipelines::rust_app::{RustApp, RustAppOutput}; +use crate::pipelines::rust_worker::{RustWorker, RustWorkerOutput}; +use crate::pipelines::sass::{Sass, SassOutput}; + +pub use html::HtmlPipeline; + +const ATTR_HREF: &str = "href"; +const ATTR_REL: &str = "rel"; +const SNIPPETS_DIR: &str = "snippets"; +const TRUNK_ID: &str = "data-trunk-id"; + +/// A model of all of the supported Trunk asset links expressed in the source HTML as `` elements. +/// +/// Trunk will remove all `` elements found in the HTML. It is the responsibility +/// of each pipeline to implement a pipeline finalizer method for its pipeline output in order to +/// update the finalized HTML for asset links and the like. +#[allow(clippy::large_enum_variant)] +pub enum TrunkLink { + Css(Css), + Sass(Sass), + Icon(Icon), + CopyFile(CopyFile), + CopyDir(CopyDir), + RustApp(RustApp), + RustWorker(RustWorker), +} + +impl TrunkLink { + /// Construct a new instance. + pub async fn from_html( + cfg: Arc, progress: ProgressBar, html_dir: Arc, ignore_chan: Option>, el: Selection<'_>, id: usize, + ) -> Result { + let rel = el + .attr(ATTR_REL) + .ok_or_else(|| anyhow!("all elements must have a `rel` attribute indicating the asset type"))?; + Ok(match rel.as_ref() { + Sass::TYPE_SASS | Sass::TYPE_SCSS => Self::Sass(Sass::new(cfg.clone(), progress, html_dir, el, id).await?), + Icon::TYPE_ICON => Self::Icon(Icon::new(cfg.clone(), progress, html_dir, el, id).await?), + Css::TYPE_CSS => Self::Css(Css::new(cfg.clone(), progress, html_dir, el, id).await?), + CopyFile::TYPE_COPY_FILE => Self::CopyFile(CopyFile::new(cfg.clone(), progress, html_dir, el, id).await?), + CopyDir::TYPE_COPY_DIR => Self::CopyDir(CopyDir::new(cfg.clone(), progress, html_dir, el, id).await?), + RustApp::TYPE_RUST_APP => Self::RustApp(RustApp::new(cfg.clone(), progress, html_dir, ignore_chan, el, id).await?), + RustWorker::TYPE_RUST_WORKER => Self::RustWorker(RustWorker::new(cfg.clone(), progress, html_dir, ignore_chan, el, id).await?), + _ => bail!( + r#"unknown attr value `rel="{}"`; please ensure the value is lowercase and is a supported asset type"#, + rel.as_ref() + ), + }) + } + + /// Spawn the build pipeline for this asset. + pub fn spawn(self) -> JoinHandle> { + match self { + TrunkLink::Css(inner) => inner.spawn(), + TrunkLink::Sass(inner) => inner.spawn(), + TrunkLink::Icon(inner) => inner.spawn(), + TrunkLink::CopyFile(inner) => inner.spawn(), + TrunkLink::CopyDir(inner) => inner.spawn(), + TrunkLink::RustApp(inner) => inner.spawn(), + TrunkLink::RustWorker(inner) => inner.spawn(), + } + } +} + +/// The output of a `` asset pipeline. +pub enum TrunkLinkPipelineOutput { + Css(CssOutput), + Sass(SassOutput), + Icon(IconOutput), + CopyFile(CopyFileOutput), + CopyDir(CopyDirOutput), + RustApp(RustAppOutput), + #[allow(dead_code)] // TODO: remove this when this pipeline type is implemented. + RustWorker(RustWorkerOutput), +} + +impl TrunkLinkPipelineOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + match self { + TrunkLinkPipelineOutput::Css(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::Sass(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::Icon(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::CopyFile(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::CopyDir(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::RustApp(out) => out.finalize(dom).await, + TrunkLinkPipelineOutput::RustWorker(out) => out.finalize(dom).await, + } + } +} + +/// An asset file to be processed by some build pipeline. +pub struct AssetFile { + /// The canonicalized path to the target file. + pub path: PathBuf, + /// The name of the file itself. + pub file_name: OsString, + /// The file stem of the asset file. + pub file_stem: OsString, + /// The extension of the file. + pub ext: String, +} + +impl AssetFile { + /// Create a new instance. + /// + /// The given path will be validated to ensure the following: + /// - that the full canonicalized path points to a file on the FS. + /// - that the file has a filename. + /// - that the file has an extension. + /// + /// Any errors returned from this constructor indicate that one of these invariants was not + /// upheld. + pub async fn new(rel_dir: &Path, mut path: PathBuf) -> Result { + // If the given path is not absolute, then we join it with the directory from which the + // relative path should be based. + if !path.is_absolute() { + path = rel_dir.join(path); + } + + // Take the path to referenced resource, if it is actually an FS path, then we continue. + let path = fs::canonicalize(&path) + .await + .with_context(|| format!("error getting canonical path for {:?}", &path))?; + ensure!(path.is_file().await, "target file does not appear to exist on disk {:?}", &path); + let file_name = match path.file_name() { + Some(file_name) => file_name.to_owned(), + None => bail!("asset has no file name {:?}", &path), + }; + let file_stem = match path.file_stem() { + Some(file_stem) => file_stem.to_owned(), + None => bail!("asset has no file name stem {:?}", &path), + }; + let ext = match path.extension() { + Some(ext) => ext.to_string_lossy().to_lowercase(), + None => bail!("asset has no file extension {:?}", &path), + }; + Ok(Self { + path: path.into(), + file_name, + file_stem, + ext, + }) + } + + /// Copy this asset to the target dir. + pub async fn copy(&self, to_dir: &Path) -> Result { + let bytes = fs::read(&self.path) + .await + .with_context(|| format!("error reading file for copying {:?}", &self.path))?; + + let file_path = to_dir.join(&self.file_name); + fs::write(&file_path, bytes) + .await + .with_context(|| format!("error copying file {:?} to {:?}", &self.path, &file_path))?; + Ok(file_path) + } + + /// Copy this asset to the target dir after hashing its contents & updating the filename with the hash. + pub async fn copy_with_hash(&self, to_dir: &Path) -> Result { + let bytes = fs::read(&self.path) + .await + .with_context(|| format!("error reading file for copying {:?}", &self.path))?; + let hash = seahash::hash(bytes.as_ref()); + let file_name = format!("{}-{:x}.{}", &self.file_stem.to_string_lossy(), hash, &self.ext); + + let file_path = to_dir.join(&file_name); + fs::write(&file_path, bytes) + .await + .with_context(|| format!("error copying file {:?} to {:?}", &self.path, &file_path))?; + Ok(HashedFileOutput { hash, file_path, file_name }) + } +} + +/// The output of a hashed file. +/// +/// A file is hashed when its contents have been read, hashed, and then a new file is written with +/// the same contents, and the filename of the new file includes the hexadecimal representation of +/// the hash before the file extension, as so: `{file_stem}-{hash}.{ext}`. +pub struct HashedFileOutput { + /// The hash of the output file. + #[allow(dead_code)] + hash: u64, + /// The canonical path to the output file. + #[allow(dead_code)] + file_path: PathBuf, + /// The output file's name. + file_name: String, +} + +/// Create the CSS selector for selecting a trunk link by ID. +pub(self) fn trunk_id_selector(id: usize) -> String { + format!(r#"link[{}="{}"]"#, TRUNK_ID, id) +} diff --git a/src/pipelines/rust_app.rs b/src/pipelines/rust_app.rs new file mode 100644 index 00000000..b956113a --- /dev/null +++ b/src/pipelines/rust_app.rs @@ -0,0 +1,262 @@ +//! Rust application pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, ensure, Context, Result}; +use async_process::{Command, Stdio}; +use async_std::fs; +use async_std::path::Path; +use async_std::task::{spawn, JoinHandle}; +use futures::channel::mpsc::Sender; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::TrunkLinkPipelineOutput; +use super::{ATTR_HREF, SNIPPETS_DIR}; +use crate::common::copy_dir_recursive; +use crate::config::{CargoMetadata, RtcBuild}; + +/// A Rust application pipeline. +pub struct RustApp { + /// The ID of this pipeline's source HTML element. + id: Option, + /// Runtime config. + cfg: Arc, + /// The progress bar used by this pipeline. + progress: ProgressBar, + /// All metadata associated with the target Cargo project. + manifest: CargoMetadata, + /// An optional channel to be used to communicate ignore paths to the watcher. + ignore_chan: Option>, + /// An optional binary name which will cause cargo & wasm-bindgen to process only the target binary. + bin: Option, +} + +impl RustApp { + pub const TYPE_RUST_APP: &'static str = "rust"; + + pub async fn new( + cfg: Arc, progress: ProgressBar, html_dir: Arc, ignore_chan: Option>, el: Selection<'_>, id: usize, + ) -> Result { + // Build the path to the target asset. + let manifest_href = el + .attr(ATTR_HREF) + .map(|tendril| { + let mut path = PathBuf::new(); + path.extend(tendril.as_ref().split('/')); + if !path.is_absolute() { + path = html_dir.join(path); + } + if !path.ends_with("Cargo.toml") { + path = path.join("Cargo.toml"); + } + path + }) + .unwrap_or_else(|| html_dir.join("Cargo.toml")); + let bin = el.attr("data-bin").map(|val| val.to_string()); + let manifest = CargoMetadata::new(&manifest_href).await?; + let id = Some(id); + + Ok(Self { + id, + cfg, + progress, + manifest, + ignore_chan, + bin, + }) + } + + pub async fn new_default( + cfg: Arc, progress: ProgressBar, html_dir: Arc, ignore_chan: Option>, + ) -> Result { + let path = html_dir.join("Cargo.toml"); + let manifest = CargoMetadata::new(&path).await?; + Ok(Self { + id: None, + cfg, + progress, + manifest, + ignore_chan, + bin: None, + }) + } + + /// Spawn a new pipeline. + pub fn spawn(self) -> JoinHandle> { + spawn(self.build()) + } + + async fn build(mut self) -> Result { + let (wasm, hashed_name) = self.cargo_build().await?; + let output = self.wasm_bindgen_build(wasm, hashed_name).await?; + Ok(TrunkLinkPipelineOutput::RustApp(output)) + } + + async fn cargo_build(&mut self) -> Result<(PathBuf, String)> { + self.progress.set_message(&format!("building {}", &self.manifest.package.name)); + if let Some(chan) = &mut self.ignore_chan { + let _ = chan.try_send(self.manifest.metadata.target_directory.clone()); + } + + // Spawn the cargo build process. + let mut args = vec![ + "build", + "--target=wasm32-unknown-unknown", + "--manifest-path", + &self.manifest.manifest_path, + ]; + if self.cfg.release { + args.push("--release"); + } + if let Some(bin) = &self.bin { + args.push("--bin"); + args.push(bin); + } + let build_output = Command::new("cargo") + .args(args.as_slice()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("error spawning cargo build")? + .output() + .await + .context("error during cargo build execution")?; + ensure!( + build_output.status.success(), + "bad status returned from cargo build: {}", + String::from_utf8_lossy(&build_output.stderr) + ); + + // Perform a final cargo invocation on success to get artifact names. + self.progress.set_message("fetching artifacts"); + args.push("--message-format=json"); + let artifacts_out = Command::new("cargo") + .args(args.as_slice()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("error spawning cargo build artifacts task")? + .output() + .await + .context("error getting cargo build artifacts info")?; + ensure!( + artifacts_out.status.success(), + "bad status returned from cargo artifacts request: {}", + String::from_utf8_lossy(&build_output.stderr) + ); + + // Stream over cargo messages to find the artifacts we are interested in. + let reader = std::io::BufReader::new(artifacts_out.stdout.as_slice()); + let artifact = cargo_metadata::Message::parse_stream(reader) + .filter_map(|msg| if let Ok(msg) = msg { Some(msg) } else { None }) + .fold(Ok(None), |acc, msg| match msg { + cargo_metadata::Message::CompilerArtifact(art) if art.package_id == self.manifest.package.id => Ok(Some(art)), + cargo_metadata::Message::BuildFinished(finished) if !finished.success => Err(anyhow!("error while fetching cargo artifact info")), + _ => acc, + })? + .ok_or_else(|| anyhow!("cargo artifacts not found for target crate"))?; + + // Get a handle to the WASM output file. + let wasm = artifact + .filenames + .into_iter() + .find(|path| path.extension().map(|ext| ext == "wasm").unwrap_or(false)) + .ok_or_else(|| anyhow!("could not find WASM output after cargo build"))?; + + // Hash the built wasm app, then use that as the out-name param. + self.progress.set_message("processing WASM"); + let wasm_bytes = async_std::fs::read(&wasm).await.context("error reading wasm file for hash generation")?; + let hashed_name = format!("index-{:x}", seahash::hash(&wasm_bytes)); + Ok((wasm, hashed_name)) + } + + async fn wasm_bindgen_build(&self, wasm: PathBuf, hashed_name: String) -> Result { + self.progress.set_message("calling wasm-bindgen"); + + // Ensure our output dir is in place. + let mode_segment = if self.cfg.release { "release" } else { "debug" }; + let bindgen_out = self.manifest.metadata.target_directory.join("wasm-bindgen").join(mode_segment); + fs::create_dir_all(bindgen_out.as_path()) + .await + .context("error creating wasm-bindgen output dir")?; + + // Build up args for calling wasm-bindgen. + let arg_out_path = format!("--out-dir={}", bindgen_out.display()); + let arg_out_name = format!("--out-name={}", &hashed_name); + let target_wasm = wasm.to_string_lossy().to_string(); + let args = vec!["--target=web", &arg_out_path, &arg_out_name, "--no-typescript", &target_wasm]; + + // Invoke wasm-bindgen. + let build_output = Command::new("wasm-bindgen") + .args(args.as_slice()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("error spawning wasm-bindgen call")? + .output() + .await + .context("error during wasm-bindgen call")?; + ensure!( + build_output.status.success(), + "wasm-bindgen call returned a bad status {}", + String::from_utf8_lossy(&build_output.stderr), + ); + + // Copy the generated WASM & JS loader to the dist dir. + self.progress.set_message("copying generated artifacts"); + let hashed_js_name = format!("{}.js", &hashed_name); + let hashed_wasm_name = format!("{}_bg.wasm", &hashed_name); + let js_loader_path = bindgen_out.join(&hashed_js_name); + let js_loader_path_dist = self.cfg.dist.join(&hashed_js_name); + let wasm_path = bindgen_out.join(&hashed_wasm_name); + let wasm_path_dist = self.cfg.dist.join(&hashed_wasm_name); + fs::copy(js_loader_path, js_loader_path_dist) + .await + .context("error copying JS loader file to dist dir")?; + fs::copy(wasm_path, wasm_path_dist).await.context("error copying wasm file to dist dir")?; + + // Check for any snippets, and copy them over. + let snippets_dir = bindgen_out.join(SNIPPETS_DIR); + if Path::new(&snippets_dir).exists().await { + copy_dir_recursive(bindgen_out.join(SNIPPETS_DIR), self.cfg.dist.join(SNIPPETS_DIR)) + .await + .context("error copying snippets dir")?; + } + + Ok(RustAppOutput { + id: self.id, + cfg: self.cfg.clone(), + js_output: hashed_js_name, + wasm_output: hashed_wasm_name, + }) + } +} + +/// The output of a cargo build pipeline. +pub struct RustAppOutput { + /// The ID of this pipeline. + pub id: Option, + pub cfg: Arc, + /// The filename of the generated JS loader file written to the dist dir. + pub js_output: String, + /// The filename of the generated WASM file written to the dist dir. + pub wasm_output: String, +} + +impl RustAppOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + let script = format!( + r#""#, + base = self.cfg.public_url, + js = &self.js_output, + wasm = &self.wasm_output, + ); + match self.id { + Some(id) => dom.select(&super::trunk_id_selector(id)).replace_with_html(script), + None => dom.select("html head").append_html(script), + } + Ok(()) + } +} diff --git a/src/pipelines/rust_worker.rs b/src/pipelines/rust_worker.rs new file mode 100644 index 00000000..5fa35224 --- /dev/null +++ b/src/pipelines/rust_worker.rs @@ -0,0 +1,61 @@ +//! Rust web worker pipeline. + +#![allow(dead_code, unused_variables)] // TODO: remove this when this pipeline type is implemented. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{bail, Result}; +use async_std::task::JoinHandle; +use futures::channel::mpsc::Sender; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::TrunkLinkPipelineOutput; +use crate::config::{CargoMetadata, RtcBuild}; + +/// A Rust web worker pipeline. +pub struct RustWorker { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime config. + cfg: Arc, + /// The progress bar used by this pipeline. + progress: ProgressBar, + /// All metadata associated with the target Cargo project. + manifest: CargoMetadata, + /// An optional channel to be used to communicate ignore paths to the watcher. + ignore_chan: Option>, +} + +impl RustWorker { + pub const TYPE_RUST_WORKER: &'static str = "rust-worker"; + + pub async fn new( + cfg: Arc, progress: ProgressBar, html_dir: Arc, ignore_chan: Option>, el: Selection<'_>, id: usize, + ) -> Result { + bail!(r#"the rust web worker asset type `` is not yet supported"#) + } + + /// Spawn a new pipeline. + pub fn spawn(self) -> JoinHandle> { + unimplemented!() + } +} + +/// The output of a cargo build pipeline for a Rust web worker. +pub struct RustWorkerOutput { + /// The ID of this pipeline. + pub id: Option, + pub cfg: Arc, + /// The filename of the generated JS loader file written to the dist dir. + pub js_output: String, + /// The filename of the generated WASM file written to the dist dir. + pub wasm_output: String, +} + +impl RustWorkerOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + unimplemented!() + } +} diff --git a/src/pipelines/sass.rs b/src/pipelines/sass.rs new file mode 100644 index 00000000..935bfcf2 --- /dev/null +++ b/src/pipelines/sass.rs @@ -0,0 +1,84 @@ +//! Sass/Scss asset pipeline. + +use std::path::PathBuf; +use std::sync::Arc; + +use anyhow::{anyhow, Context, Result}; +use async_std::fs; +use async_std::task::{spawn, spawn_blocking, JoinHandle}; +use indicatif::ProgressBar; +use nipper::{Document, Selection}; + +use super::ATTR_HREF; +use super::{AssetFile, HashedFileOutput, TrunkLinkPipelineOutput}; +use crate::config::RtcBuild; + +/// A sass/scss asset pipeline. +pub struct Sass { + /// The ID of this pipeline's source HTML element. + id: usize, + /// Runtime build config. + cfg: Arc, + /// The progress bar to use for this pipeline. + progress: ProgressBar, + /// The asset file being processed. + asset: AssetFile, +} + +impl Sass { + pub const TYPE_SASS: &'static str = "sass"; + pub const TYPE_SCSS: &'static str = "scss"; + + pub async fn new(cfg: Arc, progress: ProgressBar, html_dir: Arc, el: Selection<'_>, id: usize) -> Result { + // Build the path to the target asset. + let href_attr = el + .attr(ATTR_HREF) + .ok_or_else(|| anyhow!("required attr `href` missing for element: {}", el.html()))?; + let mut path = PathBuf::new(); + path.extend(href_attr.as_ref().split('/')); + let asset = AssetFile::new(&html_dir, path).await?; + Ok(Self { id, cfg, progress, asset }) + } + + /// Spawn the pipeline for this asset type. + pub fn spawn(self) -> JoinHandle> { + spawn(async move { + // Compile the target SASS/SCSS file. + let path_str = self.asset.path.to_string_lossy().to_string(); + let mut opts = sass_rs::Options::default(); + if self.cfg.release { + opts.output_style = sass_rs::OutputStyle::Compressed; + } + let css = spawn_blocking(move || sass_rs::compile_file(&path_str, opts)).await.map_err(|err| { + self.progress.println(err); + anyhow!("error compiling sass for {:?}", &self.asset.path) + })?; + + // Hash the contents to generate a file name, and then write the contents to the dist dir. + let hash = seahash::hash(css.as_bytes()); + let file_name = format!("{}-{:x}.css", &self.asset.file_stem.to_string_lossy(), hash); + let file_path = self.cfg.dist.join(&file_name); + fs::write(&file_path, css).await.context("error writing SASS pipeline output")?; + Ok(TrunkLinkPipelineOutput::Sass(SassOutput { + id: self.id, + file: HashedFileOutput { hash, file_path, file_name }, + })) + }) + } +} + +/// The output of a sass/scss build pipeline. +pub struct SassOutput { + /// The ID of this pipeline. + pub id: usize, + /// Data on the finalized output file. + pub file: HashedFileOutput, +} + +impl SassOutput { + pub async fn finalize(self, dom: &mut Document) -> Result<()> { + dom.select(&super::trunk_id_selector(self.id)) + .replace_with_html(format!(r#""#, self.file.file_name)); + Ok(()) + } +} diff --git a/src/pipelines/wasmbg.rs b/src/pipelines/wasmbg.rs deleted file mode 100644 index 5f6d45ab..00000000 --- a/src/pipelines/wasmbg.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! WASM bindgen pipelines. - -use std::path::PathBuf; -use std::sync::Arc; - -use anyhow::{ensure, Context, Result}; -use async_process::{Command, Stdio}; -use async_std::fs; -use async_std::task::{spawn, JoinHandle}; -use indicatif::ProgressBar; - -use crate::common::copy_dir_recursive; -use crate::config::RtcBuild; -use crate::pipelines::cargo::CargoBuildOutput; - -const SNIPPETS_DIR: &str = "snippets"; - -/// A wasm-bindgen build pipeline. -pub struct WasmBindgen { - /// Runtime config. - cfg: Arc, - /// The output dir of the wasm-bindgen execution. - bindgen_out: Arc, - /// The progress bar used by this pipeline. - progress: ProgressBar, -} - -impl WasmBindgen { - /// Create a new instance. - pub fn new(cfg: Arc, bindgen_out: Arc, progress: ProgressBar) -> Self { - Self { cfg, bindgen_out, progress } - } - - /// Spawn a new pipeline. - pub fn spawn(self: Arc, cargo: JoinHandle>) -> JoinHandle> { - spawn(self.build(cargo)) - } - - /// Perform the build routine of this pipeline. - async fn build(self: Arc, cargo: JoinHandle>) -> Result { - self.progress.set_message("awaiting cargo build"); - let cargo = cargo.await?; - self.progress.set_message("executing"); - let arg_out_path = format!("--out-dir={}", self.bindgen_out.display()); - let arg_out_name = format!("--out-name={}", &cargo.hashed_name); - let target_wasm = cargo.wasm.to_string_lossy().to_string(); - - // Ensure our output dir is in place. - fs::create_dir_all(self.bindgen_out.as_path()) - .await - .context("error creating wasm-bindgen output dir")?; - - // Spawn the wasm-bindgen process. - let args = vec!["--target=web", &arg_out_path, &arg_out_name, "--no-typescript", &target_wasm]; - let build_output = Command::new("wasm-bindgen") - .args(args.as_slice()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context("error spawning wasm-bindgen call")? - .output() - .await - .context("error during wasm-bindgen call")?; - ensure!( - build_output.status.success(), - "wasm-bindgen call returned a bad status {}", - String::from_utf8_lossy(&build_output.stderr), - ); - - // Copy the generated WASM & JS loader to the dist dir. - self.progress.set_message("copying generated artifacts"); - let hashed_js_name = format!("{}.js", &cargo.hashed_name); - let hashed_wasm_name = format!("{}_bg.wasm", &cargo.hashed_name); - let js_loader_path = self.bindgen_out.join(&hashed_js_name); - let js_loader_path_dist = self.cfg.dist.join(&hashed_js_name); - let wasm_path = self.bindgen_out.join(&hashed_wasm_name); - let wasm_path_dist = self.cfg.dist.join(&hashed_wasm_name); - fs::copy(js_loader_path, js_loader_path_dist) - .await - .context("error copying JS loader file to dist dir")?; - fs::copy(wasm_path, wasm_path_dist).await.context("error copying wasm file to dist dir")?; - - // Check for any snippets, and copy them over. - copy_dir_recursive(self.bindgen_out.join(SNIPPETS_DIR), self.cfg.dist.join(SNIPPETS_DIR)) - .await - .context("error copying snippets dir")?; - - Ok(WasmBindgenOutput { - js_output: hashed_js_name, - wasm_output: hashed_wasm_name, - }) - } -} - -/// The output of the wasm-bindgen process. -pub struct WasmBindgenOutput { - /// The filename of the generated JS loader file written to the dist dir. - pub js_output: String, - /// The filename of the generated WASM file written to the dist dir. - pub wasm_output: String, -} diff --git a/src/watch.rs b/src/watch.rs index 04db7726..a8752a9e 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -1,104 +1,115 @@ use std::path::PathBuf; -use std::sync::mpsc::channel as std_channel; use std::sync::Arc; -use std::time::Duration; -use anyhow::{anyhow, Result}; -use async_std::sync::channel; -use async_std::task::spawn_blocking; -use futures::stream::{FusedStream, StreamExt}; +use anyhow::{anyhow, Context, Result}; +use async_std::task::{spawn_blocking, JoinHandle}; +use futures::channel::mpsc::{channel, Receiver, Sender}; +use futures::prelude::*; use indicatif::ProgressBar; -use notify::{watcher, RecursiveMode, Watcher}; +use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use crate::build::BuildSystem; use crate::config::RtcWatch; /// A watch system wrapping a build system and a watcher. pub struct WatchSystem { + /// The build system progress bar for displaying the state of the build system overall. + progress: ProgressBar, + /// The build system. build: BuildSystem, - watcher: TrunkWatcher, + /// The current vector of paths to be ignored. + ignores: Vec, + /// A channel of FS watch events. + watch_rx: Receiver, + /// A channel of new paths to ignore from the build system. + build_rx: Receiver, + /// The watch system used for watching the filesystem. + _watcher: (JoinHandle<()>, RecommendedWatcher), } impl WatchSystem { /// Create a new instance. pub async fn new(cfg: Arc, progress: ProgressBar) -> Result { + // Create a channel for being able to listen for new paths to ignore while running. + let (watch_tx, watch_rx) = channel(1); + let (build_tx, build_rx) = channel(1); + // Process ignore list. - let mut ignore = cfg.ignore.iter().try_fold(vec![], |mut acc, path| -> Result> { + let mut ignores = cfg.ignore.iter().try_fold(vec![], |mut acc, path| -> Result> { let abs_path = path.canonicalize().map_err(|err| anyhow!("invalid path provided: {}", err))?; acc.push(abs_path); Ok(acc) })?; - ignore.append(&mut vec![cfg.build.manifest.metadata.target_directory.clone(), cfg.build.dist.clone()]); + ignores.append(&mut vec![cfg.build.dist.clone()]); + + // Build the watcher. + let _watcher = build_watcher(watch_tx)?; // Build dependencies. - let build = BuildSystem::new(cfg.build.clone(), progress.clone()).await?; - let watcher = TrunkWatcher::new(ignore, progress)?; - Ok(Self { build, watcher }) + let build = BuildSystem::new(cfg.build.clone(), progress.clone(), Some(build_tx)).await?; + Ok(Self { + progress, + build, + ignores, + watch_rx, + build_rx, + _watcher, + }) } /// Run a build. pub async fn build(&mut self) { if let Err(err) = self.build.build().await { - eprintln!("{}", err); + self.progress.println(format!("{}", err)); } } /// Run the watch system, responding to events and triggering builds. pub async fn run(mut self) { - while self.watcher.rx.next().await.is_some() { - if let Err(err) = self.build.build().await { - eprintln!("{}", err); + loop { + futures::select! { + ign_res = self.build_rx.next() => if let Some(ign) = ign_res { + self.update_ignore_list(ign); + }, + ev_res = self.watch_rx.next() => if let Some(ev) = ev_res { + self.handle_watch_event(ev).await; + }, } } } -} -/// A watcher system for triggering Trunk builds. -struct TrunkWatcher { - #[allow(dead_code)] - watcher: notify::RecommendedWatcher, - rx: Box + Send + Unpin>, -} - -impl TrunkWatcher { - /// Spawn a watcher to trigger builds as changes are detected on the filesystem. - pub fn new(ignore: Vec, progress: ProgressBar) -> Result { - // Setup core watcher functionality. - let (tx, rx) = std_channel(); - let mut watcher = watcher(tx, Duration::from_secs(1)).map_err(|err| anyhow!("error setting up watcher: {}", err))?; - watcher - .watch(".", RecursiveMode::Recursive) - .map_err(|err| anyhow!("error watching current directory: {}", err))?; - - // Setup notification bridge between sync & async land. - // NOTE: once notify@v5 lands, we should be able to simplify this quite a lot. - let (async_tx, async_rx) = channel(1); - spawn_blocking(move || { - use notify::DebouncedEvent as Event; - 'outer: loop { - match rx.recv() { - Ok(event) => match event { - Event::Create(path) | Event::Write(path) | Event::Remove(path) | Event::Rename(_, path) => { - for ancestor in path.ancestors() { - if ignore.contains(&ancestor.into()) { - continue 'outer; - } - } - let _ = async_tx.try_send(()); - } - Event::Error(err, path_opt) => match path_opt { - Some(path) => progress.println(format!("watcher error at {}\n{}", path.to_string_lossy(), err)), - None => progress.println(err.to_string()), - }, - _ => continue, - }, - Err(_) => return, // An error here indicates that the watcher has closed. - } + async fn handle_watch_event(&mut self, event: DebouncedEvent) { + let ev_path = match event { + DebouncedEvent::Create(path) | DebouncedEvent::Write(path) | DebouncedEvent::Remove(path) | DebouncedEvent::Rename(_, path) => path, + _ => return, + }; + for path in ev_path.ancestors() { + if self.ignores.iter().map(|p| p.as_path()).any(|p| p == path) { + return; // Don't emit a notification if ignored. } - }); - Ok(TrunkWatcher { - watcher, - rx: Box::new(async_rx.fuse()), - }) + } + if let Err(err) = self.build.build().await { + self.progress.println(format!("{}", err)); + } + } + + fn update_ignore_list(&mut self, path: PathBuf) { + if !self.ignores.contains(&path) { + self.ignores.push(path); + } } } + +fn build_watcher(mut watch_tx: Sender) -> Result<(JoinHandle<()>, RecommendedWatcher)> { + let (tx, rx) = std::sync::mpsc::channel(); + let mut watcher = watcher(tx, std::time::Duration::from_secs(1)).context("failed to build file system watcher")?; + watcher + .watch(".", RecursiveMode::Recursive) + .context("failed to watch CWD for file system changes")?; + let handle = spawn_blocking(move || loop { + if let Ok(event) = rx.recv() { + let _ = watch_tx.try_send(event); + } + }); + Ok((handle, watcher)) +}