summaryrefslogtreecommitdiffstats
path: root/vendor/gix-pathspec
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-pathspec')
-rw-r--r--vendor/gix-pathspec/.cargo-checksum.json1
-rw-r--r--vendor/gix-pathspec/CHANGELOG.md328
-rw-r--r--vendor/gix-pathspec/Cargo.toml53
-rw-r--r--vendor/gix-pathspec/LICENSE-APACHE191
-rw-r--r--vendor/gix-pathspec/LICENSE-MIT21
-rw-r--r--vendor/gix-pathspec/README.md16
-rw-r--r--vendor/gix-pathspec/src/defaults.rs70
-rw-r--r--vendor/gix-pathspec/src/lib.rs143
-rw-r--r--vendor/gix-pathspec/src/parse.rs263
-rw-r--r--vendor/gix-pathspec/src/pattern.rs194
-rw-r--r--vendor/gix-pathspec/src/search/init.rs146
-rw-r--r--vendor/gix-pathspec/src/search/matching.rs149
-rw-r--r--vendor/gix-pathspec/src/search/mod.rs51
-rw-r--r--vendor/gix-pathspec/tests/defaults.rs95
-rw-r--r--vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline.tar.xzbin0 -> 16928 bytes
-rw-r--r--vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_dirs.tar.xzbin0 -> 16028 bytes
-rw-r--r--vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_files.tar.xzbin0 -> 10700 bytes
-rw-r--r--vendor/gix-pathspec/tests/fixtures/generated-archives/parse_baseline.tar.xzbin0 -> 9528 bytes
-rw-r--r--vendor/gix-pathspec/tests/fixtures/match_baseline_dirs.sh97
-rw-r--r--vendor/gix-pathspec/tests/fixtures/match_baseline_files.sh94
-rwxr-xr-xvendor/gix-pathspec/tests/fixtures/parse_baseline.sh158
-rw-r--r--vendor/gix-pathspec/tests/normalize/mod.rs116
-rw-r--r--vendor/gix-pathspec/tests/parse/invalid.rs152
-rw-r--r--vendor/gix-pathspec/tests/parse/mod.rs93
-rw-r--r--vendor/gix-pathspec/tests/parse/valid.rs359
-rw-r--r--vendor/gix-pathspec/tests/pathspec.rs5
-rw-r--r--vendor/gix-pathspec/tests/search/mod.rs281
27 files changed, 3076 insertions, 0 deletions
diff --git a/vendor/gix-pathspec/.cargo-checksum.json b/vendor/gix-pathspec/.cargo-checksum.json
new file mode 100644
index 000000000..776151660
--- /dev/null
+++ b/vendor/gix-pathspec/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"e260578f0c5595ab2d17eddd0309da451ee37752b8ec31c09193670c5f6dfe6e","Cargo.toml":"bdb90604393782c6ea835edad435a65ccff130a667fed4471b7bc6edf9bca307","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","README.md":"ec95cf838fbde2a636e2b1de88ddde926ddbc59b496590d7a8edbd283d87875f","src/defaults.rs":"ff76c0704678059c26924f729c36f40c501d21cb0afa793359a73e67a0f2e736","src/lib.rs":"74f77299f99c32714396a2815e014474af44414941786a82cc1a3be930d47a9d","src/parse.rs":"c279f433b8585447c2f6e1d02329f8a2eb86694333b2dd6af45fedbb1faef724","src/pattern.rs":"629c3225eb83eb9e3606eeda558f8e66c12defacc99f95f00e177308322bb576","src/search/init.rs":"a26f6335f8feb7c8feac0390c07da0b64499d5a7a7d3f263149ddfe678025356","src/search/matching.rs":"e9529ca5c88762f19c890a5f210339d4b1febe8fc6633eb6f1b2d69367855d93","src/search/mod.rs":"31a3b65392c3791cb9b66f8a799275ba5d4b13a0e82bd1401bbb114cd3357ef0","tests/defaults.rs":"fb9e0c78258e96f89138e77f1d9fbb009de2ff490a3c2ecd0637e826a105dd69","tests/fixtures/generated-archives/match_baseline.tar.xz":"0ba46801dfab65bcc77c8ce0dc9144d77fd142be847f3340af6ae8fcba44c82d","tests/fixtures/generated-archives/match_baseline_dirs.tar.xz":"742241f4ea290fc9088fd5e32423859929bc4b39dccd31d205c67fe3ac9128c0","tests/fixtures/generated-archives/match_baseline_files.tar.xz":"b0c722ab08de2ab63b9f222747cf898f5b6bb6b76ec55ccd176bab3b854ef7bb","tests/fixtures/generated-archives/parse_baseline.tar.xz":"123da727b33802a3a2dc80e948b07cbf133c2d66129693f4896cba2f6b92b02f","tests/fixtures/match_baseline_dirs.sh":"202f2d67ed9107507e4c648b2ad78934ea2a3f6b6865f0a8367fe7aa6aca7614","tests/fixtures/match_baseline_files.sh":"3fa45af77c32b570c419b9746539ee9f074e13113437f5a29931126b155cb1ff","tests/fixtures/parse_baseline.sh":"55415e80ce66bce46bf342036b7fd6e8a3a9094cb058cade13af325347e8bb73","tests/normalize/mod.rs":"6d39e550b255da354b1566f01d21f270b5235bbae760448ceec734cef3930569","tests/parse/invalid.rs":"7bc793a7718a46fd08c2de87d971cdc044788d9df8c6499ca4e3022caed6d955","tests/parse/mod.rs":"e712b38cc012ff5775a9ff60c1a6f70a7c2411dad42ae5e496068db71b1565d4","tests/parse/valid.rs":"ab1f68baaeaef7d6320304117e39531e78d36ec038f78a74d49f82ac66675950","tests/pathspec.rs":"63ed83deae59a91ba60b36ffccebd5ea01229eb20a10f654595441f511dea14f","tests/search/mod.rs":"b701d3431edb87032bc85b0375cd47050210af7ab438f598c71733ad41558d97"},"package":"c3e26c9b47c51be73f98d38c84494bd5fb99334c5d6fda14ef5d036d50a9e5fd"} \ No newline at end of file
diff --git a/vendor/gix-pathspec/CHANGELOG.md b/vendor/gix-pathspec/CHANGELOG.md
new file mode 100644
index 000000000..d742565d3
--- /dev/null
+++ b/vendor/gix-pathspec/CHANGELOG.md
@@ -0,0 +1,328 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.3.0 (2023-09-24)
+
+<csr-id-832b34570bde97499e75a174bc818113092b3145/>
+
+### Other
+
+ - <csr-id-832b34570bde97499e75a174bc818113092b3145/> improve documentation of `common_prefix()` and `pattern_matching_relative_path()`.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 3 commits contributed to the release over the course of 1 calendar day.
+ - 16 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Prepare changelogs prior to release ([`8a60d5b`](https://github.com/Byron/gitoxide/commit/8a60d5b80877c213c3b646d3061e8a33e0e433ec))
+ - Merge branch 'reset' ([`54a8495`](https://github.com/Byron/gitoxide/commit/54a849545140f7f1c0c7564c418071c0a76a34e7))
+ - Improve documentation of `common_prefix()` and `pattern_matching_relative_path()`. ([`832b345`](https://github.com/Byron/gitoxide/commit/832b34570bde97499e75a174bc818113092b3145))
+</details>
+
+## 0.2.0 (2023-09-08)
+
+### Bug Fixes (BREAKING)
+
+ - <csr-id-072ee32f693a31161cd6a843da6582d13efbb20b/> use `dyn` trait where possible.
+ This reduces compile time due to avoiding duplication.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 5 commits contributed to the release over the course of 17 calendar days.
+ - 17 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Release gix-date v0.8.0, gix-hash v0.13.0, gix-features v0.34.0, gix-actor v0.26.0, gix-object v0.36.0, gix-path v0.10.0, gix-glob v0.12.0, gix-attributes v0.18.0, gix-packetline-blocking v0.16.6, gix-filter v0.4.0, gix-fs v0.6.0, gix-commitgraph v0.20.0, gix-hashtable v0.4.0, gix-revwalk v0.7.0, gix-traverse v0.32.0, gix-worktree-stream v0.4.0, gix-archive v0.4.0, gix-config-value v0.14.0, gix-tempfile v9.0.0, gix-lock v9.0.0, gix-ref v0.36.0, gix-sec v0.10.0, gix-config v0.29.0, gix-prompt v0.7.0, gix-url v0.23.0, gix-credentials v0.19.0, gix-diff v0.35.0, gix-discover v0.24.0, gix-ignore v0.7.0, gix-index v0.24.0, gix-macros v0.1.0, gix-mailmap v0.18.0, gix-negotiate v0.7.0, gix-pack v0.42.0, gix-odb v0.52.0, gix-pathspec v0.2.0, gix-packetline v0.16.6, gix-transport v0.36.0, gix-protocol v0.39.0, gix-revision v0.21.0, gix-refspec v0.17.0, gix-submodule v0.3.0, gix-worktree v0.25.0, gix-worktree-state v0.2.0, gix v0.53.0, safety bump 39 crates ([`8bd0456`](https://github.com/Byron/gitoxide/commit/8bd045676bb2cdc02624ab93e73ff8518064ca38))
+ - Prepare changelogs for release ([`375db06`](https://github.com/Byron/gitoxide/commit/375db06a8442378c3f7a922fae38e2a6694d9d04))
+ - Merge branch `dyn`ification ([`f658fcc`](https://github.com/Byron/gitoxide/commit/f658fcc52dc2200ae34ca53dc10be97fb9012057))
+ - Use `dyn` trait where possible. ([`072ee32`](https://github.com/Byron/gitoxide/commit/072ee32f693a31161cd6a843da6582d13efbb20b))
+ - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4))
+</details>
+
+## 0.1.0 (2023-08-22)
+
+<csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/>
+<csr-id-533e887e80c5f7ede8392884562e1c5ba56fb9a8/>
+<csr-id-229bd4899213f749a7cc124aa2b82a1368fba40f/>
+<csr-id-bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d/>
+
+### Chore
+
+ - <csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/> uniformize deny attributes
+ - <csr-id-533e887e80c5f7ede8392884562e1c5ba56fb9a8/> remove default link to cargo doc everywhere
+
+### New Features
+
+ - <csr-id-07a3e93d22462ed0221ee90bda17559425305528/> export `gix-attributes` as `attributes` to make `gix-glob` and `gix-attribute` types available.
+ - <csr-id-49db3ac81db18fbc492d14161c09084112ff62f3/> match pathspecs just like `git` does.
+ This is important for selecting files on disk
+ - <csr-id-b3de72e014b33bdf1ebc39cd7e3e5db990e5b7f3/> Add `Pattern::is_null()` to be able to check for a special kind of spec.
+ That spec is indicated with `:`.
+
+### Chore
+
+ - <csr-id-229bd4899213f749a7cc124aa2b82a1368fba40f/> don't call crate 'WIP' in manifest anymore.
+ - <csr-id-bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d/> Add `clippy::redundant-closure-for-method-calls` lint
+
+### Bug Fixes
+
+ - <csr-id-e14dc7d475373d2c266e84ff8f1826c68a34ab92/> note that crates have been renamed from `git-*` to `gix-*`.
+ This also means that the `git-*` prefixed crates of the `gitoxide` project
+ are effectively unmaintained.
+ Use the crates with the `gix-*` prefix instead.
+
+ If you were using `git-repository`, then `gix` is its substitute.
+ - <csr-id-a2f1879f85df75146baf32336cf5a7b19dae032e/> certain combinations of exclude specs could cause panics.
+ - <csr-id-135d317065aae87af302beb6c26bb6ca8e30b6aa/> compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`.
+ `as_ref()` relies on a known target type which isn't always present. However, once
+ there is only one implementation, that's no problem, but when that changes compilation
+ fails due to ambiguity.
+
+### Changed (BREAKING)
+
+ - <csr-id-99905bacace8aed42b16d43f0f04cae996cb971c/> upgrade `bstr` to `1.0.1`
+
+### New Features (BREAKING)
+
+ - <csr-id-3d8fa8fef9800b1576beab8a5bc39b821157a5ed/> upgrade edition to 2021 in most crates.
+ MSRV for this is 1.56, and we are now at 1.60 so should be compatible.
+ This isn't more than a patch release as it should break nobody
+ who is adhering to the MSRV, but let's be careful and mark it
+ breaking.
+
+ Note that `git-features` and `git-pack` are still on edition 2018
+ as they make use of a workaround to support (safe) mutable access
+ to non-overlapping entries in a slice which doesn't work anymore
+ in edition 2021.
+ - <csr-id-f1421d31ab9e045f6b6599d21eb1a0723f90a242/> `parse()` now supports the configuration of defaults.
+ This allows the caller to control what happens if certain configuration
+ flags of pathsepcs aren't set.
+
+ These are typically provided by pathspec configuration environment variables.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 169 commits contributed to the release over the course of 523 calendar days.
+ - 12 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 5 unique issues were worked on: [#301](https://github.com/Byron/gitoxide/issues/301), [#415](https://github.com/Byron/gitoxide/issues/415), [#427](https://github.com/Byron/gitoxide/issues/427), [#450](https://github.com/Byron/gitoxide/issues/450), [#691](https://github.com/Byron/gitoxide/issues/691)
+
+### Thanks Clippy
+
+<csr-read-only-do-not-edit/>
+
+[Clippy](https://github.com/rust-lang/rust-clippy) helped 4 times to make code idiomatic.
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **[#301](https://github.com/Byron/gitoxide/issues/301)**
+ - Add future crate for good measure ([`625eb1d`](https://github.com/Byron/gitoxide/commit/625eb1d7d266036c1f30caab7bd3897af9fdbef7))
+ * **[#415](https://github.com/Byron/gitoxide/issues/415)**
+ - Changed quickerror to thiserror ([`49fcab7`](https://github.com/Byron/gitoxide/commit/49fcab749ea3260f3333976567fcc4ab8a072fe3))
+ - Added alternative parsing module ([`eb2dec0`](https://github.com/Byron/gitoxide/commit/eb2dec0777bfe894f4d02bdc03a3e507302b41b4))
+ - Attribute parsing functional ([`4b2ed7e`](https://github.com/Byron/gitoxide/commit/4b2ed7e0f033fd01a7364fc41057e113adf2fbdc))
+ - Updated documentation ([`8b9570f`](https://github.com/Byron/gitoxide/commit/8b9570fdcdb426cbde7edb9fcca4b7340944550e))
+ - Attribute parsing WIP ([`7c84fb8`](https://github.com/Byron/gitoxide/commit/7c84fb81506cc41fbf68575583129eafbd89139d))
+ - Added some documentation ([`c04d4be`](https://github.com/Byron/gitoxide/commit/c04d4be29c7a0cf72500d30432215513f6066338))
+ - Tests now check if pathspec is valid in git ([`334659e`](https://github.com/Byron/gitoxide/commit/334659e34b1f99f3bc662fa599dcd8f0d94ad206))
+ - Remove WhitespaceError ([`4d20cd9`](https://github.com/Byron/gitoxide/commit/4d20cd91be403d48fd5443202048f4a5bb867a62))
+ - Error handling: parser can return a result now ([`31aba11`](https://github.com/Byron/gitoxide/commit/31aba11c953b5b7dd70f14ee904026d12db69d10))
+ - Pathspec parser is functional ([`7d95f16`](https://github.com/Byron/gitoxide/commit/7d95f162a3edb7b2714dfadb9b5cf8311f3da061))
+ * **[#427](https://github.com/Byron/gitoxide/issues/427)**
+ - Make fmt ([`4b320e7`](https://github.com/Byron/gitoxide/commit/4b320e773368ac5e8c38dd8a779ef3d6d2d024ec))
+ * **[#450](https://github.com/Byron/gitoxide/issues/450)**
+ - Upgrade `bstr` to `1.0.1` ([`99905ba`](https://github.com/Byron/gitoxide/commit/99905bacace8aed42b16d43f0f04cae996cb971c))
+ * **[#691](https://github.com/Byron/gitoxide/issues/691)**
+ - Set `rust-version` to 1.64 ([`55066ce`](https://github.com/Byron/gitoxide/commit/55066ce5fd71209abb5d84da2998b903504584bb))
+ * **Uncategorized**
+ - Release gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0 ([`6c62e74`](https://github.com/Byron/gitoxide/commit/6c62e748240ac0980fc23fdf30f8477dea8b9bc3))
+ - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee))
+ - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc))
+ - Just fmt ([`0d258f4`](https://github.com/Byron/gitoxide/commit/0d258f40afcd848509e2b0c7c264e9f346ed1726))
+ - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f))
+ - Merge branch 'submodule-active' ([`a3afaa4`](https://github.com/Byron/gitoxide/commit/a3afaa42741616a0f1abeef9b54557e7c2b800cb))
+ - Export `gix-attributes` as `attributes` to make `gix-glob` and `gix-attribute` types available. ([`07a3e93`](https://github.com/Byron/gitoxide/commit/07a3e93d22462ed0221ee90bda17559425305528))
+ - Add `Defaults::from_environment()` to be able to respect git environment settings. ([`fb9d4db`](https://github.com/Byron/gitoxide/commit/fb9d4db3fe304e9411a6651b128a25da260fce62))
+ - Certain combinations of exclude specs could cause panics. ([`a2f1879`](https://github.com/Byron/gitoxide/commit/a2f1879f85df75146baf32336cf5a7b19dae032e))
+ - Merge branch 'pathspec-matching' ([`9f4dfe0`](https://github.com/Byron/gitoxide/commit/9f4dfe0f0b948280692916b596923959ea2fd9da))
+ - Match pathspecs just like `git` does. ([`49db3ac`](https://github.com/Byron/gitoxide/commit/49db3ac81db18fbc492d14161c09084112ff62f3))
+ - `parse()` now supports the configuration of defaults. ([`f1421d3`](https://github.com/Byron/gitoxide/commit/f1421d31ab9e045f6b6599d21eb1a0723f90a242))
+ - Add `Pattern::is_null()` to be able to check for a special kind of spec. ([`b3de72e`](https://github.com/Byron/gitoxide/commit/b3de72e014b33bdf1ebc39cd7e3e5db990e5b7f3))
+ - Refactor ([`5f76ddf`](https://github.com/Byron/gitoxide/commit/5f76ddf0a5158ba5503a8a39b09336655eeb5156))
+ - Release gix-glob v0.10.2, gix-date v0.7.2, gix-validate v0.8.0, gix-object v0.34.0, gix-ref v0.34.0, gix-config v0.27.0, gix-commitgraph v0.18.2, gix-revwalk v0.5.0, gix-revision v0.19.0, gix-refspec v0.15.0, gix-submodule v0.1.0, safety bump 18 crates ([`4604f83`](https://github.com/Byron/gitoxide/commit/4604f83ef238dc07c85aaeae097399b67f3cfd0c))
+ - Merge branch 'dev-on-linux' ([`6b4a303`](https://github.com/Byron/gitoxide/commit/6b4a30330fe49fc97daa73f55bf56580cc0597aa))
+ - Fix various tests to run properly on linux ([`ef8ccd9`](https://github.com/Byron/gitoxide/commit/ef8ccd9d16143d37155d063747c69cade80f162d))
+ - Release gix-features v0.32.1, gix-actor v0.24.1, gix-validate v0.7.7, gix-object v0.33.1, gix-path v0.8.4, gix-glob v0.10.1, gix-quote v0.4.6, gix-attributes v0.16.0, gix-command v0.2.8, gix-packetline-blocking v0.16.4, gix-filter v0.2.0, gix-fs v0.4.1, gix-chunk v0.4.4, gix-commitgraph v0.18.1, gix-hashtable v0.2.4, gix-revwalk v0.4.1, gix-traverse v0.30.1, gix-worktree-stream v0.2.0, gix-archive v0.2.0, gix-config-value v0.12.5, gix-tempfile v7.0.1, gix-utils v0.1.5, gix-lock v7.0.2, gix-ref v0.33.1, gix-sec v0.8.4, gix-prompt v0.5.4, gix-url v0.21.1, gix-credentials v0.17.1, gix-diff v0.33.1, gix-discover v0.22.1, gix-ignore v0.5.1, gix-bitmap v0.2.6, gix-index v0.21.1, gix-mailmap v0.16.1, gix-negotiate v0.5.1, gix-pack v0.40.1, gix-odb v0.50.1, gix-packetline v0.16.4, gix-transport v0.34.1, gix-protocol v0.36.1, gix-revision v0.18.1, gix-refspec v0.14.1, gix-worktree v0.23.0, gix v0.50.0, safety bump 5 crates ([`16295b5`](https://github.com/Byron/gitoxide/commit/16295b58e2581d2e8b8b762816f52baabe871c75))
+ - Update license field following SPDX 2.1 license expression standard ([`9064ea3`](https://github.com/Byron/gitoxide/commit/9064ea31fae4dc59a56bdd3a06c0ddc990ee689e))
+ - Adjust package versions (by cargo-smart-release) ([`c70e54f`](https://github.com/Byron/gitoxide/commit/c70e54f163c312c87753a506eeaad462e8579bfb))
+ - Release gix-glob v0.9.1, gix-attributes v0.14.1, gix-config-value v0.12.3, gix-ref v0.32.1, gix-sec v0.8.3, gix-config v0.25.1, gix-url v0.20.1, gix-credentials v0.16.1, gix-discover v0.21.1, gix-ignore v0.4.1, gix-pack v0.39.1, gix-odb v0.49.1, gix-worktree v0.21.1, gix v0.48.0 ([`69c6a36`](https://github.com/Byron/gitoxide/commit/69c6a36ba14cbef129deebda9fd8870005fefa17))
+ - Release gix-date v0.6.0, gix-hash v0.11.3, gix-trace v0.1.1, gix-features v0.31.0, gix-actor v0.22.0, gix-path v0.8.2, gix-glob v0.9.0, gix-quote v0.4.5, gix-attributes v0.14.0, gix-chunk v0.4.3, gix-commitgraph v0.17.0, gix-config-value v0.12.2, gix-fs v0.3.0, gix-tempfile v7.0.0, gix-utils v0.1.3, gix-lock v7.0.0, gix-validate v0.7.6, gix-object v0.31.0, gix-ref v0.31.0, gix-sec v0.8.2, gix-config v0.24.0, gix-command v0.2.6, gix-prompt v0.5.2, gix-url v0.20.0, gix-credentials v0.16.0, gix-diff v0.31.0, gix-discover v0.20.0, gix-hashtable v0.2.2, gix-ignore v0.4.0, gix-bitmap v0.2.5, gix-revwalk v0.2.0, gix-traverse v0.28.0, gix-index v0.19.0, gix-mailmap v0.14.0, gix-negotiate v0.3.0, gix-pack v0.38.0, gix-odb v0.48.0, gix-packetline v0.16.3, gix-transport v0.33.0, gix-protocol v0.34.0, gix-revision v0.16.0, gix-refspec v0.12.0, gix-worktree v0.20.0, gix v0.47.0, gitoxide-core v0.29.0, gitoxide v0.27.0, safety bump 30 crates ([`ea9f942`](https://github.com/Byron/gitoxide/commit/ea9f9424e777f10da0e33bb9ffbbefd01c4c5a74))
+ - Merge branch 'corpus' ([`aa16c8c`](https://github.com/Byron/gitoxide/commit/aa16c8ce91452a3e3063cf1cf0240b6014c4743f))
+ - Change MSRV to 1.65 ([`4f635fc`](https://github.com/Byron/gitoxide/commit/4f635fc4429350bae2582d25de86429969d28f30))
+ - Merge branch 'help-874-redundant-closures' ([`fe59956`](https://github.com/Byron/gitoxide/commit/fe59956ad667303a923d7cfd9ffd72283df41d78))
+ - Add `clippy::redundant-closure-for-method-calls` lint ([`bcad5c2`](https://github.com/Byron/gitoxide/commit/bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d))
+ - Release gix-attributes v0.13.1, gix-diff v0.30.1, gix-revwalk v0.1.0, gix-traverse v0.27.0, gix-index v0.18.0, gix-revision v0.15.2, gix-negotiate v0.2.1, gix-pack v0.37.0, gix-odb v0.47.0, gix-protocol v0.33.2, gix-worktree v0.19.0, gix v0.46.0, safety bump 7 crates ([`2560a2c`](https://github.com/Byron/gitoxide/commit/2560a2cc3e1d8c60cd812e15696fa4761d036e19))
+ - Release gix-date v0.5.1, gix-hash v0.11.2, gix-features v0.30.0, gix-actor v0.21.0, gix-path v0.8.1, gix-glob v0.8.0, gix-quote v0.4.4, gix-attributes v0.13.0, gix-chunk v0.4.2, gix-commitgraph v0.16.0, gix-config-value v0.12.1, gix-fs v0.2.0, gix-tempfile v6.0.0, gix-utils v0.1.2, gix-lock v6.0.0, gix-validate v0.7.5, gix-object v0.30.0, gix-ref v0.30.0, gix-sec v0.8.1, gix-config v0.23.0, gix-command v0.2.5, gix-prompt v0.5.1, gix-url v0.19.0, gix-credentials v0.15.0, gix-diff v0.30.0, gix-discover v0.19.0, gix-hashtable v0.2.1, gix-ignore v0.3.0, gix-bitmap v0.2.4, gix-traverse v0.26.0, gix-index v0.17.0, gix-mailmap v0.13.0, gix-revision v0.15.0, gix-negotiate v0.2.0, gix-pack v0.36.0, gix-odb v0.46.0, gix-packetline v0.16.2, gix-transport v0.32.0, gix-protocol v0.33.0, gix-refspec v0.11.0, gix-worktree v0.18.0, gix v0.45.0, safety bump 29 crates ([`9a9fa96`](https://github.com/Byron/gitoxide/commit/9a9fa96fa8a722bddc5c3b2270b0edf8f6615141))
+ - Merge branch 'main' into auto-clippy ([`3ef5c90`](https://github.com/Byron/gitoxide/commit/3ef5c90aebce23385815f1df674c1d28d58b4b0d))
+ - Merge branch 'blinxen/main' ([`9375cd7`](https://github.com/Byron/gitoxide/commit/9375cd75b01aa22a0e2eed6305fe45fabfd6c1ac))
+ - Include license files in all crates ([`facaaf6`](https://github.com/Byron/gitoxide/commit/facaaf633f01c857dcf2572c6dbe0a92b7105c1c))
+ - Bump gix-path v0.8.0, safety bump 20 crates (gix set to 0.44.1 manually) ([`43ebaf2`](https://github.com/Byron/gitoxide/commit/43ebaf267557218865862538ffc7bdf00558492f))
+ - Merge branch 'fix-823' ([`6ebd61e`](https://github.com/Byron/gitoxide/commit/6ebd61e548a36a04e413ac725a03e607a3588334))
+ - Thanks clippy ([`14e64e7`](https://github.com/Byron/gitoxide/commit/14e64e74649cfb1f2f99da87015939af98fae5c8))
+ - Release gix-utils v0.1.0, gix-hash v0.11.0, gix-date v0.5.0, gix-features v0.29.0, gix-actor v0.20.0, gix-object v0.29.0, gix-archive v0.1.0, gix-fs v0.1.0, safety bump 25 crates ([`8dbd0a6`](https://github.com/Byron/gitoxide/commit/8dbd0a60557a85acfa231800a058cbac0271a8cf))
+ - Merge branch 'patch-1' ([`d0052c1`](https://github.com/Byron/gitoxide/commit/d0052c13cabcde8058177d2439053b50ea5adbfc))
+ - Update to latest `bitflags` version. ([`594cca5`](https://github.com/Byron/gitoxide/commit/594cca51840c00654af05acc7f7c7d01fe699067))
+ - Release gix-features v0.28.0, gix-actor v0.19.0, gix-object v0.28.0, gix-diff v0.28.0, gix-traverse v0.24.0, gix-pack v0.32.0, safety bump 20 crates ([`0f411e9`](https://github.com/Byron/gitoxide/commit/0f411e93ec812592bb9d3a52b751399dd86f76f7))
+ - Adjust manifests prior to release ([`addd789`](https://github.com/Byron/gitoxide/commit/addd78958fdd1e54eb702854e96079539d01965a))
+ - Release gix-date v0.4.3, gix-hash v0.10.3, gix-features v0.26.5, gix-actor v0.17.2, gix-glob v0.5.5, gix-path v0.7.2, gix-quote v0.4.2, gix-attributes v0.8.3, gix-validate v0.7.3, gix-object v0.26.2, gix-ref v0.24.1, gix-config v0.16.2, gix-command v0.2.4, gix-url v0.13.3, gix-credentials v0.9.2, gix-discover v0.13.1, gix-index v0.12.4, gix-mailmap v0.9.3, gix-pack v0.30.3, gix-packetline v0.14.3, gix-transport v0.25.6, gix-protocol v0.26.4, gix-revision v0.10.4, gix-refspec v0.7.3, gix-worktree v0.12.3, gix v0.36.1 ([`9604783`](https://github.com/Byron/gitoxide/commit/96047839a20a657a559376b0b14c65aeab96acbd))
+ - Compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`. ([`135d317`](https://github.com/Byron/gitoxide/commit/135d317065aae87af302beb6c26bb6ca8e30b6aa))
+ - Release gix-glob v0.5.4 ([`c56d336`](https://github.com/Byron/gitoxide/commit/c56d3365fde21120cf6101cf34f8b5669804977c))
+ - Merge branch 'rename-crates' into inform-about-gix-rename ([`c9275b9`](https://github.com/Byron/gitoxide/commit/c9275b99ea43949306d93775d9d78c98fb86cfb1))
+ - Rename `git-testtools` to `gix-testtools` ([`b65c33d`](https://github.com/Byron/gitoxide/commit/b65c33d256cfed65d11adeff41132e3e58754089))
+ - Adjust to renaming of `git-pathspec` to `gix-pathspec` ([`37f7c6b`](https://github.com/Byron/gitoxide/commit/37f7c6b9070e118604aa3fc0b38530699dcfec6e))
+ - Renmae `git-pathspec` to `gix-pathspec` ([`a49ba33`](https://github.com/Byron/gitoxide/commit/a49ba33f7aa22e39b4177320224ee99353b7540b))
+ - Adjust to renamining of `git-attributes` to `gix-attributes` ([`4a8b3b8`](https://github.com/Byron/gitoxide/commit/4a8b3b812ac26f2a2aee8ce8ca81591273383c84))
+ - Adjust to renaminig of `git-quote` to `gix-quote` ([`648025b`](https://github.com/Byron/gitoxide/commit/648025b7ca94411fdd0d90c53e5faede5fde6c8d))
+ - Adjust to renaming of `git-hash` to `gix-hash` ([`4a9d025`](https://github.com/Byron/gitoxide/commit/4a9d0257110c3efa61d08c8457c4545b200226d1))
+ - Adjust to renaming of `git-features` to `gix-features` ([`e2dd68a`](https://github.com/Byron/gitoxide/commit/e2dd68a417aad229e194ff20dbbfd77668096ec6))
+ - Adjust to renaming of `git-glob` to `gix-glob` ([`35b2a3a`](https://github.com/Byron/gitoxide/commit/35b2a3acbc8f2a03f151bc0a3863163844e0ca86))
+ - Adapt to renaming of `git-path` to `gix-path` ([`d3bbcfc`](https://github.com/Byron/gitoxide/commit/d3bbcfccad80fc44ea8e7bf819f23adaca06ba2d))
+ - Release git-date v0.4.2, git-hash v0.10.2, git-features v0.26.2, git-actor v0.17.1, git-glob v0.5.3, git-path v0.7.1, git-quote v0.4.1, git-attributes v0.8.2, git-config-value v0.10.1, git-tempfile v3.0.2, git-lock v3.0.2, git-validate v0.7.2, git-object v0.26.1, git-ref v0.24.0, git-sec v0.6.2, git-config v0.16.0, git-command v0.2.3, git-prompt v0.3.2, git-url v0.13.2, git-credentials v0.9.1, git-diff v0.26.1, git-discover v0.13.0, git-hashtable v0.1.1, git-bitmap v0.2.1, git-traverse v0.22.1, git-index v0.12.3, git-mailmap v0.9.2, git-chunk v0.4.1, git-pack v0.30.2, git-odb v0.40.2, git-packetline v0.14.2, git-transport v0.25.4, git-protocol v0.26.3, git-revision v0.10.2, git-refspec v0.7.2, git-worktree v0.12.2, git-repository v0.34.0, safety bump 3 crates ([`c196d20`](https://github.com/Byron/gitoxide/commit/c196d206d57a310b1ce974a1cf0e7e6d6db5c4d6))
+ - Thanks clippy ([`bac57dd`](https://github.com/Byron/gitoxide/commit/bac57dd05ea2d5a4ee45ef9350fa3f2e19474bc0))
+ - Release git-date v0.4.1, git-features v0.26.1, git-glob v0.5.2, git-attributes v0.8.1, git-tempfile v3.0.1, git-ref v0.23.1, git-sec v0.6.1, git-config v0.15.1, git-prompt v0.3.1, git-url v0.13.1, git-discover v0.12.1, git-index v0.12.2, git-mailmap v0.9.1, git-pack v0.30.1, git-odb v0.40.1, git-transport v0.25.3, git-protocol v0.26.2, git-revision v0.10.1, git-refspec v0.7.1, git-worktree v0.12.1, git-repository v0.33.0 ([`5b5b380`](https://github.com/Byron/gitoxide/commit/5b5b3809faa71c658db38b40dfc410224d08a367))
+ - Release git-features v0.26.0, git-actor v0.16.0, git-attributes v0.8.0, git-object v0.25.0, git-ref v0.22.0, git-config v0.14.0, git-command v0.2.1, git-url v0.13.0, git-credentials v0.9.0, git-diff v0.25.0, git-discover v0.11.0, git-traverse v0.21.0, git-index v0.11.0, git-mailmap v0.8.0, git-pack v0.29.0, git-odb v0.39.0, git-transport v0.25.0, git-protocol v0.26.0, git-revision v0.9.0, git-refspec v0.6.0, git-worktree v0.11.0, git-repository v0.31.0, safety bump 24 crates ([`5ac9fbe`](https://github.com/Byron/gitoxide/commit/5ac9fbe265a5b61c533a2a6b3abfed2bdf7f89ad))
+ - Release git-date v0.3.1, git-features v0.25.0, git-actor v0.15.0, git-glob v0.5.1, git-path v0.7.0, git-attributes v0.7.0, git-config-value v0.10.0, git-lock v3.0.1, git-validate v0.7.1, git-object v0.24.0, git-ref v0.21.0, git-sec v0.6.0, git-config v0.13.0, git-prompt v0.3.0, git-url v0.12.0, git-credentials v0.8.0, git-diff v0.24.0, git-discover v0.10.0, git-traverse v0.20.0, git-index v0.10.0, git-mailmap v0.7.0, git-pack v0.28.0, git-odb v0.38.0, git-packetline v0.14.1, git-transport v0.24.0, git-protocol v0.25.0, git-revision v0.8.0, git-refspec v0.5.0, git-worktree v0.10.0, git-repository v0.30.0, safety bump 26 crates ([`e6b9906`](https://github.com/Byron/gitoxide/commit/e6b9906c486b11057936da16ed6e0ec450a0fb83))
+ - Merge branch 'main' into read-split-index ([`c57bdde`](https://github.com/Byron/gitoxide/commit/c57bdde6de37eca9672ea715962bbd02aa3eb055))
+ - Merge branch 'adjustments-for-cargo' ([`083909b`](https://github.com/Byron/gitoxide/commit/083909bc7eb902eeee2002034fdb6ed88280dc5c))
+ - Adjust to changes in `git-testtools` ([`4eb842c`](https://github.com/Byron/gitoxide/commit/4eb842c7150b980e1c2637217e1f9657a671cea7))
+ - Merge branch 'main' into http-config ([`bcd9654`](https://github.com/Byron/gitoxide/commit/bcd9654e56169799eb706646da6ee1f4ef2021a9))
+ - Release git-hash v0.10.0, git-features v0.24.0, git-date v0.3.0, git-actor v0.14.0, git-glob v0.5.0, git-path v0.6.0, git-quote v0.4.0, git-attributes v0.6.0, git-config-value v0.9.0, git-tempfile v3.0.0, git-lock v3.0.0, git-validate v0.7.0, git-object v0.23.0, git-ref v0.20.0, git-sec v0.5.0, git-config v0.12.0, git-command v0.2.0, git-prompt v0.2.0, git-url v0.11.0, git-credentials v0.7.0, git-diff v0.23.0, git-discover v0.9.0, git-bitmap v0.2.0, git-traverse v0.19.0, git-index v0.9.0, git-mailmap v0.6.0, git-chunk v0.4.0, git-pack v0.27.0, git-odb v0.37.0, git-packetline v0.14.0, git-transport v0.23.0, git-protocol v0.24.0, git-revision v0.7.0, git-refspec v0.4.0, git-worktree v0.9.0, git-repository v0.29.0, git-commitgraph v0.11.0, gitoxide-core v0.21.0, gitoxide v0.19.0, safety bump 28 crates ([`b2c301e`](https://github.com/Byron/gitoxide/commit/b2c301ef131ffe1871314e19f387cf10a8d2ac16))
+ - Merge branch 'version2021' ([`0e4462d`](https://github.com/Byron/gitoxide/commit/0e4462df7a5166fe85c23a779462cdca8ee013e8))
+ - Upgrade edition to 2021 in most crates. ([`3d8fa8f`](https://github.com/Byron/gitoxide/commit/3d8fa8fef9800b1576beab8a5bc39b821157a5ed))
+ - Release git-glob v0.4.2, git-config-value v0.8.2, git-lock v2.2.0, git-ref v0.19.0, git-config v0.11.0, git-discover v0.8.0, git-index v0.8.0, git-transport v0.22.0, git-protocol v0.23.0, git-worktree v0.8.0, git-repository v0.28.0, gitoxide-core v0.20.0, gitoxide v0.18.0, safety bump 9 crates ([`0c253b1`](https://github.com/Byron/gitoxide/commit/0c253b15143dcedfe4c66d64ab1ea6e097030651))
+ - Release git-features v0.23.1, git-glob v0.4.1, git-config-value v0.8.1, git-tempfile v2.0.6, git-object v0.22.1, git-ref v0.18.0, git-sec v0.4.2, git-config v0.10.0, git-prompt v0.1.1, git-url v0.10.1, git-credentials v0.6.1, git-diff v0.21.0, git-discover v0.7.0, git-index v0.7.0, git-pack v0.25.0, git-odb v0.35.0, git-transport v0.21.1, git-protocol v0.22.0, git-refspec v0.3.1, git-worktree v0.7.0, git-repository v0.26.0, git-commitgraph v0.10.0, gitoxide-core v0.19.0, gitoxide v0.17.0, safety bump 9 crates ([`d071583`](https://github.com/Byron/gitoxide/commit/d071583c5576fdf5f7717765ffed5681792aa81f))
+ - Release git-hash v0.9.11, git-features v0.23.0, git-actor v0.13.0, git-attributes v0.5.0, git-object v0.22.0, git-ref v0.17.0, git-sec v0.4.1, git-config v0.9.0, git-url v0.10.0, git-credentials v0.6.0, git-diff v0.20.0, git-discover v0.6.0, git-traverse v0.18.0, git-index v0.6.0, git-mailmap v0.5.0, git-pack v0.24.0, git-odb v0.34.0, git-packetline v0.13.1, git-transport v0.21.0, git-protocol v0.21.0, git-revision v0.6.0, git-refspec v0.3.0, git-worktree v0.6.0, git-repository v0.25.0, safety bump 24 crates ([`104d922`](https://github.com/Byron/gitoxide/commit/104d922add61ab21c534c24ce8ed37cddf3e275a))
+ - Merge branch 'diff' ([`25a7726`](https://github.com/Byron/gitoxide/commit/25a7726377fbe400ea3c4927d04e9dec99802b7b))
+ - Release git-hash v0.9.10, git-features v0.22.5, git-date v0.2.0, git-actor v0.12.0, git-glob v0.4.0, git-path v0.5.0, git-quote v0.3.0, git-attributes v0.4.0, git-config-value v0.8.0, git-tempfile v2.0.5, git-validate v0.6.0, git-object v0.21.0, git-ref v0.16.0, git-sec v0.4.0, git-config v0.8.0, git-discover v0.5.0, git-traverse v0.17.0, git-index v0.5.0, git-worktree v0.5.0, git-testtools v0.9.0, git-command v0.1.0, git-prompt v0.1.0, git-url v0.9.0, git-credentials v0.5.0, git-diff v0.19.0, git-mailmap v0.4.0, git-chunk v0.3.2, git-pack v0.23.0, git-odb v0.33.0, git-packetline v0.13.0, git-transport v0.20.0, git-protocol v0.20.0, git-revision v0.5.0, git-refspec v0.2.0, git-repository v0.24.0, git-commitgraph v0.9.0, gitoxide-core v0.18.0, gitoxide v0.16.0, safety bump 28 crates ([`29a043b`](https://github.com/Byron/gitoxide/commit/29a043be6808a3e9199a9b26bd076fe843afe4f4))
+ - Merge branch 'filter-refs' ([`fd14489`](https://github.com/Byron/gitoxide/commit/fd14489f729172d615d0fa1e8dbd605e9eacf69d))
+ - Merge branch 'index-from-tree' ([`172f73c`](https://github.com/Byron/gitoxide/commit/172f73cf26878d153d51790fa01853fa4ba6beb7))
+ - Refactor ([`b2835cc`](https://github.com/Byron/gitoxide/commit/b2835cc28e10907eb375b2beb400cf408fa5a3e0))
+ - Merge branch 'main' into index-from-tree ([`bc64b96`](https://github.com/Byron/gitoxide/commit/bc64b96a2ec781c72d1d4daad38aa7fb8b74f99b))
+ - Merge branch 'main' into filter-refs-by-spec ([`cef0b51`](https://github.com/Byron/gitoxide/commit/cef0b51ade2a3301fa09ede7a425aa1fe3527e78))
+ - Release git-attributes v0.3.3, git-ref v0.15.3, git-index v0.4.3, git-worktree v0.4.3, git-testtools v0.8.0 ([`baad4ce`](https://github.com/Byron/gitoxide/commit/baad4ce51fe0e8c0c1de1b08148d8303878ca37b))
+ - Merge branch 'main' into filter-refs-by-spec ([`cfa1440`](https://github.com/Byron/gitoxide/commit/cfa144031dbcac2707ab0cec012bc35e78f9c475))
+ - Release git-date v0.0.5, git-hash v0.9.8, git-features v0.22.2, git-actor v0.11.3, git-glob v0.3.2, git-quote v0.2.1, git-attributes v0.3.2, git-tempfile v2.0.4, git-lock v2.1.1, git-validate v0.5.5, git-object v0.20.2, git-ref v0.15.2, git-sec v0.3.1, git-config v0.7.0, git-credentials v0.4.0, git-diff v0.17.2, git-discover v0.4.1, git-bitmap v0.1.2, git-index v0.4.2, git-mailmap v0.3.2, git-chunk v0.3.1, git-traverse v0.16.2, git-pack v0.21.2, git-odb v0.31.2, git-packetline v0.12.7, git-url v0.7.2, git-transport v0.19.2, git-protocol v0.19.0, git-revision v0.4.2, git-refspec v0.1.0, git-worktree v0.4.2, git-repository v0.22.0, safety bump 4 crates ([`4974eca`](https://github.com/Byron/gitoxide/commit/4974eca96d525d1ee4f8cad79bb713af7a18bf9d))
+ - Merge branch 'main' into remote-ls-refs ([`e2ee3de`](https://github.com/Byron/gitoxide/commit/e2ee3ded97e5c449933712883535b30d151c7c78))
+ - Merge branch 'docsrs-show-features' ([`31c2351`](https://github.com/Byron/gitoxide/commit/31c235140cad212d16a56195763fbddd971d87ce))
+ - Uniformize deny attributes ([`f7f136d`](https://github.com/Byron/gitoxide/commit/f7f136dbe4f86e7dee1d54835c420ec07c96cd78))
+ - Remove default link to cargo doc everywhere ([`533e887`](https://github.com/Byron/gitoxide/commit/533e887e80c5f7ede8392884562e1c5ba56fb9a8))
+ - Merge branch 'main' into remote-ls-refs ([`bd5f3e8`](https://github.com/Byron/gitoxide/commit/bd5f3e8db7e0bb4abfb7b0f79f585ab82c3a14ab))
+ - Release git-date v0.0.3, git-actor v0.11.1, git-attributes v0.3.1, git-tempfile v2.0.3, git-object v0.20.1, git-ref v0.15.1, git-config v0.6.1, git-diff v0.17.1, git-discover v0.4.0, git-bitmap v0.1.1, git-index v0.4.1, git-mailmap v0.3.1, git-traverse v0.16.1, git-pack v0.21.1, git-odb v0.31.1, git-packetline v0.12.6, git-url v0.7.1, git-transport v0.19.1, git-protocol v0.18.1, git-revision v0.4.0, git-worktree v0.4.1, git-repository v0.21.0, safety bump 5 crates ([`c96473d`](https://github.com/Byron/gitoxide/commit/c96473dce21c3464aacbc0a62d520c1a33172611))
+ - Merge branch 'rev-parse-delegate' ([`2f506c7`](https://github.com/Byron/gitoxide/commit/2f506c7c2988477b0f97d272a9ac9ed47b236457))
+ - Merge pull request #2 from SidneyDouw/main ([`ce885ad`](https://github.com/Byron/gitoxide/commit/ce885ad4c3324c09c83751c32e014f246c748766))
+ - Merge branch 'Byron:main' into main ([`9b9ea02`](https://github.com/Byron/gitoxide/commit/9b9ea0275f8ff5862f24cf5a4ca53bb1cd610709))
+ - Merge branch 'main' into rev-parse-delegate ([`6da8250`](https://github.com/Byron/gitoxide/commit/6da82507588d3bc849217c11d9a1d398b67f2ed6))
+ - Merge branch 'pathspec' ([`7db59a4`](https://github.com/Byron/gitoxide/commit/7db59a4074111086adfc2f79fd0d26bb30303ca9))
+ - Avoid another vec allocation by inlining code via closure. ([`d88952a`](https://github.com/Byron/gitoxide/commit/d88952a533cf2fa2ebf0f015b10f5983a1c8f144))
+ - Avoid temporary vec in favor of a `&'static [u8]`. ([`5a55dbf`](https://github.com/Byron/gitoxide/commit/5a55dbf5fd2ae8c28d95d72d55a30e4e7e2ef9cf))
+ - Improve docs and use 'new-style' in error messages. ([`e36d83e`](https://github.com/Byron/gitoxide/commit/e36d83e62eb7969726e7c8b3d25dbb743a508f8a))
+ - Assure all baseline samples are validated ([`4899722`](https://github.com/Byron/gitoxide/commit/489972209ee2ead2871ca2410bd10e51019dc9ad))
+ - Add documentation; rename `SearchMode` to `MatchMode`; add test ([`4f6fa59`](https://github.com/Byron/gitoxide/commit/4f6fa59d20b4e03663f3d7c3819a7d02b79ab982))
+ - Add basic docs for how to run the fuzzer ([`0c9bef4`](https://github.com/Byron/gitoxide/commit/0c9bef47a70a0787b63f9bf8e9b52f2ab9f72738))
+ - Rename `parser` fuzz target to `parse` ([`ef03823`](https://github.com/Byron/gitoxide/commit/ef03823b407bcdbac16c42e941809dfe7cde850b))
+ - Refactor ([`1cbc142`](https://github.com/Byron/gitoxide/commit/1cbc142d37599f4d7bfaf9cb07de41ee4b3f4c24))
+ - Update crate status and READMe ([`07352ce`](https://github.com/Byron/gitoxide/commit/07352ceb942dac5041fbf8584128404880166593))
+ - Refactor ([`63baa75`](https://github.com/Byron/gitoxide/commit/63baa752901388a46a4211c70f3b3a64aa36d4ec))
+ - Add readme file ([`913d94c`](https://github.com/Byron/gitoxide/commit/913d94c3c226aac321de12eb7ae8bfa3ee3458e9))
+ - Remove prefix stuff ([`b7baaa5`](https://github.com/Byron/gitoxide/commit/b7baaa5353aa52ca97488993b50cef72248387de))
+ - Refactor of `Name` and `Assignment` ([`6449e77`](https://github.com/Byron/gitoxide/commit/6449e77e11ef0d25c2990f1c29e9fbea3c97fb0a))
+ - Refactor ([`bffbcee`](https://github.com/Byron/gitoxide/commit/bffbcee68affce2a829c67bfe71e7df861c15ee5))
+ - Fix unescaping logic - thanks fuzzer ([`9c6281f`](https://github.com/Byron/gitoxide/commit/9c6281f903451011407a352e1fca877d79c10466))
+ - Add fuzzer ([`2a775c6`](https://github.com/Byron/gitoxide/commit/2a775c602da3edf20d84599839ca166bff2457a5))
+ - Check attr values regarless of it being escaped ([`6e93144`](https://github.com/Byron/gitoxide/commit/6e93144545277cb5efe1dd3fba2ecaf90ea9c726))
+ - Use "to_owned" instead of "into" ([`35c6d38`](https://github.com/Byron/gitoxide/commit/35c6d38088e09d88b30e12538e175a4a286980cd))
+ - Help type inference ([`4d6befd`](https://github.com/Byron/gitoxide/commit/4d6befdbad72d1d143edd344cc7e9e0cba1d1e8a))
+ - Fix build ([`1838f3d`](https://github.com/Byron/gitoxide/commit/1838f3db13eae6d278264dcdbc48d202de992349))
+ - Refactor ([`1bdf2e1`](https://github.com/Byron/gitoxide/commit/1bdf2e1d1b8f58ed2d6fe21c62edb93fc5473c14))
+ - Refactor ([`850bcc3`](https://github.com/Byron/gitoxide/commit/850bcc35f0e99ef1d65c6bd888638b9a67cab25b))
+ - Refactor ([`65c8349`](https://github.com/Byron/gitoxide/commit/65c83491281184161ad6d9831adabb8475722e42))
+ - Refactor attribute value unnescaping ([`24592f7`](https://github.com/Byron/gitoxide/commit/24592f7a4f6188d3bb0042f9e91dffc5fc01e382))
+ - Implement name::error for git-attributes ([`0849ebf`](https://github.com/Byron/gitoxide/commit/0849ebf4bc2052d7886f9425800a547bf530e967))
+ - Improved attribute value unescaping ([`1f89646`](https://github.com/Byron/gitoxide/commit/1f89646fc359f94ee001f5ed01623e5af7934a93))
+ - Merge branch 'main' into pathspec ([`89ea12b`](https://github.com/Byron/gitoxide/commit/89ea12b558bcc056b892193ee8fb44b8664b5da4))
+ - Refactor ([`9945ceb`](https://github.com/Byron/gitoxide/commit/9945ceb0a99c1343cb6e652e44900b36d3786e22))
+ - Refactor ([`3b2bab8`](https://github.com/Byron/gitoxide/commit/3b2bab89172b86068bda9704bc9d69690bcfb2ba))
+ - Refactor ([`852bcc3`](https://github.com/Byron/gitoxide/commit/852bcc316382fce5f5749942ecb43a73738ffe8f))
+ - Protected attribute name via "AttributeName" type ([`7bb408e`](https://github.com/Byron/gitoxide/commit/7bb408e631138854a6dff85ce356da96f61367de))
+ - Refactor ([`1ad98e8`](https://github.com/Byron/gitoxide/commit/1ad98e82f66c5f5eacb15f8ae38d8ccb1bc94e9e))
+ - Escape attribute values in pathspec crate... ([`c22e57f`](https://github.com/Byron/gitoxide/commit/c22e57f8e4131655595da2b81662e23258bb85c8))
+ - Refactor ([`7f00b50`](https://github.com/Byron/gitoxide/commit/7f00b50070c7b976a030ec836d2660ff5b7b5f72))
+ - Refactor ([`2523f96`](https://github.com/Byron/gitoxide/commit/2523f9606f0adedb20ac93cf4853298bcd996118))
+ - Refactor ([`699de03`](https://github.com/Byron/gitoxide/commit/699de03f0c981a9f8b5239c66dc425e504de1ec2))
+ - Refactor ([`7f93231`](https://github.com/Byron/gitoxide/commit/7f93231b4983f9ce596cea84ad4525feb3778dd6))
+ - Refactor ([`02fba2c`](https://github.com/Byron/gitoxide/commit/02fba2c124f3665112102469d41d476b6cf48dcd))
+ - Improved testing against the baseline ([`44991d3`](https://github.com/Byron/gitoxide/commit/44991d373bd2e2f71ccf27eabe9f074cb5fe7c18))
+ - Refactor ([`020bc24`](https://github.com/Byron/gitoxide/commit/020bc24973233edc261e05fd9935c5e598bf2922))
+ - Refactor ([`b490b4a`](https://github.com/Byron/gitoxide/commit/b490b4a7be579941c2664fbefb25dd341ed7d1e7))
+ - More testcases related to escape chars - still todo ([`f606515`](https://github.com/Byron/gitoxide/commit/f606515dfd89e28c78eaead3cf5023d5064618f5))
+ - No splitting on escaped commas in attribute values ([`c0196fa`](https://github.com/Byron/gitoxide/commit/c0196fa363088426de031e55b982f70573ab738d))
+ - Thanks clippy ([`f80eb85`](https://github.com/Byron/gitoxide/commit/f80eb851ab56b4580eb28935978487b9f37fe819))
+ - Remove attr from signature bitflag ([`998415d`](https://github.com/Byron/gitoxide/commit/998415d9a3a234787c017bd448410a24ad4965f0))
+ - Refactor ([`149d1b3`](https://github.com/Byron/gitoxide/commit/149d1b36f93d98002175cda362d50bac584c691a))
+ - Whitespace test added ([`eecd388`](https://github.com/Byron/gitoxide/commit/eecd388708017414fee9077066f24124d83b70ba))
+ - Refactor ([`476fa56`](https://github.com/Byron/gitoxide/commit/476fa56993391410fc0bafeccfcb8d4da8168bfc))
+ - Add more test cases ([`9ceea27`](https://github.com/Byron/gitoxide/commit/9ceea2718a63bdd55ea8b99c2f1656cc09850145))
+ - Thanks clippy ([`f7a3b69`](https://github.com/Byron/gitoxide/commit/f7a3b69e43e82471047091008355d180e646773d))
+ - Added more tests ([`476f31c`](https://github.com/Byron/gitoxide/commit/476f31c0f0fc7b29d02110e3a9b9a542defce63e))
+ - Refactor ([`d3ec61a`](https://github.com/Byron/gitoxide/commit/d3ec61a2fcc6d8269cb952def86a198a7ac9492e))
+ - Refactor ([`5a3c0fe`](https://github.com/Byron/gitoxide/commit/5a3c0fe8d56e9bc28eda77d3d64ef5338365622c))
+ - Refactor ([`162f9a0`](https://github.com/Byron/gitoxide/commit/162f9a06860fac69e6db6d76dc5051ec2e6ed2db))
+ - Pattern now has searchmode... ([`0bed938`](https://github.com/Byron/gitoxide/commit/0bed9382930486af144876d97b97479e03e0f1c1))
+ - Test refactor and bug fixes ([`57d8d90`](https://github.com/Byron/gitoxide/commit/57d8d90d246226fc9119612d10d31808f8fa3053))
+ - Pattern uses MagigSignature without Option ([`f1f4ab3`](https://github.com/Byron/gitoxide/commit/f1f4ab3e3f50d00db4756ea724e5fd1b8ee75a04))
+ - Error tests now use matches! ([`6a569a7`](https://github.com/Byron/gitoxide/commit/6a569a70d15c416f91ab20083747e25f867f7446))
+ - Refactor ([`13b7db5`](https://github.com/Byron/gitoxide/commit/13b7db526c0a56360998a731ba10a7b4990d9529))
+ - Refactor ([`2690b8a`](https://github.com/Byron/gitoxide/commit/2690b8a73c39175ccfddd098c1f72f2cdee048cf))
+ - Merge branch 'main' into SidneyDouw-pathspec ([`a22b1d8`](https://github.com/Byron/gitoxide/commit/a22b1d88a21311d44509018729c3ef1936cf052a))
+ - Hint for how to make a functional version bearable… ([`e8da186`](https://github.com/Byron/gitoxide/commit/e8da18663d5110c87200287a1bc0d1b6f86cf0f9))
+ - Refactor ([`a0477e9`](https://github.com/Byron/gitoxide/commit/a0477e9b1fdf6ef289208a77f0539ea090c84e79))
+ - Refactor ([`d109cfe`](https://github.com/Byron/gitoxide/commit/d109cfead637b0b2c2866fb411eeccbf6a5bff2c))
+ - Refactor ([`fbed980`](https://github.com/Byron/gitoxide/commit/fbed980797057efb22140e8ff371989d49cc2a73))
+ - Initial setup of pathspec module ([`fece972`](https://github.com/Byron/gitoxide/commit/fece9725d60201b16b67073c185195b88fa1ad20))
+ - Release git-pathspec v0.0.0 ([`d6bee3f`](https://github.com/Byron/gitoxide/commit/d6bee3f931741906126a800aec9d43bc6bf8690f))
+</details>
+
+## 0.0.0 (2022-03-17)
+
+An empty crate without any content to reserve the name for the gitoxide project.
+
diff --git a/vendor/gix-pathspec/Cargo.toml b/vendor/gix-pathspec/Cargo.toml
new file mode 100644
index 000000000..57527a4f4
--- /dev/null
+++ b/vendor/gix-pathspec/Cargo.toml
@@ -0,0 +1,53 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.65"
+name = "gix-pathspec"
+version = "0.3.0"
+authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"]
+description = "A crate of the gitoxide project dealing magical pathspecs"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/Byron/gitoxide"
+
+[lib]
+doctest = false
+
+[dependencies.bitflags]
+version = "2"
+
+[dependencies.bstr]
+version = "1.3.0"
+features = ["std"]
+default-features = false
+
+[dependencies.gix-attributes]
+version = "^0.19.0"
+
+[dependencies.gix-config-value]
+version = "^0.14.0"
+
+[dependencies.gix-glob]
+version = "^0.13.0"
+
+[dependencies.gix-path]
+version = "^0.10.0"
+
+[dependencies.thiserror]
+version = "1.0.26"
+
+[dev-dependencies.once_cell]
+version = "1.12.0"
+
+[dev-dependencies.serial_test]
+version = "2.0.0"
diff --git a/vendor/gix-pathspec/LICENSE-APACHE b/vendor/gix-pathspec/LICENSE-APACHE
new file mode 100644
index 000000000..a51f59a06
--- /dev/null
+++ b/vendor/gix-pathspec/LICENSE-APACHE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/gix-pathspec/LICENSE-MIT b/vendor/gix-pathspec/LICENSE-MIT
new file mode 100644
index 000000000..b58e818f1
--- /dev/null
+++ b/vendor/gix-pathspec/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/gix-pathspec/README.md b/vendor/gix-pathspec/README.md
new file mode 100644
index 000000000..ecaa8f56d
--- /dev/null
+++ b/vendor/gix-pathspec/README.md
@@ -0,0 +1,16 @@
+# `gix-pathspec`
+
+### Testing
+
+#### Fuzzing
+
+`cargo fuzz` is used for fuzzing, installable with `cargo install cargo-fuzz`.
+
+Targets can be listed with `cargo fuzz list` and executed via `cargo +nightly fuzz run <target>`,
+where `<target>` can be `parse` for example.
+
+### Notes
+
+- There is one additional keyword that `git` can parse, but that this crate doesn't support yet: the `prefix` keyword
+
+ [Here is a commit](https://github.com/git/git/commit/5be4efbefafcd5b81fe3d97e8395da1887b4902a) in which `prefix` is somewhat explained.
diff --git a/vendor/gix-pathspec/src/defaults.rs b/vendor/gix-pathspec/src/defaults.rs
new file mode 100644
index 000000000..81be53b38
--- /dev/null
+++ b/vendor/gix-pathspec/src/defaults.rs
@@ -0,0 +1,70 @@
+use std::ffi::OsString;
+
+use crate::{Defaults, MagicSignature, SearchMode};
+
+///
+pub mod from_environment {
+ /// The error returned by [Defaults::from_environment()](super::Defaults::from_environment()).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error(transparent)]
+ ParseValue(#[from] gix_config_value::Error),
+ #[error("Glob and no-glob settings are mutually exclusive")]
+ MixedGlobAndNoGlob,
+ }
+}
+
+impl Defaults {
+ /// Initialize this instance using information from the environment as
+ /// [per the official documentation](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables) *(look for `PATHSPECS`)*,
+ /// calling `var(variable_name)` for each variable that should be obtained.
+ ///
+ /// Used environment variables are `GIT_GLOB_PATHSPECS`, `GIT_NOGLOB_PATHSPECS`, `GIT_LITERAL_PATHSPECS` and `GIT_ICASE_PATHSPECS`.
+ /// Note that there are lot of failure modes, and instead of offering lenient parsing, the caller may ignore errors and
+ /// use other defaults instead.
+ ///
+ /// ### Deviation
+ ///
+ /// Instead of failing if `GIT_LITERAL_PATHSPECS` is used with glob globals, we ignore these. Also our implementation allows global
+ /// `icase` settings in combination with this setting.
+ pub fn from_environment(var: &mut dyn FnMut(&str) -> Option<OsString>) -> Result<Self, from_environment::Error> {
+ let mut env_bool = |name: &str| -> Result<Option<bool>, gix_config_value::Error> {
+ var(name)
+ .map(|val| gix_config_value::Boolean::try_from(val).map(|b| b.0))
+ .transpose()
+ };
+
+ let literal = env_bool("GIT_LITERAL_PATHSPECS")?.unwrap_or_default();
+ let signature = env_bool("GIT_ICASE_PATHSPECS")?
+ .and_then(|val| val.then_some(MagicSignature::ICASE))
+ .unwrap_or_default();
+ if literal {
+ return Ok(Defaults {
+ signature,
+ search_mode: SearchMode::Literal,
+ literal,
+ });
+ }
+ let glob = env_bool("GIT_GLOB_PATHSPECS")?;
+ let mut search_mode = glob
+ .and_then(|glob| glob.then_some(SearchMode::PathAwareGlob))
+ .unwrap_or_default();
+ search_mode = env_bool("GIT_NOGLOB_PATHSPECS")?
+ .map(|no_glob| {
+ if glob.unwrap_or_default() && no_glob {
+ Err(from_environment::Error::MixedGlobAndNoGlob)
+ } else {
+ Ok(SearchMode::Literal)
+ }
+ })
+ .transpose()?
+ .unwrap_or(search_mode);
+
+ Ok(Defaults {
+ signature,
+ search_mode,
+ literal,
+ })
+ }
+}
diff --git a/vendor/gix-pathspec/src/lib.rs b/vendor/gix-pathspec/src/lib.rs
new file mode 100644
index 000000000..9f91567da
--- /dev/null
+++ b/vendor/gix-pathspec/src/lib.rs
@@ -0,0 +1,143 @@
+//! Parse [path specifications](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) and
+//! see if a path matches.
+#![deny(missing_docs, rust_2018_idioms)]
+#![forbid(unsafe_code)]
+
+use std::path::PathBuf;
+
+use bitflags::bitflags;
+use bstr::BString;
+/// `gix-glob` types are available through [`attributes::glob`].
+pub use gix_attributes as attributes;
+
+///
+pub mod normalize {
+ use std::path::PathBuf;
+
+ /// The error returned by [Pattern::normalize()](super::Pattern::normalize()).
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("The path '{}' is not inside of the worktree '{}'", path.display(), worktree_path.display())]
+ AbsolutePathOutsideOfWorktree { path: PathBuf, worktree_path: PathBuf },
+ #[error("The path '{}' leaves the repository", path.display())]
+ OutsideOfWorktree { path: PathBuf },
+ }
+}
+
+mod pattern;
+
+///
+pub mod search;
+
+///
+pub mod parse;
+
+/// Default settings for some fields of a [`Pattern`].
+///
+/// These can be used to represent `GIT_*_PATHSPECS` environment variables, for example.
+#[derive(Debug, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
+pub struct Defaults {
+ /// The default signature.
+ pub signature: MagicSignature,
+ /// The default search-mode.
+ ///
+ /// Note that even if it's [`SearchMode::Literal`], the pathspecs will be parsed as usual, but matched verbatim afterwards.
+ ///
+ /// Note that pathspecs can override this the [`SearchMode::Literal`] variant with an explicit `:(glob)` prefix.
+ pub search_mode: SearchMode,
+ /// If set, the pathspec will not be parsed but used verbatim. Implies [`SearchMode::Literal`] for `search_mode`.
+ pub literal: bool,
+}
+
+///
+pub mod defaults;
+
+/// A lists of pathspec patterns, possibly from a file.
+///
+/// Pathspecs are generally relative to the root of the repository.
+#[derive(Debug, Clone)]
+pub struct Search {
+ /// Patterns and their associated data in the order they were loaded in or specified,
+ /// the line number in its source file or its sequence number (_`(pattern, value, line_number)`_).
+ ///
+ /// During matching, this order is reversed.
+ patterns: Vec<gix_glob::search::pattern::Mapping<search::Spec>>,
+
+ /// The path from which the patterns were read, or `None` if the patterns
+ /// don't originate in a file on disk.
+ pub source: Option<PathBuf>,
+
+ /// If `true`, this means all `patterns` are exclude patterns. This means that if there is no match
+ /// (which would exclude an item), we would actually match it for lack of exclusion.
+ all_patterns_are_excluded: bool,
+ /// The amount of bytes that are in common among all `patterns` and that aren't matched case-insensitively
+ common_prefix_len: usize,
+}
+
+/// The output of a pathspec [parsing][parse()] operation. It can be used to match against a one or more paths.
+#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
+pub struct Pattern {
+ /// The path part of a pathspec, which is typically a path possibly mixed with glob patterns.
+ /// Note that it might be an empty string as well.
+ ///
+ /// For example, `:(top,literal,icase,attr,exclude)some/path` would yield `some/path`.
+ path: BString,
+ /// All magic signatures that were included in the pathspec.
+ pub signature: MagicSignature,
+ /// The search mode of the pathspec.
+ pub search_mode: SearchMode,
+ /// All attributes that were included in the `ATTR` part of the pathspec, if present.
+ ///
+ /// `:(attr:a=one b=):path` would yield attribute `a` and `b`.
+ pub attributes: Vec<gix_attributes::Assignment>,
+ /// If `true`, we are a special Nil pattern and always match.
+ nil: bool,
+ /// The length of bytes in `path` that belong to the prefix, which will always be matched case-sensitively
+ /// on case-sensitive filesystems.
+ ///
+ /// That way, even though pathspecs are applied from the top, we can emulate having changed directory into
+ /// a specific sub-directory in a case-sensitive file-system, even if the rest of the pathspec can be set to
+ /// match case-insensitively.
+ /// Is set by [Pattern::normalize()].
+ prefix_len: usize,
+}
+
+bitflags! {
+ /// Flags to represent 'magic signatures' which are parsed behind colons, like `:top:`.
+ #[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
+ pub struct MagicSignature: u32 {
+ /// Matches patterns from the root of the repository
+ const TOP = 1 << 0;
+ /// Matches patterns in case insensitive mode
+ const ICASE = 1 << 1;
+ /// Excludes the matching patterns from the previous results
+ const EXCLUDE = 1 << 2;
+ /// The pattern must match a directory, and not a file.
+ /// This is equivalent to how it's handled in `gix-glob`
+ const MUST_BE_DIR = 1 << 3;
+ }
+}
+
+/// Parts of [magic signatures][MagicSignature] which don't stack as they all configure
+/// the way path specs are matched.
+#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
+pub enum SearchMode {
+ /// Expand special characters like `*` similar to how the shell would do it.
+ ///
+ /// See [`PathAwareGlob`](SearchMode::PathAwareGlob) for the alternative.
+ #[default]
+ ShellGlob,
+ /// Special characters in the pattern, like `*` or `?`, are treated literally, effectively turning off globbing.
+ Literal,
+ /// A single `*` will not match a `/` in the pattern, but a `**` will
+ PathAwareGlob,
+}
+
+/// Parse a git-style pathspec into a [`Pattern`][Pattern],
+/// setting the given `default` values in case these aren't specified in `input`.
+///
+/// Note that empty [paths](Pattern::path) are allowed here, and generally some processing has to be performed.
+pub fn parse(input: &[u8], default: Defaults) -> Result<Pattern, parse::Error> {
+ Pattern::from_bytes(input, default)
+}
diff --git a/vendor/gix-pathspec/src/parse.rs b/vendor/gix-pathspec/src/parse.rs
new file mode 100644
index 000000000..9a21511ca
--- /dev/null
+++ b/vendor/gix-pathspec/src/parse.rs
@@ -0,0 +1,263 @@
+use std::borrow::Cow;
+
+use bstr::{BStr, BString, ByteSlice, ByteVec};
+
+use crate::{Defaults, MagicSignature, Pattern, SearchMode};
+
+/// The error returned by [parse()][crate::parse()].
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error("An empty string is not a valid pathspec")]
+ EmptyString,
+ #[error("Found {keyword:?} in signature, which is not a valid keyword")]
+ InvalidKeyword { keyword: BString },
+ #[error("Unimplemented short keyword: {short_keyword:?}")]
+ Unimplemented { short_keyword: char },
+ #[error("Missing ')' at the end of pathspec signature")]
+ MissingClosingParenthesis,
+ #[error("Attribute has non-ascii characters or starts with '-': {attribute:?}")]
+ InvalidAttribute { attribute: BString },
+ #[error("Invalid character in attribute value: {character:?}")]
+ InvalidAttributeValue { character: char },
+ #[error("Escape character '\\' is not allowed as the last character in an attribute value")]
+ TrailingEscapeCharacter,
+ #[error("Attribute specification cannot be empty")]
+ EmptyAttribute,
+ #[error("Only one attribute specification is allowed in the same pathspec")]
+ MultipleAttributeSpecifications,
+ #[error("'literal' and 'glob' keywords cannot be used together in the same pathspec")]
+ IncompatibleSearchModes,
+}
+
+impl Pattern {
+ /// Try to parse a path-spec pattern from the given `input` bytes.
+ pub fn from_bytes(
+ input: &[u8],
+ Defaults {
+ signature,
+ search_mode,
+ literal,
+ }: Defaults,
+ ) -> Result<Self, Error> {
+ if input.is_empty() {
+ return Err(Error::EmptyString);
+ }
+ if literal {
+ return Ok(Self::from_literal(input, signature));
+ }
+ if input.as_bstr() == ":" {
+ return Ok(Pattern {
+ nil: true,
+ ..Default::default()
+ });
+ }
+
+ let mut p = Pattern {
+ signature,
+ search_mode: SearchMode::default(),
+ ..Default::default()
+ };
+
+ let mut cursor = 0;
+ if input.first() == Some(&b':') {
+ cursor += 1;
+ p.signature |= parse_short_keywords(input, &mut cursor)?;
+ if let Some(b'(') = input.get(cursor) {
+ cursor += 1;
+ parse_long_keywords(input, &mut p, &mut cursor)?;
+ }
+ }
+
+ if search_mode != Default::default() && p.search_mode == Default::default() {
+ p.search_mode = search_mode;
+ }
+ let mut path = &input[cursor..];
+ if path.last() == Some(&b'/') {
+ p.signature |= MagicSignature::MUST_BE_DIR;
+ path = &path[..path.len() - 1];
+ }
+ p.path = path.into();
+ Ok(p)
+ }
+
+ /// Take `input` literally without parsing anything. This will also set our mode to `literal` to allow this pathspec to match `input` verbatim, and
+ /// use `default_signature` as magic signature.
+ pub fn from_literal(input: &[u8], default_signature: MagicSignature) -> Self {
+ Pattern {
+ path: input.into(),
+ signature: default_signature,
+ search_mode: SearchMode::Literal,
+ ..Default::default()
+ }
+ }
+}
+
+fn parse_short_keywords(input: &[u8], cursor: &mut usize) -> Result<MagicSignature, Error> {
+ let unimplemented_chars = b"\"#%&'-',;<=>@_`~";
+
+ let mut signature = MagicSignature::empty();
+ while let Some(&b) = input.get(*cursor) {
+ *cursor += 1;
+ signature |= match b {
+ b'/' => MagicSignature::TOP,
+ b'^' | b'!' => MagicSignature::EXCLUDE,
+ b':' => break,
+ _ if unimplemented_chars.contains(&b) => {
+ return Err(Error::Unimplemented {
+ short_keyword: b.into(),
+ });
+ }
+ _ => {
+ *cursor -= 1;
+ break;
+ }
+ }
+ }
+
+ Ok(signature)
+}
+
+fn parse_long_keywords(input: &[u8], p: &mut Pattern, cursor: &mut usize) -> Result<(), Error> {
+ let end = input.find(")").ok_or(Error::MissingClosingParenthesis)?;
+
+ let input = &input[*cursor..end];
+ *cursor = end + 1;
+
+ if input.is_empty() {
+ return Ok(());
+ }
+
+ split_on_non_escaped_char(input, b',', |keyword| {
+ let attr_prefix = b"attr:";
+ match keyword {
+ b"attr" => {}
+ b"top" => p.signature |= MagicSignature::TOP,
+ b"icase" => p.signature |= MagicSignature::ICASE,
+ b"exclude" => p.signature |= MagicSignature::EXCLUDE,
+ b"literal" => match p.search_mode {
+ SearchMode::PathAwareGlob => return Err(Error::IncompatibleSearchModes),
+ _ => p.search_mode = SearchMode::Literal,
+ },
+ b"glob" => match p.search_mode {
+ SearchMode::Literal => return Err(Error::IncompatibleSearchModes),
+ _ => p.search_mode = SearchMode::PathAwareGlob,
+ },
+ _ if keyword.starts_with(attr_prefix) => {
+ if p.attributes.is_empty() {
+ p.attributes = parse_attributes(&keyword[attr_prefix.len()..])?;
+ } else {
+ return Err(Error::MultipleAttributeSpecifications);
+ }
+ }
+ _ => {
+ return Err(Error::InvalidKeyword {
+ keyword: BString::from(keyword),
+ });
+ }
+ };
+ Ok(())
+ })
+}
+
+fn split_on_non_escaped_char(
+ input: &[u8],
+ split_char: u8,
+ mut f: impl FnMut(&[u8]) -> Result<(), Error>,
+) -> Result<(), Error> {
+ let mut i = 0;
+ let mut last = 0;
+ for window in input.windows(2) {
+ i += 1;
+ if window[0] != b'\\' && window[1] == split_char {
+ let keyword = &input[last..i];
+ f(keyword)?;
+ last = i + 1;
+ }
+ }
+ let last_keyword = &input[last..];
+ f(last_keyword)
+}
+
+fn parse_attributes(input: &[u8]) -> Result<Vec<gix_attributes::Assignment>, Error> {
+ if input.is_empty() {
+ return Err(Error::EmptyAttribute);
+ }
+
+ let unescaped = unescape_attribute_values(input.into())?;
+
+ gix_attributes::parse::Iter::new(unescaped.as_bstr())
+ .map(|res| res.map(gix_attributes::AssignmentRef::to_owned))
+ .collect::<Result<Vec<_>, _>>()
+ .map_err(|e| Error::InvalidAttribute { attribute: e.attribute })
+}
+
+fn unescape_attribute_values(input: &BStr) -> Result<Cow<'_, BStr>, Error> {
+ if !input.contains(&b'=') {
+ return Ok(Cow::Borrowed(input));
+ }
+
+ let mut out: Cow<'_, BStr> = Cow::Borrowed("".into());
+
+ for attr in input.split(|&c| c == b' ') {
+ let split_point = attr.find_byte(b'=').map_or_else(|| attr.len(), |i| i + 1);
+ let (name, value) = attr.split_at(split_point);
+
+ if value.contains(&b'\\') {
+ let out = out.to_mut();
+ out.push_str(name);
+ out.push_str(unescape_and_check_attr_value(value.into())?);
+ out.push(b' ');
+ } else {
+ check_attribute_value(value.as_bstr())?;
+ match out {
+ Cow::Borrowed(_) => {
+ let end = out.len() + attr.len() + 1;
+ out = Cow::Borrowed(&input[0..end.min(input.len())]);
+ }
+ Cow::Owned(_) => {
+ let out = out.to_mut();
+ out.push_str(name);
+ out.push_str(value);
+ out.push(b' ');
+ }
+ }
+ }
+ }
+
+ Ok(out)
+}
+
+fn unescape_and_check_attr_value(value: &BStr) -> Result<BString, Error> {
+ let mut out = BString::from(Vec::with_capacity(value.len()));
+ let mut bytes = value.iter();
+ while let Some(mut b) = bytes.next().copied() {
+ if b == b'\\' {
+ b = *bytes.next().ok_or(Error::TrailingEscapeCharacter)?;
+ }
+
+ out.push(validated_attr_value_byte(b)?);
+ }
+ Ok(out)
+}
+
+fn check_attribute_value(input: &BStr) -> Result<(), Error> {
+ match input.iter().copied().find(|b| !is_valid_attr_value(*b)) {
+ Some(b) => Err(Error::InvalidAttributeValue { character: b as char }),
+ None => Ok(()),
+ }
+}
+
+fn is_valid_attr_value(byte: u8) -> bool {
+ byte.is_ascii_alphanumeric() || b",-_".contains(&byte)
+}
+
+fn validated_attr_value_byte(byte: u8) -> Result<u8, Error> {
+ if is_valid_attr_value(byte) {
+ Ok(byte)
+ } else {
+ Err(Error::InvalidAttributeValue {
+ character: byte as char,
+ })
+ }
+}
diff --git a/vendor/gix-pathspec/src/pattern.rs b/vendor/gix-pathspec/src/pattern.rs
new file mode 100644
index 000000000..09fd058f1
--- /dev/null
+++ b/vendor/gix-pathspec/src/pattern.rs
@@ -0,0 +1,194 @@
+use std::path::{Component, Path, PathBuf};
+
+use bstr::{BStr, BString, ByteSlice, ByteVec};
+
+use crate::{normalize, MagicSignature, Pattern, SearchMode};
+
+/// Access
+impl Pattern {
+ /// Returns `true` if this seems to be a pathspec that indicates that 'there is no pathspec'.
+ ///
+ /// Note that such a spec is `:`.
+ pub fn is_nil(&self) -> bool {
+ self.nil
+ }
+
+ /// Return the prefix-portion of the `path` of this spec, which is a *directory*.
+ /// It can be empty if there is no prefix.
+ ///
+ /// A prefix is effectively the CWD seen as relative to the working tree, and it's assumed to
+ /// match case-sensitively. This makes it useful for skipping over large portions of input by
+ /// directly comparing them.
+ pub fn prefix_directory(&self) -> &BStr {
+ self.path[..self.prefix_len].as_bstr()
+ }
+
+ /// Return the path of this spec, typically used for matching.
+ pub fn path(&self) -> &BStr {
+ self.path.as_ref()
+ }
+}
+
+/// Mutation
+impl Pattern {
+ /// Normalize the pattern's path by assuring it's relative to the root of the working tree, and contains
+ /// no relative path components. Further, it assures that `/` are used as path separator.
+ ///
+ /// If `self.path` is a relative path, it will be put in front of the pattern path if `self.signature` isn't indicating `TOP` already.
+ /// If `self.path` is an absolute path, we will use `root` to make it worktree relative if possible.
+ ///
+ /// `prefix` can be empty, we will still normalize this pathspec to resolve relative path components, and
+ /// it is assumed not to contain any relative path components, e.g. '', 'a', 'a/b' are valid.
+ /// `root` is the absolute path to the root of either the worktree or the repository's `git_dir`.
+ pub fn normalize(&mut self, prefix: &Path, root: &Path) -> Result<&mut Self, normalize::Error> {
+ fn prefix_components_to_subtract(path: &Path) -> usize {
+ let parent_component_end_bound = path.components().enumerate().fold(None::<usize>, |acc, (idx, c)| {
+ matches!(c, Component::ParentDir).then_some(idx + 1).or(acc)
+ });
+ let count = path
+ .components()
+ .take(parent_component_end_bound.unwrap_or(0))
+ .map(|c| match c {
+ Component::ParentDir => 1_isize,
+ Component::Normal(_) => -1,
+ _ => 0,
+ })
+ .sum::<isize>();
+ (count > 0).then_some(count as usize).unwrap_or_default()
+ }
+
+ let mut path = gix_path::from_bstr(self.path.as_bstr());
+ let mut num_prefix_components = 0;
+ let mut was_absolute = false;
+ if gix_path::is_absolute(path.as_ref()) {
+ was_absolute = true;
+ let rela_path = match path.strip_prefix(root) {
+ Ok(path) => path,
+ Err(_) => {
+ return Err(normalize::Error::AbsolutePathOutsideOfWorktree {
+ path: path.into_owned(),
+ worktree_path: root.into(),
+ })
+ }
+ };
+ path = rela_path.to_owned().into();
+ } else if !prefix.as_os_str().is_empty() && !self.signature.contains(MagicSignature::TOP) {
+ debug_assert_eq!(
+ prefix
+ .components()
+ .filter(|c| matches!(c, Component::Normal(_)))
+ .count(),
+ prefix.components().count(),
+ "BUG: prefixes must not have relative path components, or calculations here will be wrong so pattern won't match"
+ );
+ num_prefix_components = prefix
+ .components()
+ .count()
+ .saturating_sub(prefix_components_to_subtract(path.as_ref()));
+ path = prefix.join(path).into();
+ }
+
+ let assure_path_cannot_break_out_upwards = Path::new("");
+ let path = match gix_path::normalize(path.as_ref().into(), assure_path_cannot_break_out_upwards) {
+ Some(path) => {
+ if was_absolute {
+ num_prefix_components = path.components().count().saturating_sub(
+ if self.signature.contains(MagicSignature::MUST_BE_DIR) {
+ 0
+ } else {
+ 1
+ },
+ );
+ }
+ path
+ }
+ None => {
+ return Err(normalize::Error::OutsideOfWorktree {
+ path: path.into_owned(),
+ })
+ }
+ };
+
+ self.path = if path == Path::new(".") {
+ BString::from(".")
+ } else {
+ let cleaned = PathBuf::from_iter(path.components().filter(|c| !matches!(c, Component::CurDir)));
+ let mut out = gix_path::to_unix_separators_on_windows(gix_path::into_bstr(cleaned)).into_owned();
+ self.prefix_len = {
+ if self.signature.contains(MagicSignature::MUST_BE_DIR) {
+ out.push(b'/');
+ }
+ let len = out
+ .find_iter(b"/")
+ .take(num_prefix_components)
+ .last()
+ .unwrap_or_default();
+ if self.signature.contains(MagicSignature::MUST_BE_DIR) {
+ out.pop();
+ }
+ len
+ };
+ out
+ };
+
+ Ok(self)
+ }
+}
+
+/// Access
+impl Pattern {
+ /// Return `true` if this pathspec is negated, which means it will exclude an item from the result set instead of including it.
+ pub fn is_excluded(&self) -> bool {
+ self.signature.contains(MagicSignature::EXCLUDE)
+ }
+
+ /// Translate ourselves to a long display format, that when parsed back will yield the same pattern.
+ ///
+ /// Note that the
+ pub fn to_bstring(&self) -> BString {
+ if self.is_nil() {
+ ":".into()
+ } else {
+ let mut buf: BString = ":(".into();
+ if self.signature.contains(MagicSignature::TOP) {
+ buf.push_str("top,");
+ }
+ if self.signature.contains(MagicSignature::EXCLUDE) {
+ buf.push_str("exclude,");
+ }
+ if self.signature.contains(MagicSignature::ICASE) {
+ buf.push_str("icase,");
+ }
+ match self.search_mode {
+ SearchMode::ShellGlob => {}
+ SearchMode::Literal => buf.push_str("literal,"),
+ SearchMode::PathAwareGlob => buf.push_str("glob,"),
+ }
+ if self.attributes.is_empty() {
+ if buf.last() == Some(&b',') {
+ buf.pop();
+ }
+ } else {
+ buf.push_str("attr:");
+ for attr in &self.attributes {
+ let attr = attr.as_ref().to_string().replace(',', "\\,");
+ buf.push_str(&attr);
+ buf.push(b' ');
+ }
+ buf.pop(); // trailing ' '
+ }
+ buf.push(b')');
+ buf.extend_from_slice(&self.path);
+ if self.signature.contains(MagicSignature::MUST_BE_DIR) {
+ buf.push(b'/');
+ }
+ buf
+ }
+ }
+}
+
+impl std::fmt::Display for Pattern {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.to_bstring().fmt(f)
+ }
+}
diff --git a/vendor/gix-pathspec/src/search/init.rs b/vendor/gix-pathspec/src/search/init.rs
new file mode 100644
index 000000000..bc252f230
--- /dev/null
+++ b/vendor/gix-pathspec/src/search/init.rs
@@ -0,0 +1,146 @@
+use std::path::Path;
+
+use crate::{search::Spec, MagicSignature, Pattern, Search};
+
+/// Create a new specification to support matches from `pathspec`, [normalizing](Pattern::normalize()) it with `prefix` and `root`.
+fn mapping_from_pattern(
+ mut pathspec: Pattern,
+ prefix: &Path,
+ root: &Path,
+ sequence_number: usize,
+) -> Result<gix_glob::search::pattern::Mapping<Spec>, crate::normalize::Error> {
+ pathspec.normalize(prefix, root)?;
+ let mut match_all = pathspec.is_nil();
+ let glob = {
+ let mut g = gix_glob::Pattern::from_bytes_without_negation(&pathspec.path).unwrap_or_else(|| {
+ match_all = true;
+ // This pattern is setup to match literally as all-whitespace.
+ gix_glob::Pattern {
+ text: pathspec.path.clone(),
+ mode: gix_glob::pattern::Mode::empty(),
+ first_wildcard_pos: None,
+ }
+ });
+ g.mode |= gix_glob::pattern::Mode::ABSOLUTE;
+ if pathspec.signature.contains(MagicSignature::MUST_BE_DIR) {
+ g.mode |= gix_glob::pattern::Mode::MUST_BE_DIR;
+ }
+ g
+ };
+
+ Ok(gix_glob::search::pattern::Mapping {
+ pattern: glob,
+ value: Spec {
+ attrs_match: {
+ (!pathspec.attributes.is_empty()).then(|| {
+ let mut out = gix_attributes::search::Outcome::default();
+ out.initialize_with_selection(
+ &Default::default(),
+ pathspec.attributes.iter().map(|a| a.name.as_str()),
+ );
+ out
+ })
+ },
+ pattern: pathspec,
+ },
+ sequence_number,
+ })
+}
+
+fn common_prefix_len(patterns: &[gix_glob::search::pattern::Mapping<Spec>]) -> usize {
+ let mut count = 0;
+ let len = patterns
+ .iter()
+ .filter(|p| !p.value.pattern.is_excluded())
+ .map(|p| {
+ count += 1;
+ if p.value.pattern.signature.contains(MagicSignature::ICASE) {
+ p.value.pattern.prefix_len
+ } else {
+ p.pattern.first_wildcard_pos.unwrap_or(p.pattern.text.len())
+ }
+ })
+ .min()
+ .unwrap_or_default();
+
+ if len == 0 {
+ return 0;
+ }
+
+ let mut max_len = len;
+ if count < 2 {
+ return max_len;
+ }
+
+ let mut patterns = patterns
+ .iter()
+ .filter(|p| !p.value.pattern.is_excluded())
+ .map(|p| &p.value.pattern.path);
+ let base = &patterns.next().expect("at least two patterns");
+ for path in patterns {
+ for (idx, (a, b)) in base[..max_len].iter().zip(path[..max_len].iter()).enumerate() {
+ if *a != *b {
+ max_len = idx;
+ break;
+ }
+ }
+ }
+ max_len
+}
+
+/// Lifecycle
+impl Search {
+ /// Create a search from ready-made `pathspecs`, and [normalize](Pattern::normalize()) them with `prefix` and `root`.
+ /// `root` is the absolute path to the worktree root, if available, or the `git_dir` in case of bare repositories.
+ /// If `pathspecs` doesn't yield any pattern, we will match everything automatically. If `prefix` is also provided and not empty,
+ /// an artificial pattern will be added to yield all.
+ pub fn from_specs(
+ pathspecs: impl IntoIterator<Item = Pattern>,
+ prefix: Option<&std::path::Path>,
+ root: &std::path::Path,
+ ) -> Result<Self, crate::normalize::Error> {
+ fn inner(
+ pathspecs: &mut dyn Iterator<Item = Pattern>,
+ prefix: Option<&std::path::Path>,
+ root: &std::path::Path,
+ ) -> Result<Search, crate::normalize::Error> {
+ let prefix = prefix.unwrap_or(std::path::Path::new(""));
+ let mut patterns = pathspecs
+ .enumerate()
+ .map(|(idx, pattern)| mapping_from_pattern(pattern, prefix, root, idx))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ if patterns.is_empty() && !prefix.as_os_str().is_empty() {
+ patterns.push(mapping_from_pattern(
+ Pattern::from_literal(&[], MagicSignature::MUST_BE_DIR),
+ prefix,
+ root,
+ 0,
+ )?);
+ }
+
+ // Excludes should always happen first so we know a match is authoritative (otherwise we could find a non-excluding match first).
+ patterns.sort_by(|a, b| {
+ a.value
+ .pattern
+ .is_excluded()
+ .cmp(&b.value.pattern.is_excluded())
+ .reverse()
+ });
+
+ let common_prefix_len = common_prefix_len(&patterns);
+ Ok(Search {
+ all_patterns_are_excluded: patterns.iter().all(|s| s.value.pattern.is_excluded()),
+ patterns,
+ source: None,
+ common_prefix_len,
+ })
+ }
+ inner(&mut pathspecs.into_iter(), prefix, root)
+ }
+
+ /// Obtain ownership of the normalized pathspec patterns that were used for the search.
+ pub fn into_patterns(self) -> impl Iterator<Item = Pattern> {
+ self.patterns.into_iter().map(|p| p.value.pattern)
+ }
+}
diff --git a/vendor/gix-pathspec/src/search/matching.rs b/vendor/gix-pathspec/src/search/matching.rs
new file mode 100644
index 000000000..c7c8f2cbb
--- /dev/null
+++ b/vendor/gix-pathspec/src/search/matching.rs
@@ -0,0 +1,149 @@
+use bstr::{BStr, BString, ByteSlice};
+use gix_glob::pattern::Case;
+
+use crate::{
+ search::{Match, Spec},
+ MagicSignature, Pattern, Search, SearchMode,
+};
+
+impl Search {
+ /// Return the first [`Match`] of `relative_path`, or `None`.
+ /// `is_dir` is `true` if `relative_path` is a directory.
+ /// `attributes` is called as `attributes(relative_path, case, is_dir, outcome) -> has_match` to obtain for attributes for `relative_path`, if
+ /// the underlying pathspec defined an attribute filter, to be stored in `outcome`, returning true if there was a match.
+ /// All attributes of the pathspec have to be present in the defined value for the pathspec to match.
+ ///
+ /// Note that `relative_path` is expected to be starting at the same root as is assumed for this pattern, see [`Pattern::normalize()`].
+ /// Further, empty searches match everything, as if `:` was provided.
+ ///
+ /// ### Deviation
+ ///
+ /// The case-sensivity of the attribute match is controlled by the sensitivity of the pathspec, instead of being based on the
+ /// case folding settings of the repository. That way we assure that the matching is consistent.
+ /// Higher-level crates should control this default case folding of pathspecs when instantiating them, which is when they can
+ /// set it to match the repository setting for more natural behaviour when, for instance, adding files to a repository:
+ /// as it stands, on a case-insensitive file system, `touch File && git add file` will not add the file, but also not error.
+ pub fn pattern_matching_relative_path(
+ &mut self,
+ relative_path: &BStr,
+ is_dir: Option<bool>,
+ attributes: &mut dyn FnMut(&BStr, Case, bool, &mut gix_attributes::search::Outcome) -> bool,
+ ) -> Option<Match<'_>> {
+ let basename_not_important = None;
+ if relative_path
+ .get(..self.common_prefix_len)
+ .map_or(true, |rela_path_prefix| rela_path_prefix != self.common_prefix())
+ {
+ return None;
+ }
+
+ let is_dir = is_dir.unwrap_or(false);
+ let patterns_len = self.patterns.len();
+ let res = self.patterns.iter_mut().find_map(|mapping| {
+ let ignore_case = mapping.value.pattern.signature.contains(MagicSignature::ICASE);
+ let prefix = mapping.value.pattern.prefix_directory();
+ if ignore_case && !prefix.is_empty() {
+ let pattern_requirement_is_met = relative_path.get(prefix.len()).map_or_else(|| is_dir, |b| *b == b'/');
+ if !pattern_requirement_is_met
+ || relative_path.get(..prefix.len()).map(ByteSlice::as_bstr) != Some(prefix)
+ {
+ return None;
+ }
+ }
+
+ let case = if ignore_case { Case::Fold } else { Case::Sensitive };
+ let mut is_match = mapping.value.pattern.is_nil() || mapping.value.pattern.path.is_empty();
+ if !is_match {
+ is_match = if mapping.pattern.first_wildcard_pos.is_none() {
+ match_verbatim(mapping, relative_path, is_dir, case)
+ } else {
+ let wildmatch_mode = match mapping.value.pattern.search_mode {
+ SearchMode::ShellGlob => Some(gix_glob::wildmatch::Mode::empty()),
+ SearchMode::Literal => None,
+ SearchMode::PathAwareGlob => Some(gix_glob::wildmatch::Mode::NO_MATCH_SLASH_LITERAL),
+ };
+ match wildmatch_mode {
+ Some(wildmatch_mode) => {
+ let is_match = mapping.pattern.matches_repo_relative_path(
+ relative_path,
+ basename_not_important,
+ Some(is_dir),
+ case,
+ wildmatch_mode,
+ );
+ if !is_match {
+ match_verbatim(mapping, relative_path, is_dir, case)
+ } else {
+ true
+ }
+ }
+ None => match_verbatim(mapping, relative_path, is_dir, case),
+ }
+ }
+ }
+
+ if let Some(attrs) = mapping.value.attrs_match.as_mut() {
+ if !attributes(relative_path, Case::Sensitive, is_dir, attrs) {
+ // we have attrs, but it didn't match any
+ return None;
+ }
+ for (actual, expected) in attrs.iter_selected().zip(mapping.value.pattern.attributes.iter()) {
+ if actual.assignment != expected.as_ref() {
+ return None;
+ }
+ }
+ }
+
+ is_match.then_some(Match {
+ pattern: &mapping.value.pattern,
+ sequence_number: mapping.sequence_number,
+ })
+ });
+
+ if res.is_none() && self.all_patterns_are_excluded {
+ static MATCH_ALL_STAND_IN: Pattern = Pattern {
+ path: BString::new(Vec::new()),
+ signature: MagicSignature::empty(),
+ search_mode: SearchMode::ShellGlob,
+ attributes: Vec::new(),
+ prefix_len: 0,
+ nil: true,
+ };
+ Some(Match {
+ pattern: &MATCH_ALL_STAND_IN,
+ sequence_number: patterns_len,
+ })
+ } else {
+ res
+ }
+ }
+}
+
+fn match_verbatim(
+ mapping: &gix_glob::search::pattern::Mapping<Spec>,
+ relative_path: &BStr,
+ is_dir: bool,
+ case: Case,
+) -> bool {
+ let pattern_len = mapping.value.pattern.path.len();
+ let mut relative_path_ends_with_slash_at_pattern_len = false;
+ let match_is_allowed = relative_path.get(pattern_len).map_or_else(
+ || relative_path.len() == pattern_len,
+ |b| {
+ relative_path_ends_with_slash_at_pattern_len = *b == b'/';
+ relative_path_ends_with_slash_at_pattern_len
+ },
+ );
+ let pattern_requirement_is_met = !mapping.pattern.mode.contains(gix_glob::pattern::Mode::MUST_BE_DIR)
+ || (relative_path_ends_with_slash_at_pattern_len || is_dir);
+
+ if match_is_allowed && pattern_requirement_is_met {
+ let dir_or_file = &relative_path[..mapping.value.pattern.path.len()];
+ match case {
+ Case::Sensitive => mapping.value.pattern.path == dir_or_file,
+ Case::Fold => mapping.value.pattern.path.eq_ignore_ascii_case(dir_or_file),
+ }
+ } else {
+ false
+ }
+}
diff --git a/vendor/gix-pathspec/src/search/mod.rs b/vendor/gix-pathspec/src/search/mod.rs
new file mode 100644
index 000000000..a9c87377b
--- /dev/null
+++ b/vendor/gix-pathspec/src/search/mod.rs
@@ -0,0 +1,51 @@
+use bstr::{BStr, ByteSlice};
+
+use crate::{Pattern, Search};
+
+/// Describes a matching pattern within a search for ignored paths.
+#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
+pub struct Match<'a> {
+ /// The matching search specification, which contains the pathspec as well.
+ pub pattern: &'a Pattern,
+ /// The number of the sequence the matching pathspec was in, or the line of pathspec file it was read from if [Search::source] is not `None`.
+ pub sequence_number: usize,
+}
+
+mod init;
+
+impl Match<'_> {
+ /// Return `true` if the pathspec that matched was negative, which excludes this item from the set.
+ pub fn is_excluded(&self) -> bool {
+ self.pattern.is_excluded()
+ }
+}
+
+/// Access
+impl Search {
+ /// Return an iterator over the patterns that participate in the search.
+ pub fn patterns(&self) -> impl Iterator<Item = &Pattern> + '_ {
+ self.patterns.iter().map(|m| &m.value.pattern)
+ }
+
+ /// Return the portion of the prefix among all of the pathspecs involved in this search, or an empty string if
+ /// there is none. It doesn't have to end at a directory boundary though, nor does it denote a directory.
+ ///
+ /// Note that the common_prefix is always matched case-sensitively, and it is useful to skip large portions of input.
+ /// Further, excluded pathspecs don't participate which makes this common prefix inclusive. To work correclty though,
+ /// one will have to additionally match paths that have the common prefix with that pathspec itself to assure it is
+ /// not excluded.
+ pub fn common_prefix(&self) -> &BStr {
+ self.patterns
+ .iter()
+ .find(|p| !p.value.pattern.is_excluded())
+ .map_or("".into(), |m| m.value.pattern.path[..self.common_prefix_len].as_bstr())
+ }
+}
+
+#[derive(Default, Clone, Debug)]
+pub(crate) struct Spec {
+ pub pattern: Pattern,
+ pub attrs_match: Option<gix_attributes::search::Outcome>,
+}
+
+mod matching;
diff --git a/vendor/gix-pathspec/tests/defaults.rs b/vendor/gix-pathspec/tests/defaults.rs
new file mode 100644
index 000000000..a30cbb7af
--- /dev/null
+++ b/vendor/gix-pathspec/tests/defaults.rs
@@ -0,0 +1,95 @@
+use gix_pathspec::{Defaults, MagicSignature, SearchMode};
+use serial_test::serial;
+
+#[test]
+#[serial]
+fn literal_only_combines_with_icase() -> gix_testtools::Result {
+ {
+ let _env = gix_testtools::Env::new()
+ .set("GIT_LITERAL_PATHSPECS", "true")
+ .set("GIT_ICASE_PATHSPECS", "1")
+ .set("GIT_NOGLOB_PATHSPECS", "yes");
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))?,
+ Defaults {
+ signature: MagicSignature::ICASE,
+ search_mode: SearchMode::Literal,
+ literal: true,
+ }
+ );
+ }
+ {
+ let _env = gix_testtools::Env::new()
+ .set("GIT_LITERAL_PATHSPECS", "true")
+ .set("GIT_ICASE_PATHSPECS", "false")
+ .set("GIT_GLOB_PATHSPECS", "yes");
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))?,
+ Defaults {
+ signature: MagicSignature::default(),
+ search_mode: SearchMode::Literal,
+ literal: true,
+ }
+ );
+ }
+ Ok(())
+}
+#[test]
+#[serial]
+fn nothing_is_set_then_it_is_like_the_default_impl() -> gix_testtools::Result {
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))?,
+ Defaults::default()
+ );
+ Ok(())
+}
+
+#[test]
+#[serial]
+fn glob_and_noglob_cause_error() -> gix_testtools::Result {
+ let _env = gix_testtools::Env::new()
+ .set("GIT_GLOB_PATHSPECS", "1")
+ .set("GIT_NOGLOB_PATHSPECS", "yes");
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))
+ .unwrap_err()
+ .to_string(),
+ "Glob and no-glob settings are mutually exclusive"
+ );
+
+ Ok(())
+}
+
+#[test]
+#[serial]
+fn noglob_works() -> gix_testtools::Result {
+ let _env = gix_testtools::Env::new()
+ .set("GIT_GLOB_PATHSPECS", "0")
+ .set("GIT_NOGLOB_PATHSPECS", "true");
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))?,
+ Defaults {
+ signature: MagicSignature::default(),
+ search_mode: SearchMode::Literal,
+ literal: false,
+ },
+ "it's OK to set only one of them, and only no-glob has an interesting, non-default effect"
+ );
+ Ok(())
+}
+
+#[test]
+#[serial]
+fn glob_works() -> gix_testtools::Result {
+ let _env = gix_testtools::Env::new().set("GIT_GLOB_PATHSPECS", "yes");
+ assert_eq!(
+ Defaults::from_environment(&mut |n| std::env::var_os(n))?,
+ Defaults {
+ signature: MagicSignature::default(),
+ search_mode: SearchMode::PathAwareGlob,
+ literal: false,
+ },
+ "docs here are strange but they mean to use pathaware globbing when this variable is set"
+ );
+ Ok(())
+}
diff --git a/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline.tar.xz b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline.tar.xz
new file mode 100644
index 000000000..2121b5579
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline.tar.xz
Binary files differ
diff --git a/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_dirs.tar.xz b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_dirs.tar.xz
new file mode 100644
index 000000000..158b91b11
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_dirs.tar.xz
Binary files differ
diff --git a/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_files.tar.xz b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_files.tar.xz
new file mode 100644
index 000000000..3cd83f3fc
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/generated-archives/match_baseline_files.tar.xz
Binary files differ
diff --git a/vendor/gix-pathspec/tests/fixtures/generated-archives/parse_baseline.tar.xz b/vendor/gix-pathspec/tests/fixtures/generated-archives/parse_baseline.tar.xz
new file mode 100644
index 000000000..1b2ffb32c
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/generated-archives/parse_baseline.tar.xz
Binary files differ
diff --git a/vendor/gix-pathspec/tests/fixtures/match_baseline_dirs.sh b/vendor/gix-pathspec/tests/fixtures/match_baseline_dirs.sh
new file mode 100644
index 000000000..37af54e36
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/match_baseline_dirs.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+set -eu -o pipefail
+
+git init;
+git init sub
+(cd sub
+ : >empty
+ git add empty
+ git commit -m init-for-submodule
+)
+
+git init parent
+(cd parent
+ function baseline() {
+ local args=""
+ local specs=""
+
+ for arg in "$@"; do
+ if [[ $arg == *"+"* ]]; then
+ echo "BUG: Argument '$arg' contains a space - we use that for separating pathspecs right now" >&2
+ exit 1
+ fi
+ args="$args -c submodule.active=$arg"
+ specs="${specs}+${arg}"
+ done
+
+ {
+ echo "$specs"
+ git $args submodule
+ echo -n ';'
+ } >> baseline.git
+ }
+
+ cat <<EOF >.gitattributes
+bb bb-file
+bb/ bb-dir
+/bb/ bb-dir-from-top
+EOF
+
+ for p in a bb dir/b dir/bb dir/nested/c cc; do
+ git submodule add ../sub $p
+ git config --unset submodule.$p.active
+ done
+ git commit -m "init"
+
+ git submodule > paths
+
+ baseline ':'
+ baseline ':!'
+ baseline 'a'
+ baseline ':(attr:bb-file)'
+ # :(attr:bb-dir) - ["bb", "dir/bb"] == []
+ baseline ':(attr:bb-dir)' git-inconsistency # bb/ matches recursively, git doesn't get it
+ # :(attr:bb-dir-from-top) - ["bb"] == []
+ baseline ':(attr:bb-dir-from-top)' git-inconsistency # probably git doesn't really care about correctness here
+ baseline ':(icase)A'
+ baseline ':(icase,exclude)A'
+ baseline ':(icase,exclude)*/B*'
+ baseline ':(icase,exclude)*/B?'
+ baseline 'di'
+ baseline 'di?'
+ baseline 'di?/'
+ baseline 'dir*'
+ baseline 'dir/*'
+ baseline ':(glob)dir*'
+ baseline ':(glob,icase,exclude)dir*'
+ baseline ':(glob)dir/*'
+ baseline 'dir'
+ baseline 'dir/'
+ baseline ':(literal)dir'
+ baseline ':(literal)dir/'
+ baseline 'dir/nested'
+ baseline 'dir/nested/'
+ baseline ':(exclude)dir/'
+ baseline ':(icase)DIR'
+ baseline ':(icase)DIR/'
+ baseline ':!a'
+ baseline ':' ':!bb'
+ baseline ':!bb'
+ baseline 'a/'
+ baseline 'bb'
+ baseline 'dir/b'
+ baseline 'dir/b/'
+ # ["dir/b"] == []
+ baseline '*/b/' git-inconsistency
+ baseline '*b'
+ baseline '*b*'
+ baseline '*b?'
+ baseline '*/b'
+ baseline '*/b?'
+ baseline '*/b*'
+ baseline '*c'
+ baseline '*/c'
+ baseline ':(glob)**/c'
+ baseline ':(glob)**/c?'
+ baseline ':(glob)**/c*'
+)
diff --git a/vendor/gix-pathspec/tests/fixtures/match_baseline_files.sh b/vendor/gix-pathspec/tests/fixtures/match_baseline_files.sh
new file mode 100644
index 000000000..b8422ca11
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/match_baseline_files.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+set -eu -o pipefail
+
+git init;
+
+function baseline() {
+ local specs=""
+ for arg in "$@"; do
+ if [[ $arg == *"+"* ]]; then
+ echo "BUG: Argument '$arg' contains a space - we use that for separating pathspecs right now" >&2
+ exit 1
+ fi
+ specs="${specs}+${arg}"
+ done
+
+ {
+ echo "$specs"
+ git ls-files "$@"
+ echo -n ';'
+ } >> baseline.git
+}
+
+: >goo
+: >'g[o][o]'
+: >bar
+echo 'goo a !b c=v -d' > .gitattributes
+mkdir sub && :>sub/bar
+git add . && git commit -m init
+# this is to avoid issues on windows, which might not be able to manifest these files.
+git -c core.protectNTFS=false update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:goo)" "g*"
+git update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:goo)" "!a"
+for p in bar bAr BAR foo/bar foo/bAr foo/BAR fOo/bar fOo/bAr fOo/BAR FOO/bar FOO/bAr FOO/BAR; do
+ git -c core.ignoreCase=false update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:goo)" "$p"
+done
+git -c core.ignoreCase=false update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:goo)" " " # 4 x space
+git -c core.ignoreCase=false update-index --add --cacheinfo 100644 "$(git rev-parse HEAD:goo)" " hi " # 2 x space hi 2 x space
+
+git ls-files > paths
+
+baseline ':(attr:a)goo'
+baseline ':(attr:a)Goo'
+baseline ':(icase,attr:a)Goo'
+baseline ':(attr:!b)goo'
+baseline ':(attr:c=v)goo'
+baseline ':(attr:-d)goo'
+baseline ':(attr:a !b c=v -d)goo'
+baseline ':(icase,attr:a !b c=v -d)GOO'
+baseline ':(attr:a !b c=v -d)g*'
+baseline ':(attr:none)goo'
+baseline ':(literal)g*'
+baseline 'sub/'
+baseline 'sub'
+baseline 'sub/*'
+baseline 'sub*'
+baseline ':(literal)g*'
+baseline ':(glob)g*'
+baseline ':(exclude,literal)g*'
+baseline 'g*'
+baseline ':(exclude)g*'
+baseline ':(literal)?*'
+baseline ':(exclude,literal)?*'
+baseline '?*'
+baseline ':(exclude)?*'
+baseline 'g[o][o]'
+# ["g[o][o]", "goo"] == ["g[o][o]"]
+baseline ':(icase)G[O][o]' git-inconsistency
+baseline ':(literal)g[o][o]'
+baseline ':(literal,icase)G[o][O]'
+baseline ':(glob)g[o][o]'
+# ["g[o][o]", "goo"] == ["g[o][o]"]
+baseline ':(glob,icase)g[o][O]' git-inconsistency
+baseline ':(glob)**/bar'
+baseline ':(literal)**/bar'
+baseline '**/bar'
+baseline '*/bar'
+baseline ':(glob)*bar'
+baseline ':(glob)**bar'
+baseline '*bar'
+baseline '*bar*'
+baseline 'bar'
+baseline 'bar/'
+baseline 'sub/bar/'
+baseline 'sub/bar'
+baseline '!a'
+baseline '?a'
+baseline 'foo/'
+baseline 'foo'
+baseline 'foo/*'
+baseline 'foo*'
+baseline ':(icase)foo/'
+baseline ':(icase)foo'
+baseline ':(icase)foo/*'
+baseline ':(icase)foo*'
+baseline ':(icase)foo/bar'
diff --git a/vendor/gix-pathspec/tests/fixtures/parse_baseline.sh b/vendor/gix-pathspec/tests/fixtures/parse_baseline.sh
new file mode 100755
index 000000000..56525e9eb
--- /dev/null
+++ b/vendor/gix-pathspec/tests/fixtures/parse_baseline.sh
@@ -0,0 +1,158 @@
+#!/bin/bash
+set -eu -o pipefail
+
+git init;
+
+function baseline() {
+ local pathspec=$1 # first argument is the pathspec to test
+
+ git ls-files "$pathspec" && status=0 || status=$?
+ {
+ echo "$pathspec"
+ echo "$status"
+ } >> baseline.git
+}
+
+# success
+
+# special 'there is no pathspec' spec
+baseline ':'
+
+# repeated_matcher_keywords
+baseline ':(glob,glob)'
+baseline ':(literal,literal)'
+baseline ':(top,top)'
+baseline ':(icase,icase)'
+baseline ':(attr,attr)'
+baseline ':!^(exclude,exclude)'
+
+# empty_signatures
+baseline '.'
+baseline ':'
+baseline 'some/path'
+baseline ':some/path'
+baseline ':()some/path'
+baseline '::some/path'
+baseline ':::some/path'
+baseline ':():some/path'
+
+# whitespace_in_pathspec
+baseline ' some/path'
+baseline 'some/ path'
+baseline 'some/path '
+baseline ': some/path'
+baseline ': !some/path'
+baseline ': :some/path'
+baseline ': ()some/path'
+baseline ':! some/path'
+
+# short_signatures
+baseline ':/some/path'
+baseline '://some/path'
+baseline ':^some/path'
+baseline ':^^some/path'
+baseline ':!some/path'
+baseline ':!!some/path'
+baseline ':/!some/path'
+baseline ':!/^/:some/path'
+
+# signatures_and_searchmodes
+baseline ':(top)'
+baseline ':(icase)'
+baseline ':(attr)'
+baseline ':(exclude)'
+baseline ':(literal)'
+baseline ':(glob)'
+baseline ':(top,exclude)'
+baseline ':(icase,literal)'
+baseline ':!(literal)some/*path'
+baseline ':(top,literal,icase,attr,exclude)some/path'
+baseline ':(top,glob,icase,attr,exclude)some/path'
+
+# attributes_in_signature
+baseline ':(attr:someAttr)'
+baseline ':(attr:!someAttr)'
+baseline ':(attr:-someAttr)'
+baseline ':(attr:someAttr=value)'
+baseline ':(attr:a=one b=)'
+baseline ':(attr:a= b=two)'
+baseline ':(attr:a=one b=two)'
+baseline ':(attr:a=one b=two)'
+baseline ':(attr:someAttr anotherAttr)'
+
+# attributes_with_escape_chars_in_state_values
+baseline ':(attr:v=one\-)'
+baseline ':(attr:v=one\_)'
+baseline ':(attr:v=one\,)'
+baseline ':(attr:v=one\,two\,three)'
+baseline ':(attr:a=\d b= c=\d)'
+
+# failing
+
+#empty_input
+baseline ""
+
+# invalid_short_signatures
+baseline ':"()'
+baseline ':#()'
+baseline ':%()'
+baseline ':&()'
+baseline ":'()"
+baseline ':,()'
+baseline ':-()'
+baseline ':;()'
+baseline ':<()'
+baseline ':=()'
+baseline ':>()'
+baseline ':@()'
+baseline ':_()'
+baseline ':`()'
+baseline ':~()'
+
+# invalid_keywords
+baseline ':( )some/path'
+baseline ':(tp)some/path'
+baseline ':(top, exclude)some/path'
+baseline ':(top,exclude,icse)some/path'
+
+# invalid_attributes
+baseline ':(attr:+invalidAttr)some/path'
+baseline ':(attr:validAttr +invalidAttr)some/path'
+baseline ':(attr:+invalidAttr,attr:valid)some/path'
+baseline ':(attr:inva\lid)some/path'
+
+# invalid_attribute_values
+baseline ':(attr:v=inva#lid)some/path'
+baseline ':(attr:v=inva\\lid)some/path'
+baseline ':(attr:v=invalid\\)some/path'
+baseline ':(attr:v=invalid\#)some/path'
+baseline ':(attr:v=inva\=lid)some/path'
+baseline ':(attr:a=valid b=inva\#lid)some/path'
+baseline ':(attr:v=val��)'
+baseline ':(attr:pr=pre��x:,)�'
+
+# escape_character_at_end_of_attribute_value
+baseline ':(attr:v=invalid\)some/path'
+baseline ':(attr:v=invalid\ )some/path'
+baseline ':(attr:v=invalid\ valid)some/path'
+
+# empty_attribute_specification
+baseline ':(attr:)'
+
+# multiple_attribute_specifications
+baseline ':(attr:one,attr:two)some/path'
+
+# missing_parentheses
+baseline ':(top'
+
+# glob_and_literal_keywords_present
+baseline ':(glob,literal)some/path'
+# trailing slash
+baseline ':(glob,literal)some/path/'
+baseline 'some/path/'
+baseline 'path/'
+
+baseline 'a/b/'
+baseline 'a/'
+baseline '!a'
+baseline '\!a'
diff --git a/vendor/gix-pathspec/tests/normalize/mod.rs b/vendor/gix-pathspec/tests/normalize/mod.rs
new file mode 100644
index 000000000..2fe54f664
--- /dev/null
+++ b/vendor/gix-pathspec/tests/normalize/mod.rs
@@ -0,0 +1,116 @@
+use std::path::Path;
+
+#[test]
+fn removes_relative_path_components() -> crate::Result {
+ for (input_path, expected_path, expected_prefix) in [
+ ("c", "a/b/c", "a/b"),
+ ("../c", "a/c", "a"),
+ ("../b/c", "a/b/c", "a"), // this is a feature - prefix components once consumed by .. are lost. Important as paths can contain globs
+ ("../*c/d", "a/*c/d", "a"),
+ ("../../c/d", "c/d", ""),
+ ("../../c/d/", "c/d", ""),
+ ("./c", "a/b/c", "a/b"),
+ ("../../c", "c", ""),
+ ("../..", ".", ""),
+ ("../././c", "a/c", "a"),
+ ("././/./c", "a/b/c", "a/b"),
+ ("././/./c/", "a/b/c", "a/b"),
+ ("././/./../c/d/", "a/c/d", "a"),
+ ] {
+ let spec = normalized_spec(input_path, "a/b", "")?;
+ assert_eq!(spec.path(), expected_path);
+ assert_eq!(
+ spec.prefix_directory(),
+ expected_prefix,
+ "{input_path} -> {expected_path}"
+ );
+ }
+ Ok(())
+}
+
+#[test]
+fn single_dot_is_special_and_directory_is_implied_without_trailing_slash() -> crate::Result {
+ for (input_path, expected) in [(".", "."), ("./", ".")] {
+ let spec = normalized_spec(input_path, "", "/repo")?;
+ assert_eq!(spec.path(), expected);
+ assert_eq!(spec.prefix_directory(), "");
+ }
+ Ok(())
+}
+
+#[test]
+fn absolute_path_made_relative() -> crate::Result {
+ for (input_path, expected, prefix_dir) in [
+ ("/repo/a", "a", ""),
+ ("/repo/a/..//.///b", "b", ""),
+ ("/repo/a/", "a", "a"),
+ ("/repo/*/", "*", "*"),
+ ("/repo/a/b", "a/b", "a"),
+ ("/repo/*/b", "*/b", "*"), // we assume literal paths if specs are absolute
+ ("/repo/a/*/", "a/*", "a/*"),
+ ("/repo/a/b/", "a/b", "a/b"),
+ ("/repo/a/b/*", "a/b/*", "a/b"),
+ ("/repo/a/b/c/..", "a/b", "a"),
+ ] {
+ let spec = normalized_spec(input_path, "", "/repo")?;
+ assert_eq!(spec.path(), expected);
+ assert_eq!(spec.prefix_directory(), prefix_dir, "{input_path}");
+ }
+ Ok(())
+}
+
+#[test]
+fn relative_top_patterns_ignore_the_prefix() -> crate::Result {
+ let spec = normalized_spec(":(top)c", "a/b", "")?;
+ assert_eq!(spec.path(), "c");
+ assert_eq!(spec.prefix_directory(), "");
+ Ok(())
+}
+
+#[test]
+fn absolute_top_patterns_ignore_the_prefix_but_are_made_relative() -> crate::Result {
+ let spec = normalized_spec(":(top)/a/b", "prefix-ignored", "/a")?;
+ assert_eq!(spec.path(), "b");
+ assert_eq!(spec.prefix_directory(), "");
+ Ok(())
+}
+
+#[test]
+fn relative_path_breaks_out_of_working_tree() {
+ let err = normalized_spec("../a", "", "").unwrap_err();
+ assert_eq!(err.to_string(), "The path '../a' leaves the repository");
+ let err = normalized_spec("../../b", "a", "").unwrap_err();
+ assert_eq!(
+ err.to_string(),
+ format!(
+ "The path '{}' leaves the repository",
+ if cfg!(windows) { "a\\../../b" } else { "a/../../b" }
+ )
+ );
+}
+
+#[test]
+fn absolute_path_breaks_out_of_working_tree() {
+ let err = normalized_spec("/path/to/repo/..///./a", "", "/path/to/repo").unwrap_err();
+ assert_eq!(err.to_string(), "The path '..///./a' leaves the repository");
+ let err = normalized_spec("/path/to/repo/../../../dev", "", "/path/to/repo").unwrap_err();
+ assert_eq!(err.to_string(), "The path '../../../dev' leaves the repository");
+}
+
+#[test]
+fn absolute_path_escapes_worktree() {
+ assert_eq!(
+ normalized_spec("/dev", "", "/path/to/repo").unwrap_err().to_string(),
+ "The path '/dev' is not inside of the worktree '/path/to/repo'"
+ );
+}
+
+fn normalized_spec(
+ path: &str,
+ prefix: &str,
+ root: &str,
+) -> Result<gix_pathspec::Pattern, gix_pathspec::normalize::Error> {
+ let mut spec = gix_pathspec::parse(path.as_bytes(), Default::default()).expect("valid");
+ spec.normalize(Path::new(prefix), Path::new(root))?;
+ Ok(spec)
+}
diff --git a/vendor/gix-pathspec/tests/parse/invalid.rs b/vendor/gix-pathspec/tests/parse/invalid.rs
new file mode 100644
index 000000000..d080f4afc
--- /dev/null
+++ b/vendor/gix-pathspec/tests/parse/invalid.rs
@@ -0,0 +1,152 @@
+use gix_pathspec::parse::Error;
+
+use crate::parse::check_against_baseline;
+
+#[test]
+fn empty_input() {
+ let input = "";
+
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::EmptyString));
+}
+
+#[test]
+fn invalid_short_signatures() {
+ let inputs = vec![
+ ":\"()", ":#()", ":%()", ":&()", ":'()", ":,()", ":-()", ":;()", ":<()", ":=()", ":>()", ":@()", ":_()",
+ ":`()", ":~()",
+ ];
+
+ for input in inputs.into_iter() {
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::Unimplemented { .. }));
+ }
+}
+
+#[test]
+fn invalid_keywords() {
+ let inputs = vec![
+ ":( )some/path",
+ ":(tp)some/path",
+ ":(top, exclude)some/path",
+ ":(top,exclude,icse)some/path",
+ ];
+
+ for input in inputs.into_iter() {
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::InvalidKeyword { .. }));
+ }
+}
+
+#[test]
+fn invalid_attributes() {
+ let inputs = vec![
+ ":(attr:+invalidAttr)some/path",
+ ":(attr:validAttr +invalidAttr)some/path",
+ ":(attr:+invalidAttr,attr:valid)some/path",
+ r":(attr:inva\lid)some/path",
+ ];
+
+ for input in inputs {
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err(), "This pathspec did not produce an error {input}");
+ assert!(matches!(output.unwrap_err(), Error::InvalidAttribute { .. }));
+ }
+}
+
+#[test]
+fn invalid_attribute_values() {
+ let inputs = vec![
+ r":(attr:v=inva#lid)some/path",
+ r":(attr:v=inva\\lid)some/path",
+ r":(attr:v=invalid\\)some/path",
+ r":(attr:v=invalid\#)some/path",
+ r":(attr:v=inva\=lid)some/path",
+ r":(attr:a=valid b=inva\#lid)some/path",
+ ":(attr:v=val��)",
+ ":(attr:pr=pre��x:,)�",
+ ];
+
+ for input in inputs {
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err(), "This pathspec did not produce an error {input}");
+ assert!(
+ matches!(output.unwrap_err(), Error::InvalidAttributeValue { .. }),
+ "Errors did not match for pathspec: {input}"
+ );
+ }
+}
+
+#[test]
+fn escape_character_at_end_of_attribute_value() {
+ let inputs = vec![
+ r":(attr:v=invalid\)some/path",
+ r":(attr:v=invalid\ )some/path",
+ r":(attr:v=invalid\ valid)some/path",
+ ];
+
+ for input in inputs {
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err(), "This pathspec did not produce an error {input}");
+ assert!(matches!(output.unwrap_err(), Error::TrailingEscapeCharacter));
+ }
+}
+
+#[test]
+fn empty_attribute_specification() {
+ let input = ":(attr:)";
+
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::EmptyAttribute));
+}
+
+#[test]
+fn multiple_attribute_specifications() {
+ let input = ":(attr:one,attr:two)some/path";
+
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::MultipleAttributeSpecifications));
+}
+
+#[test]
+fn missing_parentheses() {
+ let input = ":(top";
+
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::MissingClosingParenthesis { .. }));
+}
+
+#[test]
+fn glob_and_literal_keywords_present() {
+ let input = ":(glob,literal)some/path";
+
+ assert!(!check_against_baseline(input), "This pathspec is valid in git: {input}");
+
+ let output = gix_pathspec::parse(input.as_bytes(), Default::default());
+ assert!(output.is_err());
+ assert!(matches!(output.unwrap_err(), Error::IncompatibleSearchModes));
+}
diff --git a/vendor/gix-pathspec/tests/parse/mod.rs b/vendor/gix-pathspec/tests/parse/mod.rs
new file mode 100644
index 000000000..6ee363d6b
--- /dev/null
+++ b/vendor/gix-pathspec/tests/parse/mod.rs
@@ -0,0 +1,93 @@
+use std::collections::HashMap;
+
+use bstr::{BStr, BString, ByteSlice};
+use gix_attributes::State;
+use gix_pathspec::{MagicSignature, Pattern, SearchMode};
+use once_cell::sync::Lazy;
+
+#[test]
+fn baseline() {
+ for (pattern, exit_code) in BASELINE.iter() {
+ let res = gix_pathspec::parse(pattern, Default::default());
+ assert_eq!(
+ res.is_ok(),
+ *exit_code == 0,
+ "{pattern:?} disagrees with baseline: {res:?}"
+ );
+ if let Ok(pat) = res {
+ let actual = pat.to_bstring();
+ assert_eq!(
+ pat,
+ gix_pathspec::parse(actual.as_ref(), Default::default()).expect("still valid"),
+ "{pattern} != {actual}: display must roundtrip into actual pattern"
+ );
+ }
+ let p = gix_pathspec::Pattern::from_literal(pattern, Default::default());
+ assert!(matches!(p.search_mode, SearchMode::Literal));
+ }
+}
+
+mod invalid;
+mod valid;
+
+/// A way to specify expectations more easily by simplifying assignments.
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct NormalizedPattern {
+ path: BString,
+ signature: MagicSignature,
+ search_mode: SearchMode,
+ attributes: Vec<(BString, State)>,
+}
+
+impl From<Pattern> for NormalizedPattern {
+ fn from(p: Pattern) -> Self {
+ NormalizedPattern {
+ path: p.path().to_owned(),
+ signature: p.signature,
+ search_mode: p.search_mode,
+ attributes: p
+ .attributes
+ .into_iter()
+ .map(|attr| (attr.name.as_str().into(), attr.state))
+ .collect(),
+ }
+ }
+}
+
+static BASELINE: Lazy<HashMap<BString, usize>> = Lazy::new(|| {
+ let base = gix_testtools::scripted_fixture_read_only("parse_baseline.sh").unwrap();
+
+ (|| -> crate::Result<_> {
+ let mut map = HashMap::new();
+ let baseline = std::fs::read(base.join("baseline.git"))?;
+ let mut lines = baseline.lines();
+ while let Some(spec) = lines.next() {
+ let exit_code = lines.next().expect("two lines per baseline").to_str()?.parse()?;
+ map.insert(spec.into(), exit_code);
+ }
+ Ok(map)
+ })()
+ .unwrap()
+});
+
+fn check_valid_inputs<'a>(inputs: impl IntoIterator<Item = (&'a str, NormalizedPattern)>) {
+ for (input, expected) in inputs.into_iter() {
+ assert!(
+ check_against_baseline(input),
+ "This pathspec is invalid in git: {input}"
+ );
+
+ let pattern = gix_pathspec::parse(input.as_bytes(), Default::default())
+ .unwrap_or_else(|_| panic!("parsing should not fail with pathspec {input}"));
+ let pattern: NormalizedPattern = pattern.into();
+ assert_eq!(pattern, expected, "while checking input: \"{input}\"");
+ }
+}
+
+fn check_against_baseline(pathspec: &str) -> bool {
+ let key: &BStr = pathspec.into();
+ let base = BASELINE
+ .get(key)
+ .unwrap_or_else(|| panic!("missing baseline for pathspec: {pathspec:?}"));
+ *base == 0
+}
diff --git a/vendor/gix-pathspec/tests/parse/valid.rs b/vendor/gix-pathspec/tests/parse/valid.rs
new file mode 100644
index 000000000..ce0b05d88
--- /dev/null
+++ b/vendor/gix-pathspec/tests/parse/valid.rs
@@ -0,0 +1,359 @@
+use gix_attributes::State;
+use gix_pathspec::{MagicSignature, SearchMode};
+
+use crate::parse::{check_against_baseline, check_valid_inputs, NormalizedPattern};
+
+#[test]
+fn repeated_matcher_keywords() {
+ let input = vec![
+ (":(glob,glob)", pat_with_search_mode(SearchMode::PathAwareGlob)),
+ (":(literal,literal)", pat_with_search_mode(SearchMode::Literal)),
+ (":(top,top)", pat_with_sig(MagicSignature::TOP)),
+ (":(icase,icase)", pat_with_sig(MagicSignature::ICASE)),
+ (":(attr,attr)", pat_with_attrs(vec![])),
+ (":!^(exclude,exclude)", pat_with_sig(MagicSignature::EXCLUDE)),
+ ];
+
+ check_valid_inputs(input);
+}
+
+#[test]
+fn glob_negations_are_always_literal() {
+ check_valid_inputs([("!a", pat_with_path("!a")), ("\\!a", pat_with_path("\\!a"))]);
+}
+
+#[test]
+fn literal_default_prevents_parsing() {
+ let pattern = gix_pathspec::parse(
+ ":".as_bytes(),
+ gix_pathspec::Defaults {
+ signature: MagicSignature::EXCLUDE,
+ search_mode: SearchMode::PathAwareGlob,
+ literal: true,
+ },
+ )
+ .expect("valid");
+ assert!(!pattern.is_nil());
+ assert_eq!(pattern.path(), ":");
+ assert!(matches!(pattern.search_mode, SearchMode::Literal));
+
+ let input = ":(literal)f[o][o]";
+ let pattern = gix_pathspec::parse(
+ input.as_bytes(),
+ gix_pathspec::Defaults {
+ signature: MagicSignature::TOP,
+ search_mode: SearchMode::Literal,
+ literal: true,
+ },
+ )
+ .expect("valid");
+ assert_eq!(pattern.path(), input, "no parsing happens at all");
+ assert!(matches!(pattern.search_mode, SearchMode::Literal));
+
+ let pattern = gix_pathspec::parse(
+ input.as_bytes(),
+ gix_pathspec::Defaults {
+ signature: MagicSignature::TOP,
+ search_mode: SearchMode::Literal,
+ literal: false,
+ },
+ )
+ .expect("valid");
+ assert_eq!(pattern.path(), "f[o][o]", "in literal default mode, we still parse");
+ assert!(matches!(pattern.search_mode, SearchMode::Literal));
+}
+
+#[test]
+fn there_is_no_pathspec_pathspec() {
+ check_against_baseline(":");
+ let pattern = gix_pathspec::parse(":".as_bytes(), Default::default()).expect("valid");
+ assert!(pattern.is_nil());
+
+ let actual: NormalizedPattern = pattern.into();
+ assert_eq!(actual, pat_with_path(""));
+
+ let pattern = gix_pathspec::parse(
+ ":".as_bytes(),
+ gix_pathspec::Defaults {
+ signature: MagicSignature::EXCLUDE,
+ search_mode: SearchMode::PathAwareGlob,
+ literal: false,
+ },
+ )
+ .expect("valid");
+ assert!(pattern.is_nil());
+}
+
+#[test]
+fn defaults_are_used() -> crate::Result {
+ let defaults = gix_pathspec::Defaults {
+ signature: MagicSignature::EXCLUDE,
+ search_mode: SearchMode::Literal,
+ literal: false,
+ };
+ let p = gix_pathspec::parse(".".as_bytes(), defaults)?;
+ assert_eq!(p.path(), ".");
+ assert_eq!(p.signature, defaults.signature);
+ assert_eq!(p.search_mode, defaults.search_mode);
+ assert!(p.attributes.is_empty());
+ assert!(!p.is_nil());
+ Ok(())
+}
+
+#[test]
+fn literal_from_defaults_is_overridden_by_element_glob() -> crate::Result {
+ let defaults = gix_pathspec::Defaults {
+ search_mode: SearchMode::Literal,
+ ..Default::default()
+ };
+ let p = gix_pathspec::parse(":(glob)*override".as_bytes(), defaults)?;
+ assert_eq!(p.path(), "*override");
+ assert_eq!(p.signature, MagicSignature::default());
+ assert_eq!(p.search_mode, SearchMode::PathAwareGlob, "this is the element override");
+ assert!(p.attributes.is_empty());
+ assert!(!p.is_nil());
+ Ok(())
+}
+
+#[test]
+fn glob_from_defaults_is_overridden_by_element_glob() -> crate::Result {
+ let defaults = gix_pathspec::Defaults {
+ search_mode: SearchMode::PathAwareGlob,
+ ..Default::default()
+ };
+ let p = gix_pathspec::parse(":(literal)*override".as_bytes(), defaults)?;
+ assert_eq!(p.path(), "*override");
+ assert_eq!(p.signature, MagicSignature::default());
+ assert_eq!(p.search_mode, SearchMode::Literal, "this is the element override");
+ assert!(p.attributes.is_empty());
+ assert!(!p.is_nil());
+ Ok(())
+}
+
+#[test]
+fn empty_signatures() {
+ let inputs = vec![
+ (".", pat_with_path(".")),
+ ("some/path", pat_with_path("some/path")),
+ (":some/path", pat_with_path("some/path")),
+ (":()some/path", pat_with_path("some/path")),
+ ("::some/path", pat_with_path("some/path")),
+ (":::some/path", pat_with_path(":some/path")),
+ (":():some/path", pat_with_path(":some/path")),
+ ];
+
+ check_valid_inputs(inputs)
+}
+
+#[test]
+fn whitespace_in_pathspec() {
+ let inputs = vec![
+ (" some/path", pat_with_path(" some/path")),
+ ("some/ path", pat_with_path("some/ path")),
+ ("some/path ", pat_with_path("some/path ")),
+ (": some/path", pat_with_path(" some/path")),
+ (": !some/path", pat_with_path(" !some/path")),
+ (": :some/path", pat_with_path(" :some/path")),
+ (": ()some/path", pat_with_path(" ()some/path")),
+ (
+ ":! some/path",
+ pat_with_path_and_sig(" some/path", MagicSignature::EXCLUDE),
+ ),
+ (
+ ":!!some/path",
+ pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),
+ ),
+ ];
+
+ check_valid_inputs(inputs)
+}
+
+#[test]
+fn short_signatures() {
+ let inputs = vec![
+ (":/some/path", pat_with_path_and_sig("some/path", MagicSignature::TOP)),
+ (
+ ":^some/path",
+ pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),
+ ),
+ (
+ ":!some/path",
+ pat_with_path_and_sig("some/path", MagicSignature::EXCLUDE),
+ ),
+ (
+ ":/!some/path",
+ pat_with_path_and_sig("some/path", MagicSignature::TOP | MagicSignature::EXCLUDE),
+ ),
+ (
+ ":!/^/:some/path",
+ pat_with_path_and_sig("some/path", MagicSignature::TOP | MagicSignature::EXCLUDE),
+ ),
+ ];
+
+ check_valid_inputs(inputs)
+}
+
+#[test]
+fn trailing_slash_is_turned_into_magic_signature_and_removed() {
+ check_valid_inputs([
+ ("a/b/", pat_with_path_and_sig("a/b", MagicSignature::MUST_BE_DIR)),
+ ("a/", pat_with_path_and_sig("a", MagicSignature::MUST_BE_DIR)),
+ ]);
+}
+
+#[test]
+fn signatures_and_searchmodes() {
+ let inputs = vec![
+ (":(top)", pat_with_sig(MagicSignature::TOP)),
+ (":(icase)", pat_with_sig(MagicSignature::ICASE)),
+ (":(attr)", pat_with_path("")),
+ (":(exclude)", pat_with_sig(MagicSignature::EXCLUDE)),
+ (":(literal)", pat_with_search_mode(SearchMode::Literal)),
+ (":(glob)", pat_with_search_mode(SearchMode::PathAwareGlob)),
+ (
+ ":(top,exclude)",
+ pat_with_sig(MagicSignature::TOP | MagicSignature::EXCLUDE),
+ ),
+ (
+ ":(icase,literal)",
+ pat("", MagicSignature::ICASE, SearchMode::Literal, vec![]),
+ ),
+ (
+ ":!(literal)some/*path",
+ pat("some/*path", MagicSignature::EXCLUDE, SearchMode::Literal, vec![]),
+ ),
+ (
+ ":(top,literal,icase,attr,exclude)some/path",
+ pat(
+ "some/path",
+ MagicSignature::TOP | MagicSignature::EXCLUDE | MagicSignature::ICASE,
+ SearchMode::Literal,
+ vec![],
+ ),
+ ),
+ (
+ ":(top,glob,icase,attr,exclude)some/path",
+ pat(
+ "some/path",
+ MagicSignature::TOP | MagicSignature::EXCLUDE | MagicSignature::ICASE,
+ SearchMode::PathAwareGlob,
+ vec![],
+ ),
+ ),
+ ];
+
+ check_valid_inputs(inputs);
+}
+
+#[test]
+fn attributes_in_signature() {
+ let inputs = vec![
+ (":(attr:someAttr)", pat_with_attrs(vec![("someAttr", State::Set)])),
+ (
+ ":(attr:!someAttr)",
+ pat_with_attrs(vec![("someAttr", State::Unspecified)]),
+ ),
+ (":(attr:-someAttr)", pat_with_attrs(vec![("someAttr", State::Unset)])),
+ (
+ ":(attr:someAttr=value)",
+ pat_with_attrs(vec![("someAttr", State::Value("value".into()))]),
+ ),
+ (
+ ":(attr:a=one b=)",
+ pat_with_attrs(vec![("a", State::Value("one".into())), ("b", State::Value("".into()))]),
+ ),
+ (
+ ":(attr:a= b=two)",
+ pat_with_attrs(vec![("a", State::Value("".into())), ("b", State::Value("two".into()))]),
+ ),
+ (
+ ":(attr:a=one b=two)",
+ pat_with_attrs(vec![
+ ("a", State::Value("one".into())),
+ ("b", State::Value("two".into())),
+ ]),
+ ),
+ (
+ ":(attr:a=one b=two)",
+ pat_with_attrs(vec![
+ ("a", State::Value("one".into())),
+ ("b", State::Value("two".into())),
+ ]),
+ ),
+ (
+ ":(attr:someAttr anotherAttr)",
+ pat_with_attrs(vec![("someAttr", State::Set), ("anotherAttr", State::Set)]),
+ ),
+ ];
+
+ check_valid_inputs(inputs)
+}
+
+#[test]
+fn attributes_with_escape_chars_in_state_values() {
+ let inputs = vec![
+ (
+ r":(attr:v=one\-)",
+ pat_with_attrs(vec![("v", State::Value(r"one-".into()))]),
+ ),
+ (
+ r":(attr:v=one\_)",
+ pat_with_attrs(vec![("v", State::Value(r"one_".into()))]),
+ ),
+ (
+ r":(attr:v=one\,)",
+ pat_with_attrs(vec![("v", State::Value(r"one,".into()))]),
+ ),
+ (
+ r":(attr:v=one\,two\,three)",
+ pat_with_attrs(vec![("v", State::Value(r"one,two,three".into()))]),
+ ),
+ (
+ r":(attr:a=\d b= c=\d)",
+ pat_with_attrs(vec![
+ ("a", State::Value(r"d".into())),
+ ("b", State::Value(r"".into())),
+ ("c", State::Value(r"d".into())),
+ ]),
+ ),
+ ];
+
+ check_valid_inputs(inputs)
+}
+
+fn pat_with_path(path: &str) -> NormalizedPattern {
+ pat_with_path_and_sig(path, MagicSignature::empty())
+}
+
+fn pat_with_path_and_sig(path: &str, signature: MagicSignature) -> NormalizedPattern {
+ pat(path, signature, SearchMode::ShellGlob, vec![])
+}
+
+fn pat_with_sig(signature: MagicSignature) -> NormalizedPattern {
+ pat("", signature, SearchMode::ShellGlob, vec![])
+}
+
+fn pat_with_attrs(attrs: Vec<(&'static str, State)>) -> NormalizedPattern {
+ pat("", MagicSignature::empty(), SearchMode::ShellGlob, attrs)
+}
+
+fn pat_with_search_mode(search_mode: SearchMode) -> NormalizedPattern {
+ pat("", MagicSignature::empty(), search_mode, vec![])
+}
+
+fn pat(
+ path: &str,
+ signature: MagicSignature,
+ search_mode: SearchMode,
+ attributes: Vec<(&str, State)>,
+) -> NormalizedPattern {
+ NormalizedPattern {
+ path: path.into(),
+ signature,
+ search_mode,
+ attributes: attributes
+ .into_iter()
+ .map(|(attr, state)| (attr.into(), state))
+ .collect(),
+ }
+}
diff --git a/vendor/gix-pathspec/tests/pathspec.rs b/vendor/gix-pathspec/tests/pathspec.rs
new file mode 100644
index 000000000..d83fefbcb
--- /dev/null
+++ b/vendor/gix-pathspec/tests/pathspec.rs
@@ -0,0 +1,5 @@
+pub use gix_testtools::Result;
+
+mod normalize;
+mod parse;
+mod search;
diff --git a/vendor/gix-pathspec/tests/search/mod.rs b/vendor/gix-pathspec/tests/search/mod.rs
new file mode 100644
index 000000000..638709c35
--- /dev/null
+++ b/vendor/gix-pathspec/tests/search/mod.rs
@@ -0,0 +1,281 @@
+use std::path::Path;
+
+#[test]
+fn directories() -> crate::Result {
+ baseline::run("directory", true, baseline::directories)
+}
+
+#[test]
+fn no_pathspecs_match_everything() -> crate::Result {
+ let mut search = gix_pathspec::Search::from_specs([], None, Path::new(""))?;
+ assert_eq!(search.patterns().count(), 0, "nothing artificial is added");
+ let m = search
+ .pattern_matching_relative_path("hello".into(), None, &mut |_, _, _, _| {
+ unreachable!("must not be called")
+ })
+ .expect("matches");
+ assert_eq!(m.pattern.prefix_directory(), "", "there is no prefix as none was given");
+
+ Ok(())
+}
+
+#[test]
+fn init_with_exclude() -> crate::Result {
+ let search = gix_pathspec::Search::from_specs(pathspecs(&["tests/", ":!*.sh"]), None, Path::new(""))?;
+ assert_eq!(search.patterns().count(), 2, "nothing artificial is added");
+ assert!(
+ search.patterns().next().expect("first of two").is_excluded(),
+ "re-orded so that excluded are first"
+ );
+ assert_eq!(search.common_prefix(), "tests");
+ Ok(())
+}
+
+#[test]
+fn no_pathspecs_respect_prefix() -> crate::Result {
+ let mut search = gix_pathspec::Search::from_specs([], Some(Path::new("a")), Path::new(""))?;
+ assert_eq!(
+ search.patterns().count(),
+ 1,
+ "we get an artificial pattern to get the prefix"
+ );
+ assert!(
+ search
+ .pattern_matching_relative_path("hello".into(), None, &mut |_, _, _, _| unreachable!(
+ "must not be called"
+ ))
+ .is_none(),
+ "not the right prefix"
+ );
+ let m = search
+ .pattern_matching_relative_path("a/b".into(), None, &mut |_, _, _, _| unreachable!("must not be called"))
+ .expect("match");
+ assert_eq!(
+ m.pattern.prefix_directory(),
+ "a",
+ "the prefix directory matched verbatim"
+ );
+
+ Ok(())
+}
+
+#[test]
+fn prefixes_are_always_case_insensitive() -> crate::Result {
+ let path = gix_testtools::scripted_fixture_read_only("match_baseline_files.sh")?.join("paths");
+ let items = baseline::parse_paths(path)?;
+
+ for (spec, prefix, common_prefix, expected) in [
+ (":(icase)bar", "FOO", "FOO", &["FOO/BAR", "FOO/bAr", "FOO/bar"] as &[_]),
+ (":(icase)bar", "F", "F", &[]),
+ (":(icase)bar", "FO", "FO", &[]),
+ (":(icase)../bar", "fOo", "", &["BAR", "bAr", "bar"]),
+ ("../bar", "fOo", "bar", &["bar"]),
+ (" ", "", " ", &[" "]), // whitespace can match verbatim
+ (" hi*", "", " hi", &[" hi "]), // whitespace can match with globs as well
+ (":(icase)../bar", "fO", "", &["BAR", "bAr", "bar"]), // prefixes are virtual, and don't have to exist at all.
+ (
+ ":(icase)../foo/bar",
+ "FOO",
+ "",
+ &[
+ "FOO/BAR", "FOO/bAr", "FOO/bar", "fOo/BAR", "fOo/bAr", "fOo/bar", "foo/BAR", "foo/bAr", "foo/bar",
+ ],
+ ),
+ ("../foo/bar", "FOO", "foo/bar", &["foo/bar"]),
+ (
+ ":(icase)../foo/../fOo/bar",
+ "FOO",
+ "",
+ &[
+ "FOO/BAR", "FOO/bAr", "FOO/bar", "fOo/BAR", "fOo/bAr", "fOo/bar", "foo/BAR", "foo/bAr", "foo/bar",
+ ],
+ ),
+ ("../foo/../fOo/BAR", "FOO", "fOo/BAR", &["fOo/BAR"]),
+ ] {
+ let mut search = gix_pathspec::Search::from_specs(
+ gix_pathspec::parse(spec.as_bytes(), Default::default()),
+ Some(Path::new(prefix)),
+ Path::new(""),
+ )?;
+ assert_eq!(search.common_prefix(), common_prefix, "{spec} {prefix}");
+ let actual: Vec<_> = items
+ .iter()
+ .filter(|relative_path| {
+ search
+ .pattern_matching_relative_path(relative_path.as_str().into(), Some(false), &mut |_, _, _, _| false)
+ .is_some()
+ })
+ .collect();
+ assert_eq!(actual, expected, "{spec} {prefix}");
+ }
+ Ok(())
+}
+
+#[test]
+fn common_prefix() -> crate::Result {
+ for (specs, prefix, expected) in [
+ (&["foo/bar", ":(icase)foo/bar"] as &[_], None, ""),
+ (&["foo/bar", "foo"], None, "foo"),
+ (&["foo/bar/baz", "foo/bar/"], None, "foo/bar"), // directory trailing slashes are ignored, but that prefix shouldn't care anyway
+ (&[":(icase)bar", ":(icase)bart"], Some("foo"), "foo"), // only case-sensitive portions count
+ (&["bar", "bart"], Some("foo"), "foo/bar"), // otherwise everything that matches counts
+ (&["bar", "bart", "ba"], Some("foo"), "foo/ba"),
+ ] {
+ let search = gix_pathspec::Search::from_specs(
+ specs
+ .iter()
+ .map(|s| gix_pathspec::parse(s.as_bytes(), Default::default()).expect("valid")),
+ prefix.map(Path::new),
+ Path::new(""),
+ )?;
+ assert_eq!(search.common_prefix(), expected, "{specs:?} {prefix:?}");
+ }
+ Ok(())
+}
+
+#[test]
+fn files() -> crate::Result {
+ baseline::run("file", false, baseline::files)
+}
+
+fn pathspecs(input: &[&str]) -> Vec<gix_pathspec::Pattern> {
+ input
+ .iter()
+ .map(|pattern| gix_pathspec::parse(pattern.as_bytes(), Default::default()).expect("known to be valid"))
+ .collect()
+}
+
+mod baseline {
+ use std::path::{Path, PathBuf};
+
+ use bstr::{BString, ByteSlice};
+
+ pub fn run(
+ name: &str,
+ items_are_dirs: bool,
+ init: impl FnOnce() -> crate::Result<(PathBuf, Vec<String>, Vec<Expected>)>,
+ ) -> crate::Result {
+ let (root, items, expected) = init()?;
+ let mut collection = Default::default();
+ let attrs =
+ gix_attributes::Search::new_globals(Some(root.join(".gitattributes")), &mut Vec::new(), &mut collection)?;
+ let tests = expected.len();
+ for expected in expected {
+ let mut search = gix_pathspec::Search::from_specs(expected.pathspecs, None, Path::new(""))?;
+ let actual: Vec<_> = items
+ .iter()
+ .filter(|path| {
+ search
+ .pattern_matching_relative_path(
+ path.as_str().into(),
+ Some(items_are_dirs),
+ &mut |rela_path, case, is_dir, out| {
+ out.initialize(&collection);
+ attrs.pattern_matching_relative_path(rela_path, case, Some(is_dir), out)
+ },
+ )
+ .map_or(false, |m| !m.is_excluded())
+ })
+ .cloned()
+ .collect();
+ let matches_expectation = actual == expected.matches;
+ assert_eq!(
+ matches_expectation,
+ expected.is_consistent,
+ "{} - {actual:?} == {:?}",
+ search.patterns().map(|p| format!("{p}")).collect::<Vec<_>>().join(", "),
+ expected.matches
+ );
+ }
+ eprintln!("{tests} {name} matches OK");
+ Ok(())
+ }
+
+ #[derive(Debug)]
+ pub struct Expected {
+ pub pathspecs: Vec<gix_pathspec::Pattern>,
+ pub matches: Vec<String>,
+ /// If true, this means that the baseline is different from what we get, and that our solution is consistent with the rules.
+ pub is_consistent: bool,
+ }
+
+ pub fn parse_paths(path: PathBuf) -> std::io::Result<Vec<String>> {
+ let buf = std::fs::read(path)?;
+ Ok(buf.lines().map(BString::from).map(|s| s.to_string()).collect())
+ }
+
+ fn parse_blocks(input: &[u8], parse_matches: impl Fn(&[u8]) -> Vec<String>) -> Vec<Expected> {
+ input
+ .split(|b| *b == b';')
+ .filter(|b| !b.is_empty())
+ .map(move |block| {
+ let mut lines = block.lines();
+ let mut is_inconsistent = false;
+ let pathspecs = lines
+ .next()
+ .expect("pathspec")
+ .split(|b| *b == b'+')
+ .filter(|spec| {
+ is_inconsistent = spec.as_bstr() == "git-inconsistency";
+ !is_inconsistent
+ })
+ .filter_map(|s| (!s.trim().is_empty()).then(|| s.trim()))
+ .map(|pathspec| gix_pathspec::parse(pathspec, Default::default()).expect("valid pathspec"))
+ .collect();
+ Expected {
+ pathspecs,
+ matches: parse_matches(lines.as_bytes()),
+ is_consistent: !is_inconsistent,
+ }
+ })
+ .collect()
+ }
+
+ mod submodule {
+ use bstr::ByteSlice;
+
+ pub fn matches_from_status(input: &[u8]) -> impl Iterator<Item = (bool, String)> + '_ {
+ input.lines().map(|line| {
+ let matches = line[0] == b' ';
+ assert_eq!(!matches, line[0] == b'-');
+ let mut tokens = line[1..].split(|b| *b == b' ').skip(1);
+ let path = tokens.next().expect("path").to_str().expect("valid UTF-8");
+ (matches, path.to_owned())
+ })
+ }
+
+ pub fn parse_expected(input: &[u8]) -> Vec<super::Expected> {
+ super::parse_blocks(input, |block| {
+ matches_from_status(block)
+ .filter_map(|(matches, module_path)| matches.then_some(module_path))
+ .collect()
+ })
+ }
+ }
+
+ mod files {
+ use bstr::{BString, ByteSlice};
+ pub fn parse_expected(input: &[u8]) -> Vec<super::Expected> {
+ super::parse_blocks(input, |block| {
+ block.lines().map(BString::from).map(|s| s.to_string()).collect()
+ })
+ }
+ }
+
+ pub fn directories() -> crate::Result<(PathBuf, Vec<String>, Vec<Expected>)> {
+ let root = gix_testtools::scripted_fixture_read_only("match_baseline_dirs.sh")?.join("parent");
+ let buf = std::fs::read(root.join("paths"))?;
+ let items = submodule::matches_from_status(&buf)
+ .map(|(_matches, path)| path)
+ .collect();
+ let expected = submodule::parse_expected(&std::fs::read(root.join("baseline.git"))?);
+ Ok((root, items, expected))
+ }
+
+ pub fn files() -> crate::Result<(PathBuf, Vec<String>, Vec<Expected>)> {
+ let root = gix_testtools::scripted_fixture_read_only("match_baseline_files.sh")?;
+ let items = parse_paths(root.join("paths"))?;
+ let expected = files::parse_expected(&std::fs::read(root.join("baseline.git"))?);
+ Ok((root, items, expected))
+ }
+}