summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Gerace <nickagerace@gmail.com>2023-03-28 17:50:36 -0400
committerNick Gerace <nickagerace@gmail.com>2023-04-07 13:44:47 -0400
commitf3a4c1563218ac35f8ecfe131de9eb8c50292a9e (patch)
treeb949bb567eaebc108b118d65485d7b4e5eac3c6f
parentbb91ee33ca811f8cf28791710c40e8c4fe0b0aa3 (diff)
downloadgfold-f3a4c1563218ac35f8ecfe131de9eb8c50292a9e.zip
Restore cargo xtask
Primary: - Restore cargo xtask to the repository - Polish "size" and "loose-bench" tasks and integrate them with cargo xtask - Update documentation to reflect new xtask changes - Move ci to use cargo xtask Secondary: - Remove unneeded run from gfold test Signed-off-by: Nick Gerace <nickagerace@gmail.com>
-rw-r--r--.cargo/config3
-rw-r--r--.github/workflows/ci.yml23
-rw-r--r--Cargo.lock401
-rw-r--r--Cargo.toml2
-rw-r--r--crates/bench-loosely/Cargo.toml7
-rw-r--r--crates/bench-loosely/src/main.rs180
-rw-r--r--crates/gfold/Cargo.toml4
-rw-r--r--crates/gfold/src/main.rs16
-rw-r--r--crates/size/Cargo.toml7
-rw-r--r--crates/size/src/main.rs54
-rw-r--r--crates/xtask/Cargo.toml12
-rw-r--r--crates/xtask/src/main.rs69
-rw-r--r--crates/xtask/src/task.rs118
-rw-r--r--crates/xtask/src/task/bloat.rs13
-rw-r--r--crates/xtask/src/task/build.rs12
-rw-r--r--crates/xtask/src/task/build_release.rs12
-rw-r--r--crates/xtask/src/task/ci.rs19
-rw-r--r--crates/xtask/src/task/loose_bench.rs142
-rw-r--r--crates/xtask/src/task/prepare.rs15
-rw-r--r--crates/xtask/src/task/scan.rs13
-rw-r--r--crates/xtask/src/task/size.rs49
-rw-r--r--docs/DEVELOPING.md49
-rw-r--r--docs/RELEASE.md6
23 files changed, 738 insertions, 488 deletions
diff --git a/.cargo/config b/.cargo/config
index 9825746..337141e 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,2 +1,5 @@
[build]
rustdocflags = "--document-private-items"
+
+[alias]
+xtask = "run -q --manifest-path ./crates/xtask/Cargo.toml --" \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cde6f1d..6adf7dd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,28 +26,11 @@ jobs:
toolchain: stable
override: true
components: rustfmt, clippy
- - uses: actions-rs/cargo@v1
- with:
- command: fmt
- args: --all -- --check
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
- command: clippy
- args: -- -D warnings
- - uses: actions-rs/cargo@v1
- with:
- command: doc
- args: --all
- env:
- RUSTDOCFLAGS: "-Dwarnings"
- - uses: actions-rs/cargo@v1
- with:
- command: test
- - uses: actions-rs/cargo@v1
- with:
- command: build
- args: --locked
+ command: xtask
+ args: ci
build:
name: "Test / Build"
runs-on: ${{ matrix.os }}
@@ -68,4 +51,4 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: build
- args: --locked
+ args: --all-targets --locked
diff --git a/Cargo.lock b/Cargo.lock
index ba8165d..ad73ade 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "anstream"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-wincon",
+ "concolor-override",
+ "concolor-query",
+ "is-terminal",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
name = "anyhow"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -48,25 +88,12 @@ dependencies = [
]
[[package]]
-name = "bench-loosely"
-version = "0.1.0"
-dependencies = [
- "dirs 4.0.0",
-]
-
-[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
-name = "bitflags"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1"
-
-[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -83,39 +110,59 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
-version = "4.1.11"
+version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098"
+checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
dependencies = [
- "bitflags 2.0.2",
+ "clap_builder",
"clap_derive",
- "clap_lex",
- "is-terminal",
"once_cell",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "bitflags",
+ "clap_lex",
"strsim",
- "termcolor",
]
[[package]]
name = "clap_derive"
-version = "4.1.9"
+version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644"
+checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
dependencies = [
"heck",
- "proc-macro-error",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.13",
]
[[package]]
name = "clap_lex"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+
+[[package]]
+name = "concolor-override"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
+
+[[package]]
+name = "concolor-query"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646"
+checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
dependencies = [
- "os_str_bytes",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -179,31 +226,11 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "dirs"
-version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
-dependencies = [
- "dirs-sys 0.3.7",
-]
-
-[[package]]
-name = "dirs"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd"
dependencies = [
- "dirs-sys 0.4.0",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
+ "dirs-sys",
]
[[package]]
@@ -235,13 +262,13 @@ dependencies = [
[[package]]
name = "errno"
-version = "0.2.8"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0"
dependencies = [
"errno-dragonfly",
"libc",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -274,9 +301,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.8"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
@@ -289,7 +316,7 @@ version = "4.3.2"
dependencies = [
"anyhow",
"clap",
- "dirs 5.0.0",
+ "dirs",
"env_logger",
"git2",
"log",
@@ -315,7 +342,7 @@ version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags",
"libc",
"libgit2-sys",
"log",
@@ -367,9 +394,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.9.2"
+version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
@@ -386,25 +413,25 @@ dependencies = [
[[package]]
name = "io-lifetimes"
-version = "1.0.9"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
+checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [
"hermit-abi 0.3.1",
"libc",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
name = "is-terminal"
-version = "0.4.5"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e"
+checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -424,9 +451,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.140"
+version = "0.2.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]]
name = "libgit2-sys"
@@ -454,9 +481,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.1.4"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]]
name = "log"
@@ -517,12 +544,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
-name = "os_str_bytes"
-version = "6.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
-
-[[package]]
name = "output_vt100"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -556,34 +577,10 @@ dependencies = [
]
[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
name = "proc-macro2"
-version = "1.0.52"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [
"unicode-ident",
]
@@ -625,7 +622,16 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
]
[[package]]
@@ -635,31 +641,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom",
- "redox_syscall",
+ "redox_syscall 0.2.16",
"thiserror",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.21"
+version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b"
[[package]]
name = "rustix"
-version = "0.36.11"
+version = "0.37.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e"
+checksum = "1aef160324be24d31a62147fae491c14d2204a3865c7ca8c3b0d7f7bcb3ea635"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys 0.45.0",
+ "windows-sys 0.48.0",
]
[[package]]
+name = "rustversion"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
+
+[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -673,29 +685,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
-version = "1.0.158"
+version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
+checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.158"
+version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
+checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.3",
+ "syn 2.0.13",
]
[[package]]
name = "serde_json"
-version = "1.0.94"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
+checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
dependencies = [
"itoa",
"ryu",
@@ -712,17 +724,32 @@ dependencies = [
]
[[package]]
-name = "size"
-version = "0.1.0"
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "strum"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
dependencies = [
- "dirs 4.0.0",
+ "strum_macros",
]
[[package]]
-name = "strsim"
-version = "0.10.0"
+name = "strum_macros"
+version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 1.0.109",
+]
[[package]]
name = "syn"
@@ -737,9 +764,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.3"
+version = "2.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60"
+checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
dependencies = [
"proc-macro2",
"quote",
@@ -748,15 +775,15 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.4.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
+checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
dependencies = [
"cfg-if",
"fastrand",
- "redox_syscall",
+ "redox_syscall 0.3.5",
"rustix",
- "windows-sys 0.42.0",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -785,7 +812,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.3",
+ "syn 2.0.13",
]
[[package]]
@@ -826,9 +853,9 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.19.7"
+version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274"
+checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
dependencies = [
"indexmap",
"serde",
@@ -839,9 +866,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
-version = "0.3.12"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d502c968c6a838ead8e69b2ee18ec708802f99db92a0d156705ec9ef801993b"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
@@ -870,16 +897,16 @@ dependencies = [
]
[[package]]
-name = "vcpkg"
-version = "0.2.15"
+name = "utf8parse"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
-name = "version_check"
-version = "0.9.4"
+name = "vcpkg"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasi"
@@ -920,26 +947,20 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
-version = "0.42.0"
+version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
-version = "0.45.0"
+version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
- "windows-targets",
+ "windows-targets 0.48.0",
]
[[package]]
@@ -948,13 +969,28 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
]
[[package]]
@@ -964,51 +1000,104 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
name = "winnow"
-version = "0.3.6"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966"
+checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"memchr",
]
[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "dirs",
+ "strum",
+ "termcolor",
+ "thiserror",
+]
+
+[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 52bc1f1..764529e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-members = ["crates/*"]
+members = ["crates/gfold", "crates/xtask"]
default-members = ["crates/gfold"]
[profile.release.package.gfold]
diff --git a/crates/bench-loosely/Cargo.toml b/crates/bench-loosely/Cargo.toml
deleted file mode 100644
index d090406..0000000
--- a/crates/bench-loosely/Cargo.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "bench-loosely"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-dirs = "4.0"
diff --git a/crates/bench-loosely/src/main.rs b/crates/bench-loosely/src/main.rs
deleted file mode 100644
index 52aa498..0000000
--- a/crates/bench-loosely/src/main.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-//! This is the loose bench for gfold. Why use a loose bench over a precise one? Most of gfold
-//! development happens with a mobile processor, which is prone to performance fluctuations over
-//! background I/O operations, battery life and temperature. Moreover, the "real world" use case of
-//! gfold is via CLI and not a library. Thus, this loose bench executes gfold as a CLI similarly
-//! to real world use. This benchmark is not precise and is designed to give a high level overview.
-
-// TODO(nick): add consistency deviation. We should see how far each result strays from the average.
-// We want gfold to perform consistently as well as quickly.
-
-use std::path::Path;
-use std::process::Command;
-use std::time::{Duration, Instant};
-
-fn main() {
- let global_instant = Instant::now();
-
- let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
- let repo = manifest_dir
- .parent()
- .expect("could not get parent")
- .parent()
- .expect("could not get parent");
-
- println!("running in {:?}: cargo build --release", &repo);
- let output = Command::new("cargo")
- .arg("build")
- .arg("--release")
- .current_dir(repo)
- .output()
- .expect("could not execute command");
- if !output.status.success() {
- panic!("command failed: \"cargo build --release\"");
- }
-
- let binary = repo.join("target").join("release").join("gfold");
- let home_path = dirs::home_dir().expect("could not find home directory");
- let installed = home_path.join(".cargo").join("bin").join("gfold");
- let home = home_path.to_str().expect("could not convert to str");
-
- // Add "1" to total runs to ensure caching does not skew results. We need one
- // "warm up" run.
- let runs = 41;
-
- // Loosely bench using the home directory as the target.
- let mut home_new_durations = Vec::new();
- let mut home_old_durations = Vec::new();
- let mut first = true;
- for run in 0..runs {
- println!("group {} of {} in {}", run + 1, runs, home);
-
- // Alternate at the halfway point. Though, it is doubtful that this would actually change anything.
- // Only calculate the average after the first run to avoid caching skewing results.
- if run > runs / 2 {
- let (old_duration, new_duration) = loose_bench(&installed, &binary, &home_path);
- if first {
- first = false;
- } else {
- home_new_durations.push(new_duration);
- home_old_durations.push(old_duration);
- }
- } else {
- let (new_duration, old_duration) = loose_bench(&binary, &installed, &home_path);
- if first {
- first = false;
- } else {
- home_new_durations.push(new_duration);
- home_old_durations.push(old_duration);
- }
- }
- }
-
- // Loosely bench with the parent directory of the repository as the target.
- let parent_of_repo = repo.parent().expect("could not get parent");
- let parent = parent_of_repo.to_str().expect("could not convert to str");
- let mut parent_new_durations = Vec::new();
- let mut parent_old_durations = Vec::new();
- let mut first = true;
- for run in 0..runs {
- println!("group {} of {} in {}", run + 1, runs, parent);
-
- // Alternate at the halfway point. Though, it is doubtful that this would actually change anything.
- // Only calculate the average after the first run to avoid caching skewing results.
- if run > runs / 2 {
- let (old_duration, new_duration) = loose_bench(&installed, &binary, parent_of_repo);
- if first {
- first = false;
- } else {
- parent_new_durations.push(new_duration);
- parent_old_durations.push(old_duration);
- }
- } else {
- let (new_duration, old_duration) = loose_bench(&binary, &installed, parent_of_repo);
- if first {
- first = false;
- } else {
- parent_new_durations.push(new_duration);
- parent_old_durations.push(old_duration);
- }
- }
- }
-
- // Print the averages. Start with a multi-platform empty newline print.
- println!();
- println!(
- "Average: {:?} - {} - {}",
- average_duration(&home_new_durations),
- home,
- &binary.display(),
- );
- println!(
- "Average: {:?} - {} - {}",
- average_duration(&home_old_durations),
- home,
- &installed.display(),
- );
- println!(
- "Average: {:?} - {} - {}",
- average_duration(&parent_new_durations),
- parent,
- &binary.display(),
- );
- println!(
- "Average: {:?} - {} - {}",
- average_duration(&parent_old_durations),
- parent,
- &installed.display(),
- );
-
- // Display the global duration for the entire script. Start with a multi-platform empty newline
- // print.
- println!();
- println!("Total duration: {:?}", global_instant.elapsed());
-}
-
-fn loose_bench(first: &Path, second: &Path, target: &Path) -> (Duration, Duration) {
- let first_duration = execute(first, target);
- let second_duration = execute(second, target);
- let (first_text, second_text) = match first_duration {
- first_duration if first_duration > second_duration => ("LOST", "WON "),
- first_duration if first_duration < second_duration => ("WON ", "LOST"),
- _ => ("TIE ", "TIE "),
- };
-
- println!(
- " {} @ {:?} - {}",
- first_text,
- first_duration,
- first.to_str().expect("could not convert to str"),
- );
- println!(
- " {} @ {:?} - {}",
- second_text,
- second_duration,
- second.to_str().expect("could not convert to str"),
- );
- (first_duration, second_duration)
-}
-
-fn execute(binary: &Path, target: &Path) -> Duration {
- let start = Instant::now();
- let output = Command::new(binary)
- .arg("-i")
- .arg(target)
- .output()
- .expect("could not execute command");
- let duration = start.elapsed();
-
- // Check for failure _after_ the bench finishes.
- if !output.status.success() {
- panic!("bench failed");
- }
-
- duration
-}
-
-fn average_duration(durations: &[Duration]) -> Duration {
- let sum = durations.iter().sum::<Duration>();
- let count = durations.len() as f32;
- sum.div_f32(count)
-}
diff --git a/crates/gfold/Cargo.toml b/crates/gfold/Cargo.toml
index 76daf14..fdb581f 100644
--- a/crates/gfold/Cargo.toml
+++ b/crates/gfold/Cargo.toml
@@ -14,7 +14,7 @@ version = "4.3.2"
[dependencies]
anyhow = { version = "1.0", features = ["backtrace"] }
-clap = { version = "4.1", features = ["derive"] }
+clap = { version = "4.2", features = ["derive"] }
dirs = "5.0"
env_logger = { version = "0.10", features = ["humantime"], default_features = false }
git2 = { version = "0.16", default_features = false }
@@ -28,4 +28,4 @@ toml = "0.7"
[dev-dependencies]
pretty_assertions = "1.3"
-tempfile = "3.4"
+tempfile = "3.5"
diff --git a/crates/gfold/src/main.rs b/crates/gfold/src/main.rs
index 964fd5e..47175b5 100644
--- a/crates/gfold/src/main.rs
+++ b/crates/gfold/src/main.rs
@@ -50,9 +50,8 @@ mod tests {
use tempfile::tempdir;
use crate::collector::{RepositoryCollection, RepositoryCollector};
- use crate::config::{ColorMode, Config, DisplayMode};
+ use crate::config::{Config, DisplayMode};
use crate::repository_view::RepositoryView;
- use crate::run::RunHarness;
use crate::status::Status;
/// This integration test for `gfold` covers an end-to-end usage scenario. It uses the
@@ -129,15 +128,8 @@ mod tests {
commit_head_and_create_branch(&repository, "needtopush")?;
repository.set_head("refs/heads/needtopush")?;
- // Run once with default display mode.
- let mut config = Config::try_config_default()?;
- config.path = root.path().to_path_buf();
- config.color_mode = ColorMode::Never;
- let run_harness = RunHarness::new(&config);
- run_harness.run()?;
-
- // Now, let's run a second time, but generate the collection directly and ensure the
- // resulting views match what we expect.
+ // Generate the collection directly with a default config and ensure the resulting views
+ // match what we expect.
let mut expected_collection = RepositoryCollection::new();
let expected_views_key = root
.path()
@@ -216,6 +208,8 @@ mod tests {
expected_collection.insert(Some(nested_expected_views_key), nested_expected_views_raw);
// Generate a collection. Use classic display mode to avoid collecting email results.
+ let mut config = Config::try_config_default()?;
+ config.path = root.path().to_path_buf();
config.display_mode = DisplayMode::Classic;
let found_collection = RepositoryCollector::run(&config.path, config.display_mode)?;
diff --git a/crates/size/Cargo.toml b/crates/size/Cargo.toml
deleted file mode 100644
index 9b56e93..0000000
--- a/crates/size/Cargo.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "size"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-dirs = "4.0"
diff --git a/crates/size/src/main.rs b/crates/size/src/main.rs
deleted file mode 100644
index bd9b313..0000000
--- a/crates/size/src/main.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use std::fs;
-use std::fs::Metadata;
-use std::io;
-use std::path::{Path, PathBuf};
-use std::process::Command;
-
-fn main() {
- let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
- let repo = manifest_dir
- .parent()
- .expect("could not get parent")
- .parent()
- .expect("could not get parent");
-
- println!("running in {:?}: cargo build --release", &repo);
- let output = Command::new("cargo")
- .arg("build")
- .arg("--release")
- .current_dir(repo)
- .output()
- .expect("could not execute command");
- if !output.status.success() {
- panic!("command failed: \"cargo build --release\"");
- }
-
- let binary = repo.join("target").join("release").join("gfold");
- let metadata = fs::metadata(&binary).expect("could not get metadata");
- print_binary_size(&metadata, &binary);
-
- // Check if the binary is currently installed to compare release build sizes. If it is not,
- // we can skip this check.
- let home = dirs::home_dir().expect("could not find home directory");
- let installed = home.join(".cargo").join("bin").join("gfold");
- match fs::metadata(&installed) {
- Ok(metadata) => {
- print_binary_size(&metadata, &installed);
- }
- Err(e) if e.kind() == io::ErrorKind::NotFound => {}
- Err(e) => panic!(
- "encountered error when trying to get metadata for file: {}",
- e.to_string()
- ),
- }
-}
-
-fn print_binary_size(metadata: &Metadata, path: &PathBuf) {
- // Divisor used to perform human readable size conversion.
- // 1048576.0 = 1024.0 * 1024.0
- println!(
- "{:.3} MB - {}",
- metadata.len() as f64 / 1048576.0,
- path.to_str().expect("could not convert to str")
- );
-}
diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml
new file mode 100644
index 0000000..901a138
--- /dev/null
+++ b/crates/xtask/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "xtask"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+clap = { version = "4.2", features = ["derive"] }
+dirs = "5.0"
+strum = { version = "0.24", features = ["derive"] }
+termcolor = "1.2"
+thiserror = "1.0" \ No newline at end of file
diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs
new file mode 100644
index 0000000..c1d7d5a
--- /dev/null
+++ b/crates/xtask/src/main.rs
@@ -0,0 +1,69 @@
+//! This crate is an example of the [`cargo-xtask`](https://github.com/matklad/cargo-xtask) pattern.
+
+mod task;
+
+use clap::{Parser, Subcommand};
+use std::io;
+use std::process::Output;
+use strum::Display;
+use thiserror::Error;
+
+pub use task::TaskHarness;
+pub use task::TaskRunner;
+
+#[derive(Error, Debug)]
+pub enum TaskError {
+ #[error(transparent)]
+ Io(#[from] io::Error),
+
+ #[error("cargo command failed")]
+ CargoCommandFailed,
+ #[error("could not determine repository root")]
+ CouldNotDetermineRepositoryRoot,
+ #[error("home directory not found")]
+ HomeDirectoryNotFound,
+ #[error("invalid task provided: {0}")]
+ InvalidTaskProvided(String),
+ #[error("repository does not have parent directory (this should be impossible)")]
+ RepositoryDoesNotHaveParentDirectory,
+ #[error("command during loose bench was not successful: {0:?}")]
+ UnsuccessfulCommandDuringLooseBench(Output),
+}
+
+pub type TaskResult<T> = Result<T, TaskError>;
+
+#[derive(Parser)]
+#[command(long_about = None)]
+struct Cli {
+ #[command(subcommand)]
+ command: Task,
+}
+
+#[derive(Display, Subcommand)]
+#[strum(serialize_all = "kebab-case")]
+pub enum Task {
+ /// Scan for potential bloat
+ Bloat,
+ /// Build all targets
+ Build,
+ /// Build all targets, scan and check binary size
+ BuildRelease,
+ /// Run the ci suite
+ Ci,
+ /// Perform loose bench
+ LooseBench,
+ /// Run update, and baseline lints and checks
+ Prepare,
+ /// Scan for vulnerabilities and unused dependencies
+ Scan,
+ /// Get the release binary size (and compare to the installed binary size from "crates.io", if
+ /// it exists)
+ Size,
+}
+
+fn main() -> TaskResult<()> {
+ let cli = Cli::parse();
+ let mut harness = TaskHarness::new()?;
+ harness.task(cli.command)?;
+ Ok(())
+}
diff --git a/crates/xtask/src/task.rs b/crates/xtask/src/task.rs
new file mode 100644
index 0000000..d5d4bc9
--- /dev/null
+++ b/crates/xtask/src/task.rs
@@ -0,0 +1,118 @@
+mod bloat;
+mod build;
+mod build_release;
+mod ci;
+mod loose_bench;
+mod prepare;
+mod scan;
+mod size;
+
+use std::io::Write;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};
+
+use crate::task::bloat::RunBloat;
+use crate::task::build::RunBuild;
+use crate::task::build_release::RunBuildRelease;
+use crate::task::ci::RunCi;
+use crate::task::loose_bench::RunLooseBench;
+use crate::task::prepare::RunPrepare;
+use crate::task::scan::RunScan;
+use crate::task::size::RunSize;
+use crate::{Task, TaskError, TaskResult};
+
+const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
+const CRATE: &str = "gfold";
+const ROOT_PREFIX: &str = "xtask";
+
+pub struct TaskHarness {
+ root: PathBuf,
+ prefix: Vec<String>,
+}
+
+pub trait TaskRunner {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()>;
+}
+
+enum WriteKind {
+ Stdout,
+ Stderr,
+}
+
+impl TaskHarness {
+ pub fn new() -> TaskResult<Self> {
+ let root = match Path::new(CARGO_MANIFEST_DIR).ancestors().nth(2) {
+ Some(found_root) => found_root.to_path_buf(),
+ None => return Err(TaskError::CouldNotDetermineRepositoryRoot),
+ };
+ Ok(Self {
+ root,
+ prefix: vec![ROOT_PREFIX.to_string()],
+ })
+ }
+
+ pub fn task(&mut self, task: Task) -> TaskResult<()> {
+ self.prefix.push(task.to_string());
+
+ match task {
+ Task::Bloat => RunBloat::run(self)?,
+ Task::Build => RunBuild::run(self)?,
+ Task::BuildRelease => RunBuildRelease::run(self)?,
+ Task::Ci => RunCi::run(self)?,
+ Task::Prepare => RunPrepare::run(self)?,
+ Task::Scan => RunScan::run(self)?,
+ Task::Size => RunSize::run(self)?,
+ Task::LooseBench => RunLooseBench::run(self)?,
+ }
+
+ self.prefix.pop();
+ Ok(())
+ }
+
+ pub fn stdout(&self, contents: impl AsRef<str>) -> TaskResult<()> {
+ self.write(contents, WriteKind::Stdout)
+ }
+
+ pub fn stderr(&self, contents: impl AsRef<str>) -> TaskResult<()> {
+ self.write(contents, WriteKind::Stderr)
+ }
+
+ fn write(&self, contents: impl AsRef<str>, kind: WriteKind) -> TaskResult<()> {
+ let mut buffer = match kind {
+ WriteKind::Stdout => StandardStream::stdout(ColorChoice::Auto),
+ WriteKind::Stderr => StandardStream::stderr(ColorChoice::Auto),
+ };
+
+ buffer.set_color(ColorSpec::new().set_bold(true))?;
+ write!(&mut buffer, "{} ", self.prefix.join(":"))?;
+
+ buffer.reset()?;
+ writeln!(&mut buffer, "{}", contents.as_ref())?;
+ Ok(())
+ }
+
+ fn cargo(
+ &self,
+ args: &'static str,
+ env: Option<(&'static str, &'static str)>,
+ ) -> TaskResult<()> {
+ let mut cmd = Command::new("cargo");
+ if let Some((key, value)) = env {
+ cmd.env(key, value);
+ self.stdout(format!("{key}={value} cargo {args}"))?;
+ } else {
+ self.stdout(format!("cargo {args}"))?;
+ }
+ match cmd
+ .current_dir(&self.root)
+ .env("CARGO_TERM_COLOR", "always")
+ .args(args.trim().split(' '))
+ .status()?
+ .success()
+ {
+ true => Ok(()),
+ false => Err(TaskError::CargoCommandFailed),
+ }
+ }
+}
diff --git a/crates/xtask/src/task/bloat.rs b/crates/xtask/src/task/bloat.rs
new file mode 100644
index 0000000..7880036
--- /dev/null
+++ b/crates/xtask/src/task/bloat.rs
@@ -0,0 +1,13 @@
+use crate::TaskHarness;
+use crate::TaskResult;
+use crate::TaskRunner;
+
+pub struct RunBloat;
+
+impl TaskRunner for RunBloat {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.cargo("bloat --release", None)?;
+ harness.cargo("bloat --release --crates", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/build.rs b/crates/xtask/src/task/build.rs
new file mode 100644
index 0000000..e1ea8a2
--- /dev/null
+++ b/crates/xtask/src/task/build.rs
@@ -0,0 +1,12 @@
+use crate::task::TaskRunner;
+use crate::TaskHarness;
+use crate::TaskResult;
+
+pub struct RunBuild;
+
+impl TaskRunner for RunBuild {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.cargo("build --all-targets", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/build_release.rs b/crates/xtask/src/task/build_release.rs
new file mode 100644
index 0000000..64b5e63
--- /dev/null
+++ b/crates/xtask/src/task/build_release.rs
@@ -0,0 +1,12 @@
+use crate::TaskHarness;
+use crate::TaskResult;
+use crate::TaskRunner;
+
+pub struct RunBuildRelease;
+
+impl TaskRunner for RunBuildRelease {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.cargo("build --release", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/ci.rs b/crates/xtask/src/task/ci.rs
new file mode 100644
index 0000000..979f499
--- /dev/null
+++ b/crates/xtask/src/task/ci.rs
@@ -0,0 +1,19 @@
+use crate::TaskResult;
+use crate::{TaskHarness, TaskRunner};
+
+pub struct RunCi;
+
+impl TaskRunner for RunCi {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.cargo("fmt --all -- --check", None)?;
+ harness.cargo("check --all-targets --all-features --workspace", None)?;
+ harness.cargo(
+ "clippy --all-targets --all-features --no-deps --workspace -- -D warnings",
+ None,
+ )?;
+ harness.cargo("doc --all --no-deps", Some(("RUSTDOCFLAGS", "-Dwarnings")))?;
+ harness.cargo("test --all-targets", None)?;
+ harness.cargo("build --locked --all-targets", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/loose_bench.rs b/crates/xtask/src/task/loose_bench.rs
new file mode 100644
index 0000000..91c0ee7
--- /dev/null
+++ b/crates/xtask/src/task/loose_bench.rs
@@ -0,0 +1,142 @@
+//! This is the loose bench for gfold. Why use a loose bench over a precise one? Most of gfold
+//! development happens with a mobile processor, which is prone to performance fluctuations over
+//! background I/O operations, battery life and temperature. Moreover, the "real world" use case of
+//! gfold is via CLI and not a library. Thus, this loose bench executes gfold as a CLI similarly
+//! to real world use. This benchmark is neither precise nor "scientific" and is purely designed to
+//! give a high level performance overview.
+
+// TODO(nick): add consistency deviation. We should see how far each result strays from the average.
+// We want gfold to perform consistently as well as quickly.
+
+use std::cmp::Ordering;
+use std::path::Path;
+use std::process::Command;
+use std::time::{Duration, Instant};
+
+use crate::{Task, TaskError, TaskResult};
+use crate::{TaskHarness, TaskRunner};
+
+pub struct RunLooseBench;
+
+const RUNS: usize = 100;
+
+impl TaskRunner for RunLooseBench {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ let global_instant = Instant::now();
+
+ harness.task(Task::BuildRelease)?;
+
+ let release = harness.root.join("target").join("release").join("gfold");
+ let home = dirs::home_dir().ok_or(TaskError::HomeDirectoryNotFound)?;
+ let installed = home.join(".cargo").join("bin").join("gfold");
+ let target = harness
+ .root
+ .parent()
+ .ok_or(TaskError::RepositoryDoesNotHaveParentDirectory)?;
+
+ // Loosely bench with the parent directory of the repository as the target.
+ let mut release_durations = Vec::new();
+ let mut installed_durations = Vec::new();
+ let mut first = true;
+
+ // Add "1" to total runs to ensure caching does not skew results. We need one
+ // "warm up" run.
+ let runs_with_warm_up = RUNS + 1;
+ for run in 0..runs_with_warm_up {
+ println!("run {run} of {RUNS}");
+
+ // Alternate at the halfway point. Though, it is doubtful that this would actually
+ // change anything. Only calculate the average after the first run to avoid caching
+ // skewing results.
+ if run > RUNS / 2 {
+ let (old_duration, new_duration) =
+ harness.loose_bench(&installed, &release, target)?;
+ if first {
+ first = false;
+ } else {
+ release_durations.push(new_duration);
+ installed_durations.push(old_duration);
+ }
+ } else {
+ let (new_duration, old_duration) =
+ harness.loose_bench(&release, &installed, target)?;
+ if first {
+ first = false;
+ } else {
+ release_durations.push(new_duration);
+ installed_durations.push(old_duration);
+ }
+ }
+ }
+
+ let release_average = harness.average_duration(&release_durations);
+ let installed_average = harness.average_duration(&installed_durations);
+ let (difference, label) = match release_average.cmp(&installed_average) {
+ Ordering::Greater => (
+ release_average - installed_average,
+ "installed was faster than release",
+ ),
+ Ordering::Less => (
+ installed_average - release_average,
+ "release was faster than installed",
+ ),
+ Ordering::Equal => (Duration::from_millis(0), "tied"),
+ };
+
+ println!(
+ "
+target: {}
+
+ release {release_average:.2?} {}
+ installed {installed_average:.2?} {}
+ difference {difference:.2?} ({label})
+
+loose bench duration: {:.2?}",
+ target.display(),
+ &release.display(),
+ &installed.display(),
+ global_instant.elapsed()
+ );
+ Ok(())
+ }
+}
+
+impl TaskHarness {
+ fn loose_bench(
+ &self,
+ first: &Path,
+ second: &Path,
+ target: &Path,
+ ) -> TaskResult<(Duration, Duration)> {
+ let first_duration = self.execute_gfold(first, target)?;
+ let second_duration = self.execute_gfold(second, target)?;
+
+ let (first_text, second_text) = match first_duration.cmp(&second_duration) {
+ Ordering::Greater => ("slower", "faster"),
+ Ordering::Less => ("faster", "slower"),
+ Ordering::Equal => ("tied ", "tied "),
+ };
+
+ println!(" {first_text} {first_duration:.2?} {}", first.display(),);
+ println!(
+ " {second_text} {second_duration:.2?} {}",
+ second.display(),
+ );
+ Ok((first_duration, second_duration))
+ }
+
+ fn execute_gfold(&self, binary: &Path, target: &Path) -> TaskResult<Duration> {
+ let start = Instant::now();
+ let output = Command::new(binary).arg("-i").arg(target).output()?;
+ match output.status.success() {
+ true => Ok(start.elapsed()),
+ false => Err(TaskError::UnsuccessfulCommandDuringLooseBench(output)),
+ }
+ }
+
+ fn average_duration(&self, durations: &[Duration]) -> Duration {
+ let sum = durations.iter().sum::<Duration>();
+ let count = durations.len() as f32;
+ sum.div_f32(count)
+ }
+}
diff --git a/crates/xtask/src/task/prepare.rs b/crates/xtask/src/task/prepare.rs
new file mode 100644
index 0000000..eef2506
--- /dev/null
+++ b/crates/xtask/src/task/prepare.rs
@@ -0,0 +1,15 @@
+use crate::TaskResult;
+use crate::{TaskHarness, TaskRunner};
+
+pub struct RunPrepare;
+
+impl TaskRunner for RunPrepare {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.cargo("update", None)?;
+ harness.cargo("fmt", None)?;
+ harness.cargo("check --all-targets --all-features --workspace", None)?;
+ harness.cargo("fix --edition-idioms --allow-dirty --allow-staged", None)?;
+ harness.cargo("clippy --all-features --all-targets --workspace --no-deps --fix --allow-dirty --allow-staged", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/scan.rs b/crates/xtask/src/task/scan.rs
new file mode 100644
index 0000000..207bcc2
--- /dev/null
+++ b/crates/xtask/src/task/scan.rs
@@ -0,0 +1,13 @@
+use crate::{Task, TaskResult};
+use crate::{TaskHarness, TaskRunner};
+
+pub struct RunScan;
+
+impl TaskRunner for RunScan {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.task(Task::Prepare)?;
+ harness.cargo("+nightly udeps", None)?;
+ harness.cargo("audit", None)?;
+ Ok(())
+ }
+}
diff --git a/crates/xtask/src/task/size.rs b/crates/xtask/src/task/size.rs
new file mode 100644
index 0000000..b8ee730
--- /dev/null
+++ b/crates/xtask/src/task/size.rs
@@ -0,0 +1,49 @@
+use std::path::PathBuf;
+use std::{fs, io};
+
+use crate::task::CRATE;
+use crate::TaskResult;
+use crate::{Task, TaskError};
+use crate::{TaskHarness, TaskRunner};
+
+pub struct RunSize;
+
+impl TaskRunner for RunSize {
+ fn run(harness: &mut TaskHarness) -> TaskResult<()> {
+ harness.task(Task::BuildRelease)?;
+
+ let binary = harness.root.join("target").join("release").join(CRATE);
+ harness.print_binary_size(&binary, false)?;
+
+ // Check if the binary is currently installed to compare release build sizes. If it is not,
+ // we can skip this check.
+ let home = dirs::home_dir().ok_or(TaskError::HomeDirectoryNotFound)?;
+ let installed = home.join(".cargo").join("bin").join(CRATE);
+ harness.print_binary_size(&installed, true)?;
+ Ok(())
+ }
+}
+
+impl TaskHarness {
+ fn print_binary_size(&self, binary: &PathBuf, skip_if_not_found: bool) -> TaskResult<()> {
+ let size = match fs::metadata(binary) {
+ Ok(metadata) => metadata.len() as f64 / 1048576.0,
+ Err(e) if e.kind() == io::ErrorKind::NotFound => match skip_if_not_found {
+ true => {
+ self.stdout(format!("skipping, binary not found: {}", binary.display()))?;
+ return Ok(());
+ }
+ false => {
+ self.stderr(format!("error binary not found: {}", binary.display()))?;
+ return Err(e.into());
+ }
+ },
+ Err(e) => return Err(e.into()),
+ };
+
+ // Divisor used to perform human readable size conversion.
+ // 1048576.0 = 1024.0 * 1024.0
+ self.stdout(format!("{:.3} MB - {}", size, binary.display()))?;
+ Ok(())
+ }
+}
diff --git a/docs/DEVELOPING.md b/docs/DEVELOPING.md
index f13e2dd..fa369bd 100644
--- a/docs/DEVELOPING.md
+++ b/docs/DEVELOPING.md
@@ -2,50 +2,9 @@
This document contains information related to development.
-## Preparing Changes
+## `cargo xtask`
-First, update dependencies and tidy your changes.
+This repository uses the [`cargo-xtask`](https://github.com/matklad/cargo-xtask) pattern for local development
+and automation.
-```shell
-cargo fmt
-cargo update
-cargo fix --edition-idioms --allow-dirty --allow-staged
-cargo clippy --all-features --all-targets --no-deps
-```
-
-Now, ensure that lints, tests, and builds succeed.
-
-```shell
-cargo fmt --all -- --check
-cargo build --all-targets
-cargo clippy -- -D warnings
-RUSTDOCFLAGS="-Dwarnings" cargo doc --all --no-deps
-cargo test -- --nocapture
-```
-
-If you'd like to mass "fix" everything, you should commit/save existing work and execute the following:
-
-```shell
-cargo fix --all-targets --all-features --allow-dirty --allow-staged
-cargo clippy --fix --all-features --all-targets --allow-dirty --allow-staged
-```
-
-## Running Performance Tests
-
-See available packages with the following command:
-
-```shell
-cargo run -p
-```
-
-## Optional Checks
-
-The following checks are optional and should be run occasionally.
-
-```shell
-# This command requires a nightly toolchain to be installed.
-cargo +nightly udeps
-cargo bloat --release
-cargo bloat --release --crates
-cargo audit
-``` \ No newline at end of file
+To see what commands are available, execute `cargo xtask` from the root of the repository. \ No newline at end of file
diff --git a/docs/RELEASE.md b/docs/RELEASE.md
index 4b87ee0..8b36897 100644
--- a/docs/RELEASE.md
+++ b/docs/RELEASE.md
@@ -13,11 +13,7 @@ Steps should be executed in sequential order.
- [ ] Verify that everything looks/works as expected:
```shell
-cargo fmt --all -- --check
-cargo clippy -- -D warnings
-cargo test
-RUSTDOCFLAGS="-Dwarnings" cargo doc --all --no-deps
-cargo build --all-targets
+cargo xtask ci
```
- [ ] Create and _do not merge_ a commit with the following message: `Update to <tag>`