summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Gerace <nickagerace@gmail.com>2022-03-30 01:06:52 -0400
committerNick Gerace <nickagerace@gmail.com>2022-03-30 01:36:38 -0400
commitfde1cd0c5f32e407cddbf677fb86d78a4e028d28 (patch)
tree1d22cf74e60598022ccd03047e6acdcfa78c237c
parent52ccb1444e7aa675430ce4016685e0a60054a1d9 (diff)
downloadgfold-fde1cd0c5f32e407cddbf677fb86d78a4e028d28.zip
Enable multi-platform development
TLDR: remove barriers to multi-platform development, like Bash and Make. Moreover, remove the nightly fmt dependency and improve testing to catch potential corner cases on multiple platforms. Core: - Rename "Reports" to "LabeledReports" since "Reports" is not of implied type Vec<Report> Testing: - Add second half to the integration test: comparing found reports with expected reports - Essentially, we run the core gfold loop _again_, but only generate reports and skip displaying them to stdout CI: - Removed nightly fmt check and job - Moved fmt check to stable - Update bors toml to match changes Scripts: - Convert scripts from Bash scripts to independent crates (multi-platform friendly) - Add README to scripts directory - Ensure script crates do not have their Cargo lockfile tracked in Git Docs: - Adding DEVELOPING file to replace Makefile - Move THANKS and RELEASE files to new docs directory, along with DEVELOPING - Replace make commands in README and RELEASE files Misc: - Remove Rust nightly dependency since it was solely for imports granulaity for rustfmt - This repository is once again only reliant on stable Rust toolchains - Remove "rust-version" from Cargo toml since it was unused - Remove Makefile entirely in favor of DEVELOPING file (multi-platform friendly) - Update markdown code block languages as "shell" instead of "bash" to be multi-platform friendly Signed-off-by: Nick Gerace <nickagerace@gmail.com>
-rw-r--r--.github/workflows/ci.yml24
-rw-r--r--Cargo.lock93
-rw-r--r--Cargo.toml4
-rw-r--r--Makefile44
-rw-r--r--README.md31
-rw-r--r--bors.toml3
-rw-r--r--docs/DEVELOPING.md48
-rw-r--r--docs/RELEASE.md (renamed from RELEASE.md)20
-rw-r--r--docs/THANKS.md (renamed from THANKS.md)0
-rw-r--r--rustfmt.toml2
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/README.md15
-rwxr-xr-xscripts/bench-loosely.sh27
-rw-r--r--scripts/bench-loosely/Cargo.toml7
-rw-r--r--scripts/bench-loosely/src/main.rs95
-rw-r--r--scripts/size/Cargo.toml7
-rw-r--r--scripts/size/src/main.rs53
-rw-r--r--src/display/mod.rs16
-rw-r--r--src/main.rs79
-rw-r--r--src/report/mod.rs14
-rw-r--r--src/status.rs2
21 files changed, 425 insertions, 160 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5ef7f93..0e892b2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,44 +10,32 @@ on:
paths:
- "**.rs"
- "Cargo.*"
- - "rustfmt.toml"
+ - "*.toml"
+ - ".github/workflows/ci.yml"
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
- lint:
- name: "Nightly Fmt Check"
+ test:
+ name: "Lint, Test, and Build (ubuntu-latest)"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- # Do not use "rust-cache" since nightly will wipe out the cache daily
- uses: actions-rs/toolchain@v1
with:
profile: minimal
- toolchain: nightly
+ toolchain: stable
override: true
- components: rustfmt
+ components: rustfmt, clippy
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- test:
- name: "Clippy Lint, Test, and Build (ubuntu-latest)"
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- components: clippy
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings
- # FIXME: use cargo nextest
- uses: actions-rs/cargo@v1
with:
command: test
diff --git a/Cargo.lock b/Cargo.lock
index 6b83455..386095e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,6 +3,15 @@
version = 3
[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
name = "argh"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -71,9 +80,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-channel"
-version = "0.5.2"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
+checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -92,10 +101,11 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.7"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
+checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
+ "autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
@@ -105,15 +115,31 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
+checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
+name = "ctor"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "diff"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
+
+[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -124,9 +150,9 @@ dependencies = [
[[package]]
name = "dirs-sys"
-version = "0.3.6"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
@@ -162,9 +188,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
+checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if",
"libc",
@@ -180,6 +206,7 @@ dependencies = [
"env_logger",
"git2",
"log",
+ "pretty_assertions",
"rayon",
"serde",
"serde_json",
@@ -259,9 +286,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.119"
+version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
+checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "libgit2-sys"
@@ -289,9 +316,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.14"
+version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if",
]
@@ -322,6 +349,15 @@ dependencies = [
]
[[package]]
+name = "output_vt100"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -334,6 +370,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
+name = "pretty_assertions"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c038cb5319b9c704bf9c227c261d275bfec0ad438118a2787ce47944fb228b"
+dependencies = [
+ "ansi_term",
+ "ctor",
+ "diff",
+ "output_vt100",
+]
+
+[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -344,9 +392,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.15"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
+checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
@@ -378,21 +426,22 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.11"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
+checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
-version = "0.4.0"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
+checksum = "7776223e2696f1aa4c6b0170e83212f47296a00424305117d013dfe86fb0fe55"
dependencies = [
"getrandom",
"redox_syscall",
+ "thiserror",
]
[[package]]
@@ -440,9 +489,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.86"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
+checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index d9b8ecc..1229fd9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,6 @@ repository = "https://github.com/nickgerace/gfold/"
edition = "2021"
version = "4.0.0-rc.1"
-rust-version = "1.56.1"
[dependencies]
argh = "0"
@@ -29,6 +28,9 @@ toml = "0"
# Removed features: ["regex", "termcolor"]
env_logger = { version = "0", features = ["atty", "humantime"], default_features = false }
+[dev-dependencies]
+pretty_assertions = "1"
+
[profile.release]
codegen-units = 1
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 8d5b0a6..0000000
--- a/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-MAKEPATH := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
-
-.DEFAULT_GOAL := prepare
-
-prepare:
- cd $(MAKEPATH); cargo +nightly fmt
- cd $(MAKEPATH); cargo update
- cd $(MAKEPATH); cargo fix --edition-idioms --allow-dirty --allow-staged
- cd $(MAKEPATH); cargo clippy --all-features --all-targets
-.PHONY: prepare
-
-lint:
- cd $(MAKEPATH); cargo +nightly fmt --all -- --check
- cd $(MAKEPATH); cargo clippy -- -D warnings
-.PHONY: lint
-
-test:
- cd $(MAKEPATH); cargo nextest run --success-output immediate
-.PHONY: test
-
-scan:
- cd $(MAKEPATH); cargo +nightly udeps
- cd $(MAKEPATH); cargo bloat --release
- cd $(MAKEPATH); cargo bloat --release --crates
- cd $(MAKEPATH); cargo audit
- cd $(MAKEPATH); cargo msrv
-.PHONY: scan
-
-clean:
- cd $(MAKEPATH); cargo clean
-.PHONY: clean
-
-install:
- cargo install --locked --path $(MAKEPATH)
-.PHONY: install
-
-bench-loosely:
- $(MAKEPATH)/scripts/bench-loosely.sh
-.PHONY: bench-loosely
-
-size:
- cd $(MAKEPATH); cargo build --release
- @du -h $(MAKEPATH)/target/release/gfold
-.PHONY: size
diff --git a/README.md b/README.md
index bf301e3..2fb27c7 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@ gfold ../../this/is/a/relative/path
Upon execution, `gfold` will look for a config file at the following path on macOS, Linux and similar operating systems:
-```bash
+```shell
$HOME/.config/gfold.toml
```
@@ -96,7 +96,7 @@ Creating and using the config file is entirely optional, and you can ignore your
Here is an example creation workflow for a config file:
-```bash
+```shell
gfold --classic ~/ --print > $HOME/.config/gfold.toml
```
@@ -112,7 +112,7 @@ display_mode = 'Classic'
You can back up a config file and track its history with `git`.
On macOS, Linux, and most systems, you can link the file back to a `git` repository.
-```bash
+```shell
ln -s path/to/repository/gfold.toml $HOME/.config/gfold.toml
```
@@ -124,7 +124,7 @@ Now, you can update the config file within your repository and include the linki
**macOS users:** you can use [Homebrew](https://brew.sh) to install the [tap](https://github.com/nickgerace/homebrew-nickgerace/blob/main/Formula/gfold.rb).
-```bash
+```shell
brew install nickgerace/nickgerace/gfold
```
@@ -132,13 +132,13 @@ _Note:_ the tap may not work with [Linuxbrew](https://docs.brew.sh/Homebrew-on-L
**Arch Linux users:** you can use [pacman](https://wiki.archlinux.org/title/Pacman) to install `gfold` from the [community repository](https://archlinux.org/packages/community/x86_64/gfold/).
-```bash
+```shell
pacman -S gfold
```
If you'd like the [development (VCS) package](https://aur.archlinux.org/packages/gfold-git/), you can install it from the AUR.
-```bash
+```shell
paru -S gfold-git
```
@@ -146,36 +146,35 @@ _Note:_ the above example uses [paru](https://github.com/Morganamilo/paru), whic
**Nix and NixOS users:** you can install `gfold` from [nixpkgs](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/version-management/git-and-tools/gfold/default.nix):
-```bash
+```shell
nix-env --install ripgrep
```
**Rust developers and Cargo users:** you can use [cargo](https://crates.io) to install the [crate](https://crates.io/crates/gfold) on almost any platform.
-```bash
+```shell
cargo install gfold
```
Keeping the crate up to date is easy with [cargo-update](https://crates.io/crates/cargo-update).
-```bash
+```shell
cargo install cargo-update
cargo install-update -a
```
**Build and install from source:** if you want to install from source, and not from [crates.io](https://crates.io/crates/gfold), you can clone the repository and build `gfold`.
-```bash
+```shell
(
git clone https://github.com/nickgerace/gfold.git
- cd gfold
- make install
+ cargo install --locked --path gfold
)
```
**Download a binary:** if you do not want to use one of the above installation methods, you can download a binary from the [releases](https://github.com/nickgerace/gfold/releases) page.
-```bash
+```shell
curl -s https://raw.githubusercontent.com/nickgerace/gfold/main/scripts/install.sh | bash
```
@@ -184,7 +183,7 @@ Discretion is advised, including downloading and reading the script before execu
To uninstall `gfold` fully, after using this installation method, execute the following script:
-```bash
+```shell
curl -s https://raw.githubusercontent.com/nickgerace/gfold/main/scripts/uninstall.sh | bash
```
@@ -194,7 +193,7 @@ The uninstall script can also be used for cleanup in the event of a failed insta
## Community
-For more information and thanks to contributors, users, and the "community" at large, please refer to the **[THANKS](./THANKS.md)** file.
+For more information and thanks to contributors, users, and the "community" at large, please refer to the **[THANKS](./docs/THANKS.md)** file.
### Projects
@@ -222,6 +221,6 @@ If `fold` from [GNU Coreutils](https://www.gnu.org/software/coreutils/) is insta
You can avoid this collision with shell aliases, shell functions, and/or `PATH` changes.
Here is an example with the `o` dropped from `gfold`:
-```bash
+```shell
alias gfld=$HOME/.cargo/bin/gfold
```
diff --git a/bors.toml b/bors.toml
index 1c76368..9c01ef1 100644
--- a/bors.toml
+++ b/bors.toml
@@ -1,6 +1,5 @@
status = [
- "Nightly Fmt Check",
- "Clippy Lint, Test, and Build (ubuntu-latest)",
+ "Lint, Test, and Build (ubuntu-latest)",
"Build (windows-latest)",
"Build (macos-latest)"
]
diff --git a/docs/DEVELOPING.md b/docs/DEVELOPING.md
new file mode 100644
index 0000000..d990684
--- /dev/null
+++ b/docs/DEVELOPING.md
@@ -0,0 +1,48 @@
+# Developing
+
+This document contains information related to development.
+
+## Preparing Changes
+
+First, update dependencies and tidy your changes.
+
+```shell
+cargo fmt
+cargo update
+cargo fix --edition-idioms --allow-dirty --allow-staged
+cargo clippy --all-features --all-targets
+```
+
+Now, ensure that lints, tests, and builds succeed.
+
+```shell
+cargo fmt --all -- --check
+cargo clippy -- -D warnings
+cargo doc
+cargo test
+cargo build
+```
+
+> Alternatively, you can replace `cargo test` above with [cargo nextest](https://github.com/nextest-rs/nextest).
+>
+> ```shell
+> cargo nextest run
+> ```
+
+## Performance Checks
+
+Navigate to the [README in the `scripts` directory](../scripts/README.md) for more information on
+how to run performance checks.
+
+## 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
diff --git a/RELEASE.md b/docs/RELEASE.md
index c92cc52..3c0f43e 100644
--- a/RELEASE.md
+++ b/docs/RELEASE.md
@@ -5,15 +5,19 @@ This document contains all information related to release.
## Checklist
This checklist details the `gfold` release process.
-Steps should (and frequently must) be executed in sequential order.
+Steps should be executed in sequential order.
- [ ] Checkout and rebase `main` to its latest commit, then checkout a new branch
- [ ] Change the `version` field in `Cargo.toml` to the new tag
- [ ] **Full Releases Only**: change the version in `CHANGELOG.md` and uncomment the following line: `<!--The latest version contains all changes.-->`
-- [ ] Run final `make` targets and verify that everything looks/works as expected:
-
-```bash
-make lint test; cargo build
+- [ ] Verify that everything looks/works as expected:
+
+```shell
+cargo fmt --all -- --check
+cargo clippy -- -D warnings
+cargo test
+cargo doc
+cargo build
```
- [ ] Create and _do not merge_ a commit with the following message: `Update to <tag>`
@@ -27,21 +31,21 @@ cargo publish --dry-run
- [ ] Checkout and rebase `main` to its latest commit, which should be the aforementioned commit
- [ ] Tag and push the tag:
-```bash
+```shell
git tag <tag>
git push --tags origin main
```
- [ ] Publish the crate:
-```bash
+```shell
cargo publish
```
- [ ] Verify that the [crate](https://crates.io/crates/gfold) on `crates.io` looks correct
- [ ] Download and install the crate:
-```bash
+```shell
# Full releases
cargo install --locked gfold
diff --git a/THANKS.md b/docs/THANKS.md
index cf1a526..cf1a526 100644
--- a/THANKS.md
+++ b/docs/THANKS.md
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 100644
index f8b799b..0000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-imports_granularity = "Module"
-newline_style = "Unix"
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644
index 0000000..6485775
--- /dev/null
+++ b/scripts/.gitignore
@@ -0,0 +1 @@
+**/Cargo.lock
diff --git a/scripts/README.md b/scripts/README.md
new file mode 100644
index 0000000..513bacb
--- /dev/null
+++ b/scripts/README.md
@@ -0,0 +1,15 @@
+# Scripts
+
+Run a script by executing `cargo run` in its directory.
+
+```shell
+cd ./scripts/<script>/
+cargo run
+```
+
+Alternatively, you can run `cargo run` from another directory.
+Here is an example:
+
+```shell
+cargo run --manifest-path ./scripts/<script>/Cargo.toml
+``` \ No newline at end of file
diff --git a/scripts/bench-loosely.sh b/scripts/bench-loosely.sh
deleted file mode 100755
index b08a1b5..0000000
--- a/scripts/bench-loosely.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-REALPATH=realpath
-if [ "$(uname -s)" = "Darwin" ]; then
- REALPATH=grealpath
-fi
-REPOPATH=$(dirname $(dirname $($REALPATH -s $0)))
-
-( cd $REPOPATH; cargo build --release )
-
-OLD=$HOME/.cargo/bin/gfold
-NEW=$REPOPATH/target/release/gfold
-
-function run {
- local BENCH_FILE
- for COUNT in {1..4}; do
- echo "- - - - - - - - - - - - -"
- echo "[OLD]"
- time $OLD -i $1 > /dev/null
- echo "[NEW]"
- time $NEW -i $1 > /dev/null
- done
-}
-
-run "$HOME/" "home"
-run "$HOME/src" "src"
diff --git a/scripts/bench-loosely/Cargo.toml b/scripts/bench-loosely/Cargo.toml
new file mode 100644
index 0000000..b533aa1
--- /dev/null
+++ b/scripts/bench-loosely/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "bench-loosely"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+dirs = "4"
diff --git a/scripts/bench-loosely/src/main.rs b/scripts/bench-loosely/src/main.rs
new file mode 100644
index 0000000..68d58f6
--- /dev/null
+++ b/scripts/bench-loosely/src/main.rs
@@ -0,0 +1,95 @@
+use std::fs;
+use std::fs::Metadata;
+use std::io;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::time::{Duration, Instant};
+
+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 \"cargo build --release\"...");
+ let output = Command::new("cargo")
+ .arg("build")
+ .arg("--release")
+ .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 = dirs::home_dir().expect("could not find home directory");
+ let installed = home.join(".cargo").join("bin").join("gfold");
+ let runs = 4;
+
+ // Loosely bench using the home directory as the target.
+ for run in 0..runs {
+ println!(
+ "group {} of {} in {}",
+ run + 1,
+ runs,
+ home.to_str().expect("could not convert to str")
+ );
+ loose_bench(&binary, &installed, &home);
+ }
+
+ // Loosely bench with the parent directory of the repository as the target.
+ let parent_of_repo = repo.parent().expect("could not get parent");
+ for run in 0..runs {
+ println!(
+ "group {} of {} in {}",
+ run + 1,
+ runs,
+ parent_of_repo.to_str().expect("could not convert to str")
+ );
+ loose_bench(&binary, &installed, parent_of_repo);
+ }
+}
+
+fn loose_bench(new: &Path, old: &Path, target: &Path) {
+ let new_duration = execute(new, target);
+ let old_duration = execute(old, target);
+ let (new_text, old_text) = if new_duration > old_duration {
+ ("LOST", "WON ")
+ } else if new_duration < old_duration {
+ ("WON ", "LOST")
+ } else {
+ ("TIE ", "TIE ")
+ };
+
+ println!(
+ " {} @ {:?} - {}",
+ new_text,
+ new_duration,
+ new.to_str().expect("could not convert to str"),
+ );
+ println!(
+ " {} @ {:?} - {}",
+ old_text,
+ old_duration,
+ old.to_str().expect("could not convert to str"),
+ );
+}
+
+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
+}
diff --git a/scripts/size/Cargo.toml b/scripts/size/Cargo.toml
new file mode 100644
index 0000000..1a6bc06
--- /dev/null
+++ b/scripts/size/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "size"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+dirs = "4"
diff --git a/scripts/size/src/main.rs b/scripts/size/src/main.rs
new file mode 100644
index 0000000..2d5f5e9
--- /dev/null
+++ b/scripts/size/src/main.rs
@@ -0,0 +1,53 @@
+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 \"cargo build --release\"...");
+ let output = Command::new("cargo")
+ .arg("build")
+ .arg("--release")
+ .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/src/display/mod.rs b/src/display/mod.rs
index 5da34fe..fc1a339 100644
--- a/src/display/mod.rs
+++ b/src/display/mod.rs
@@ -3,7 +3,7 @@
use crate::config::{ColorMode, DisplayMode};
use crate::display::color::ColorHarness;
use crate::error::Error;
-use crate::report::Reports;
+use crate::report::LabeledReports;
use crate::result::Result;
use log::warn;
use std::path::Path;
@@ -16,7 +16,7 @@ const NONE: &str = "none";
/// This function chooses the display execution function based on the [`DisplayMode`] provided.
pub fn display(
display_mode: &DisplayMode,
- reports: &Reports,
+ reports: &LabeledReports,
color_mode: &ColorMode,
) -> Result<()> {
match display_mode {
@@ -26,8 +26,8 @@ pub fn display(
}
}
-/// Display [`Reports`] to `stdout` in the standard (default) format.
-fn standard(reports: &Reports, color_mode: &ColorMode) -> Result<()> {
+/// Display [`LabeledReports`] to `stdout` in the standard (default) format.
+fn standard(reports: &LabeledReports, color_mode: &ColorMode) -> Result<()> {
let mut all_reports = Vec::new();
for grouped_report in reports {
all_reports.append(&mut grouped_report.1.clone());
@@ -69,8 +69,8 @@ fn standard(reports: &Reports, color_mode: &ColorMode) -> Result<()> {
Ok(())
}
-/// Display [`Reports`] to `stdout` in JSON format.
-fn json(reports: &Reports) -> Result<()> {
+/// Display [`LabeledReports`] to `stdout` in JSON format.
+fn json(reports: &LabeledReports) -> Result<()> {
let mut all_reports = Vec::new();
for grouped_report in reports {
all_reports.append(&mut grouped_report.1.clone());
@@ -81,8 +81,8 @@ fn json(reports: &Reports) -> Result<()> {
Ok(())
}
-/// Display [`Reports`] to `stdout` in the classic format.
-fn classic(reports: &Reports, color_mode: &ColorMode) -> Result<()> {
+/// Display [`LabeledReports`] to `stdout` in the classic format.
+fn classic(reports: &LabeledReports, color_mode: &ColorMode) -> Result<()> {
let color_harness = ColorHarness::new(color_mode);
let length = reports.keys().len();
diff --git a/src/main.rs b/src/main.rs
index 4797f6c..ea39e87 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,8 +22,12 @@ fn main() -> Result<()> {
mod tests {
use super::*;
- use crate::config::Config;
+ use crate::config::{Config, DisplayMode};
+ use crate::report::{LabeledReports, Report};
+ use crate::status::Status;
use git2::Repository;
+ use pretty_assertions::assert_eq;
+ use std::collections::BTreeMap;
use std::path::Path;
use std::{env, fs, io};
@@ -58,10 +62,10 @@ mod tests {
// ├── bar
// ├── baz
// ├── foo
- // │   └── newfile
+ // │ └── newfile
// └── nested
// ├── one
- // │   ├── newfile
+ // │ └── newfile
// ├── three
// └── two
@@ -94,7 +98,74 @@ mod tests {
let mut config = Config::new().expect("could not create new config");
config.path = test;
-
assert!(run::run(&config).is_ok());
+
+ // Now, let's ensure our reports are what we expect.
+ let test_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
+ .join("target")
+ .join("test");
+ let mut expected_reports: LabeledReports = BTreeMap::new();
+
+ let key = test_dir
+ .to_str()
+ .expect("could not convert to str")
+ .to_string();
+ let mut reports = vec![
+ Report::new(&test_dir.join("foo"), "HEAD", &Status::Unclean, None, None)
+ .expect("could not create report"),
+ Report::new(&test_dir.join("bar"), "HEAD", &Status::Clean, None, None)
+ .expect("could not create report"),
+ Report::new(&test_dir.join("baz"), "HEAD", &Status::Clean, None, None)
+ .expect("could not create report"),
+ ];
+ reports.sort_by(|a, b| a.name.cmp(&b.name));
+ expected_reports.insert(Some(key), reports);
+
+ let nested_test_dir = test_dir.join("nested");
+ let key = nested_test_dir
+ .to_str()
+ .expect("could not convert to str")
+ .to_string();
+ let mut reports = vec![
+ Report::new(
+ &nested_test_dir.join("one"),
+ "HEAD",
+ &Status::Unclean,
+ None,
+ None,
+ )
+ .expect("could not create report"),
+ Report::new(
+ &nested_test_dir.join("two"),
+ "HEAD",
+ &Status::Clean,
+ None,
+ None,
+ )
+ .expect("could not create report"),
+ Report::new(
+ &nested_test_dir.join("three"),
+ "HEAD",
+ &Status::Clean,
+ None,
+ None,
+ )
+ .expect("could not create report"),
+ ];
+ reports.sort_by(|a, b| a.name.cmp(&b.name));
+ expected_reports.insert(Some(key), reports);
+
+ // Use classic display mode to avoid collecting email results.
+ config.display_mode = DisplayMode::Classic;
+ let found_labeled_reports = report::generate_reports(&config.path, &config.display_mode)
+ .expect("could not generate reports");
+ let mut found_labeled_reports_sorted = LabeledReports::new();
+ for labeled_report in found_labeled_reports {
+ let mut value = labeled_report.1;
+ value.sort_by(|a, b| a.name.cmp(&b.name));
+ found_labeled_reports_sorted.insert(labeled_report.0.clone(), value.clone());
+ }
+
+ assert_eq!(found_labeled_reports_sorted, expected_reports);
}
}
diff --git a/src/report/mod.rs b/src/report/mod.rs
index aadab52..bcf0dbb 100644
--- a/src/report/mod.rs
+++ b/src/report/mod.rs
@@ -19,10 +19,10 @@ const HEAD: &str = "HEAD";
/// parent directory for a group of reports ([`Vec<Report>`]). The values corresponding to those keys
/// are the actual groups of reports.
// NOTE: We use a BTreeMap over a HashMap for sorted keys.
-pub type Reports = BTreeMap<Option<String>, Vec<Report>>;
+pub type LabeledReports = BTreeMap<Option<String>, Vec<Report>>;
/// A collection of results for a Git repository at a given path.
-#[derive(Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Report {
/// The directory name of the Git repository.
pub name: String,
@@ -41,7 +41,7 @@ pub struct Report {
}
impl Report {
- fn new(
+ pub fn new(
path: &Path,
branch: &str,
status: &Status,
@@ -71,9 +71,9 @@ impl Report {
}
}
-/// Generate [`Reports`] for a given path and its children. The [`DisplayMode`] is required because
-/// any two display modes can require differing ammounts of data to be collected.
-pub fn generate_reports(path: &Path, display_mode: &DisplayMode) -> Result<Reports> {
+/// Generate [`LabeledReports`] for a given path and its children. The [`DisplayMode`] is required
+/// because any two display modes can require differing amounts of data to be collected.
+pub fn generate_reports(path: &Path, display_mode: &DisplayMode) -> Result<LabeledReports> {
let include_email = match display_mode {
DisplayMode::Standard | DisplayMode::Json => true,
DisplayMode::Classic => false,
@@ -84,7 +84,7 @@ pub fn generate_reports(path: &Path, display_mode: &DisplayMode) -> Result<Repor
.map(|path| generate_report(path, include_email))
.collect::<Vec<Result<Report>>>();
- let mut processed = Reports::new();
+ let mut processed = LabeledReports::new();
for wrapped_report in unprocessed {
match wrapped_report {
Ok(report) => {
diff --git a/src/status.rs b/src/status.rs
index a75ebde..2301dc9 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -3,7 +3,7 @@
use serde::{Deserialize, Serialize};
/// A summarized interpretation of the status of a Git working tree.
-#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
+#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)]
pub enum Status {
Bare,
Clean,