Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"ee8696af611b486bded26ad9cbdeb0e9cf459edf410bc38d4068d6c44b74e89f","CHANGELOG.md":"9f37ce4a5a9ac730ab3bf1a065cc4f945b4e33074d413cbc2eaede140d4192cd","Cargo.lock":"d939d1254bd9a5f246f55161927f3a99b6828618df7ab82c86d3627e9265c165","Cargo.toml":"049d90ab477cf29f87177aa9f41ffeef1e06944f748c942d8bbd35bee9a2d5a5","Cargo.toml.orig":"ff60a468cb2925657da7f6309f0421c71c522f4e48419516edd5748b5d3f06eb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"70525682ac1de97a7c42a7e32a67cfe3a370534753d0bf440728bbb577304128","README.md":"8c1380ee8786e82b661035f7388b5da290785b74e929aa3bb1c53d5ee209335c","src/dependency.rs":"ab99b3cf10325a3414430e127f90a433314c9b39bfd02515ce4aa5aae38c65bb","src/dependency/graph.rs":"c6cfcdce226a7f7732709262e26ae7e4b4464f14c82ba8cc0ef9bc5ce7d989d5","src/dependency/tree.rs":"06d366cfb73efb8fe85484f2cbfb0f5c856e1ba9cf15955d7a46ecbbd2a03019","src/error.rs":"0cbce2dece82030cfa3b41ca0b15453ee30154ae1798386402959efc11c57caf","src/lib.rs":"19e930b2934fdd989549015bfa459ba45b53223561a7dcec5f15c2cb5b9310a2","src/lockfile.rs":"5357b4ab5ef465e24dfca3a63baccc35c544128a66ba683419a2011321002094","src/lockfile/encoding.rs":"464e381fb7f17c59868c6ad5a49f1649aa9eb3315986f17cf8afa1122d412917","src/lockfile/version.rs":"28ecc3a0e48a6b339f169ecc525c6c51b196c915c191777f9eb486dc3455b6ac","src/main.rs":"73736a72efe88ac1b71207df10aeffacebaa0ed08644b9f82e617716eb815881","src/metadata.rs":"69c8233333109be15d2b136a38b7d62ef6ebe505928983356ea067ae360ad015","src/package.rs":"e2ca59ec4e557efa99cb42d58e539f69b1acf93aee8988d70ce97562c91d09c4","src/package/checksum.rs":"d16a39dc30374add89f307e9e76bb9fd21b115d0c07877daa7b4f1d4e09714c0","src/package/name.rs":"f73da34f930bfa34872dd353425ce12a26861290d791cb2fe80aa2c4baba3e2e","src/package/source.rs":"2cf78f71f03fcb9b1aea370fc73e5ce3cfeb4f1e3cb73986c2948606e677c1bf","src/patch.rs":"ffe69e67a977d021222bba0b65d801caafd1d0f04e2d8c21720eb0c93d21fd57","tests/examples/Cargo.lock":"a00f206d76efdb60a9197b457728d3ba91c9051145821330c781b564ac6078ff","tests/examples/Cargo.lock.git-ref":"d1bfecef6cf7445b50cf624e1adc3f4af5794030a5d4a5bf180a5714c87defe4","tests/examples/Cargo.lock.same-git":"12df62bb744bea0dfcaa6e1bd6751f4e4960d39c79db988e82b1c3e9cc422ddc","tests/examples/Cargo.lock.unused-patch":"9a48795f8dc42aa3139f9c7d739d5d5d5cb42c9b8f7a068b13bdf9a0f16a9ba7","tests/examples/Cargo.lock.v1":"d165f5440214a919b9e10f098a02db4da7783623a9326f6d0a2527ee65f64410","tests/examples/Cargo.lock.v2":"81836bee7160f36c2b25b95ec1e428c60c8b356bc399ecdcff923119bb8201db","tests/examples/Cargo.lock.v3":"a00f206d76efdb60a9197b457728d3ba91c9051145821330c781b564ac6078ff","tests/examples/Cargo.lock.v4":"c0d439d40dd24b7c2c768849d8d6ccfc2a0a0ae6975f4467a67aafd395ebbbef","tests/examples/source_disambiguation/Cargo.lock.single_version_different_registries":"4c0be1bbbea1127bf2630f99f763ce93dc551b9bc7a496b2d9b5c68305754291","tests/examples/source_disambiguation/Cargo.lock.single_version_different_source_types":"7c1085cd3d0f39acb6297b7e2a4a1eb7216676a2c72f0b190e82008ff5e012ff","tests/examples/source_disambiguation/Cargo.lock.two_versions_different_registries":"222331d5573b8f760be07959937fe9c855e1811908e88ea3eb5809ea7f584f64","tests/examples/source_disambiguation/Cargo.lock.two_versions_different_source_types":"cea977a57e0f6f5e9fbc6756999173c6f5f36a0ef90b1088e47214b465915a62","tests/examples/source_disambiguation/Cargo.lock.two_versions_same_registry":"81e94ddfe997393e70de5a1821b92de5260dfadfdbfe4da1b127e513858c71d4","tests/examples/source_disambiguation/README.md":"ef93f29fd436a2bdbe3bfbf854135bc41c0e0b1228a2e96ebcf95ad33eb6a578","tests/lockfile.rs":"8acd72da2a3ad8d3bbc3e3be454261fef759febde68e58830290758fef575d30"},"package":"50524592e6bfbb1bf6f94e8184a786f637faeaf1cf37bbe65502b9a2c5c48939"}
+6
View File
@@ -0,0 +1,6 @@
{
"git": {
"sha1": "86193f5e6d7f98a9f3d30b2c99390d9ba7c88589"
},
"path_in_vcs": "cargo-lock"
}
+174
View File
@@ -0,0 +1,174 @@
# 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).
## 10.1.0 (2025-01-18)
### Fixed
- Fixed git tags in Cargo.lock not being normalized correctly when using lockfile v4 format ([#1298])
- Increased MSRV to 1.73 to match the requirements of dependencies in Cargo.lock
[#1298]: https://github.com/RustSec/rustsec/pull/1298
## 10.0.1 (2024-10-25)
### Fixed
- Remove `precise` from source IDs during normalization ([#1270])
[#1270]: https://github.com/RustSec/rustsec/pull/1270
## 10.0.0 (2024-10-15)
### Added
- V4 lockfile support ([#1206])
### Changed
- MSRV 1.70 ([#1092])
### Removed
- `toml` dependency from public API ([#1226])
[#1092]: https://github.com/RustSec/rustsec/pull/1092
[#1206]: https://github.com/RustSec/rustsec/pull/1206
[#1226]: https://github.com/RustSec/rustsec/pull/1226
## 9.0.0 (2023-04-24)
### Added
- Implement `From<Name>` for `String` ([#776])
- Support sparse registry references in `Lockfile`s ([#780])
### Changed
- Mark `SourceKind` as `#[non_exhaustive]` ([#793])
- Use `Display` for `io::ErrorKind`; MSRV 1.60 ([#794])
- Bump `toml` to 0.7 ([#800], [#805])
- Improvements to the `cargo lock tree` subcommand ([#860])
### Fixed
- `Source::is_default_registry` for sparse index ([#859])
[#776]: https://github.com/RustSec/rustsec/pull/776
[#780]: https://github.com/RustSec/rustsec/pull/780
[#793]: https://github.com/RustSec/rustsec/pull/793
[#794]: https://github.com/RustSec/rustsec/pull/794
[#800]: https://github.com/RustSec/rustsec/pull/800
[#805]: https://github.com/RustSec/rustsec/pull/805
[#859]: https://github.com/RustSec/rustsec/pull/859
[#860]: https://github.com/RustSec/rustsec/pull/860
## 8.0.3 (2022-11-30)
### Fixed
- Encoding inconsistency when there's only one registry for all packages ([#767])
[#767]: https://github.com/RustSec/rustsec/pull/767
## 8.0.2 (2022-06-30)
### Fixed
- Re-export `GitReference` ([#595])
- Encode version into V3 lockfiles ([#596])
[#595]: https://github.com/RustSec/rustsec/pull/595
[#596]: https://github.com/RustSec/rustsec/pull/596
## 8.0.1 (2022-05-21)
### Fixed
- Dependency source extraction for V2+ lockfiles ([#568])
[#568]: https://github.com/RustSec/rustsec/pull/568
## 8.0.0 (2022-05-08) [YANKED]
NOTE: yanked due to bug fixed in v8.0.1.
### Added
- Expose `package::SourceKind` ([#557])
### Changed
- Flatten API ([#558])
- 2021 edition upgrade; MSRV 1.56 ([#559])
- Refactor error handling ([#560])
[#557]: https://github.com/RustSec/rustsec/pull/557
[#558]: https://github.com/RustSec/rustsec/pull/558
[#559]: https://github.com/RustSec/rustsec/pull/559
[#560]: https://github.com/RustSec/rustsec/pull/560
## 7.1.0 (2022-04-23)
### Added
- `SourceId::default()` ([#536])
### Changed
- MSRV is now 1.49 ([#524])
### Fixed
- V3 lockfile handling and tests ([#535])
[#524]: https://github.com/RustSec/rustsec/pull/524
[#535]: https://github.com/RustSec/rustsec/pull/535
[#536]: https://github.com/RustSec/rustsec/pull/536
## 7.0.1 (2021-07-05)
### Changed
- Bump `petgraph` dependency from 0.5.1 to 0.6.0 ([#396])
[#396]: https://github.com/RustSec/rustsec/pull/396
## 7.0.0 (2021-05-27) [YANKED]
### Added
- Support for V3 lockfile format ([#363])
### Changed
- Bump `semver` to v1.0.0 ([#378])
[#363]: https://github.com/RustSec/rustsec/pull/363
[#378]: https://github.com/RustSec/rustsec/pull/378
## 6.0.1 (2021-01-25)
### Changed
- Rename default branch to `main`
## 6.0.0 (2020-09-25)
- Bump semver from 0.10.0 to 0.11.0
## 5.0.0 (2020-09-23)
- CLI: support for listing a single dependency
- Cargo-compatible serializer
- CLI: add `--dependencies` and `--sources` flags to `cargo lock list`
- CLI: implement `cargo lock tree` without arguments
- Add `dependency::Tree::roots()` method
- CLI: make `list` the default command
- Make `cli` feature non-default
- WASM support; MSRV 1.41+
- Bump `semver` dependency from v0.9 to v0.10
## 4.0.1 (2020-01-22)
- CLI: fix executable name
## 4.0.0 (2020-01-22)
- Command line interface
- Add helper methods for working with checksum metadata
- Use minified version of Cargo's `SourceId` type
- Overhaul encoding: use serde_derive, proper V1/V2 support
- Add support Cargo.lock `patch` and `root`
- Detect V1 vs V2 Cargo.lock files
- Update `petgraph` requirement from 0.4 to 0.5
- Add `package::Checksum`
## 3.0.0 (2019-10-01)
- Support `[package.dependencies]` without versions
## 2.0.0 (2019-09-25)
- Use two-pass dependency tree computation
- Remove `Lockfile::root_package()`
## 1.0.0 (2019-09-24)
- dependency/tree: Render trees to an `io::Write`
- metadata: Generalize into `Key` and `Value` types
- Refactor dependency handling
## 0.2.1 (2019-09-21)
- Allow empty `[metadata]` in Cargo.lock files
## 0.2.0 (2019-09-21)
- dependency_graph: Move `petgraph` types into a module
## 0.1.0 (2019-09-21)
- Initial release
+617
View File
@@ -0,0 +1,617 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anstream"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anstyle-parse"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
]
[[package]]
name = "cargo-lock"
version = "11.1.0"
dependencies = [
"clap",
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "clap"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "displaydoc"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "icu_collections"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
"potential_utf",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]]
name = "icu_properties"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
dependencies = [
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
[[package]]
name = "icu_provider"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "litemap"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "petgraph"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [
"zerovec",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
dependencies = [
"serde",
"serde_core",
]
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_spanned"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
dependencies = [
"serde_core",
]
[[package]]
name = "smallvec"
version = "1.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tinystr"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "toml"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
dependencies = [
"indexmap",
"serde_core",
"serde_spanned",
"toml_datetime",
"toml_parser",
"toml_writer",
"winnow",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "winnow"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
[[package]]
name = "writeable"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "yoke"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerofrom"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "zerotrie"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+101
View File
@@ -0,0 +1,101 @@
# 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 = "2024"
rust-version = "1.85"
name = "cargo-lock"
version = "11.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Self-contained Cargo.lock parser with optional dependency graph analysis"
homepage = "https://rustsec.org"
readme = "README.md"
keywords = [
"cargo",
"dependency",
"lock",
"lockfile",
]
categories = ["parser-implementations"]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/rustsec/rustsec"
resolver = "2"
[package.metadata.docs.rs]
features = ["dependency-tree"]
rustdoc-args = [
"--cfg",
"docsrs",
]
[features]
cli = [
"dep:clap",
"dependency-tree",
]
dependency-tree = ["petgraph"]
[lib]
name = "cargo_lock"
path = "src/lib.rs"
[[bin]]
name = "cargo-lock"
path = "src/main.rs"
required-features = ["cli"]
[[test]]
name = "lockfile"
path = "tests/lockfile.rs"
[dependencies.clap]
version = "4"
features = ["derive"]
optional = true
[dependencies.petgraph]
version = "0.8.2"
optional = true
[dependencies.semver]
version = "1.0.23"
features = ["serde"]
[dependencies.serde]
version = "1"
features = ["serde_derive"]
[dependencies.toml]
version = "1.0"
[dependencies.url]
version = "2"
[lints.clippy]
cloned_instead_of_copied = "warn"
manual_let_else = "warn"
or_fun_call = "warn"
upper_case_acronyms = "warn"
use_self = "warn"
[lints.rust]
elided_lifetimes_in_paths = "warn"
trivial_numeric_casts = "warn"
unnameable_types = "warn"
unreachable_pub = "warn"
unused_extern_crates = "warn"
unused_import_braces = "warn"
unused_qualifications = "warn"
+35
View File
@@ -0,0 +1,35 @@
[package]
name = "cargo-lock"
description = "Self-contained Cargo.lock parser with optional dependency graph analysis"
version = "11.1.0"
license = "Apache-2.0 OR MIT"
readme = "README.md"
homepage = "https://rustsec.org"
repository = "https://github.com/rustsec/rustsec"
categories = ["parser-implementations"]
keywords = ["cargo", "dependency", "lock", "lockfile"]
edition = "2024"
rust-version = "1.85"
[[bin]]
name = "cargo-lock"
required-features = ["cli"]
[dependencies]
clap = { workspace = true, features = ["derive"], optional = true }
petgraph = { workspace = true, optional = true }
semver = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["serde_derive"] }
toml = { workspace = true }
url = { workspace = true }
[features]
cli = ["dep:clap", "dependency-tree"]
dependency-tree = ["petgraph"]
[package.metadata.docs.rs]
features = ["dependency-tree"]
rustdoc-args = ["--cfg", "docsrs"]
[lints]
workspace = true
+201
View File
@@ -0,0 +1,201 @@
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
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2019-2022 The RustSec Project Developers
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.
+92
View File
@@ -0,0 +1,92 @@
# RustSec: `cargo-lock` crate
[![Latest Version][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
[![Build Status][build-image]][build-link]
[![Safety Dance][safety-image]][safety-link]
![MSRV][rustc-image]
![Apache 2.0 OR MIT licensed][license-image]
[![Project Chat][zulip-image]][zulip-link]
Self-contained [serde]-powered `Cargo.lock` parser/serializer with support
for the V1/V2/V3/V4 formats, as well as optional dependency tree analysis features.
Used by [RustSec].
When the `dependency-tree` feature of this crate is enabled, it supports
computing a directed graph of the dependency tree, modeled using the
[`petgraph`] crate, along with support for printing dependency trees ala
the [`cargo-tree`] crate.
[Documentation][docs-link]
## Minimum Supported Rust Version
Rust **1.70** or higher.
Minimum supported Rust version can be changed in the future, but it will be
accompanied by a minor version bump.
## SemVer Policy
- MSRV is considered exempt from SemVer as noted above
- The `cargo lock` CLI interface is not considered to have a stable interface
and is also exempted from SemVer. We reserve the right to make substantial
changes to it at any time (for now)
- The `dependency-tree` feature depends on the pre-1.0 `petgraph` crate.
We reserve the right to update `petgraph`, however when we do it will be
accompanied by a minor version bump.
## Command Line Interface
This crate provides a `cargo lock` subcommand which can be installed with:
```text
cargo install cargo-lock --features=cli
```
It supports the following subcommands:
- `list`: list packages in `Cargo.lock`
- `translate`: translate `Cargo.lock` files between the V1 and V2 formats
- `tree`: print a dependency tree from `Cargo.lock` alone
See the [crate documentation][docs-link] for more detailed usage information.
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE] or <https://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT] or <https://opensource.org/licenses/MIT>)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you shall be dual licensed as above, without any
additional terms or conditions.
[//]: # (badges)
[crate-image]: https://img.shields.io/crates/v/cargo-lock?logo=rust
[crate-link]: https://crates.io/crates/cargo-lock
[docs-image]: https://docs.rs/cargo-lock/badge.svg
[docs-link]: https://docs.rs/cargo-lock/
[build-image]: https://github.com/RustSec/rustsec/actions/workflows/cargo-lock.yml/badge.svg
[build-link]: https://github.com/RustSec/rustsec/actions/workflows/cargo-lock.yml
[license-image]: https://img.shields.io/badge/license-Apache2.0%2FMIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.70+-blue.svg
[safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg
[safety-link]: https://github.com/rust-secure-code/safety-dance/
[zulip-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
[zulip-link]: https://rust-lang.zulipchat.com/#narrow/stream/146229-wg-secure-code/
[//]: # (general links)
[serde]: https://serde.rs/
[RustSec]: https://rustsec.org/
[`petgraph`]: https://github.com/petgraph/petgraph
[`cargo-tree`]: https://github.com/sfackler/cargo-tree
[LICENSE-APACHE]: https://github.com/RustSec/cargo-lock/blob/main/LICENSE-APACHE
[LICENSE-MIT]: https://github.com/RustSec/cargo-lock/blob/main/LICENSE-MIT
+57
View File
@@ -0,0 +1,57 @@
//! Package dependencies
#[cfg(feature = "dependency-tree")]
pub mod graph;
#[cfg(feature = "dependency-tree")]
pub mod tree;
#[cfg(feature = "dependency-tree")]
pub use self::tree::Tree;
use crate::package::{Name, Package, SourceId};
use semver::Version;
use serde::{Deserialize, Serialize};
use std::fmt;
/// Package dependencies
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct Dependency {
/// Name of the dependency
pub name: Name,
/// Version of the dependency
pub version: Version,
/// Source identifier for the dependency
pub source: Option<SourceId>,
}
impl Dependency {
/// Does the given [`Package`] exactly match this `Dependency`?
pub fn matches(&self, package: &Package) -> bool {
self.name == package.name && self.version == package.version
}
}
impl fmt::Display for Dependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.name, self.version)?;
if let Some(source) = &self.source {
write!(f, " ({source})")?;
}
Ok(())
}
}
impl From<&Package> for Dependency {
/// Get the [`Dependency`] requirement for this `[[package]]`
fn from(pkg: &Package) -> Self {
Self {
name: pkg.name.clone(),
version: pkg.version.clone(),
source: pkg.source.clone(),
}
}
}
+11
View File
@@ -0,0 +1,11 @@
//! `petgraph` types used for modeling the `dependency::Tree`.
pub use petgraph::{EdgeDirection, graph::NodeIndex};
use crate::{Map, dependency::Dependency, package::Package};
/// Dependency graph (modeled using `petgraph`)
pub type Graph = petgraph::graph::Graph<Package, Dependency>;
/// Nodes in the dependency graph
pub type Nodes = Map<Dependency, NodeIndex>;
+238
View File
@@ -0,0 +1,238 @@
//! Dependency trees computed from `Cargo.lock` files.
//!
//! Uses the `petgraph` crate for modeling the dependency structure.
// Includes code from `cargo-tree`, Copyright (c) 2015-2016 Steven Fackler
// Licensed under the same terms as `cargo-audit` (i.e. Apache 2.0 + MIT)
use super::{
Dependency,
graph::{EdgeDirection, Graph, NodeIndex, Nodes},
};
use crate::{Map, error::Error, lockfile::Lockfile};
use std::{collections::BTreeSet as Set, io};
/// Dependency tree computed from a `Cargo.lock` file
#[derive(Clone, Debug)]
pub struct Tree {
/// Dependency graph for a particular package
graph: Graph,
/// Package data associated with nodes in the graph
nodes: Nodes,
}
impl Tree {
/// Construct a new dependency tree for the given [`Lockfile`].
pub fn new(lockfile: &Lockfile) -> Result<Self, Error> {
let mut graph = Graph::new();
let mut nodes = Map::new();
// Populate all graph nodes in the first pass
for package in &lockfile.packages {
let node_index = graph.add_node(package.clone());
nodes.insert(Dependency::from(package), node_index);
}
// Populate all graph edges in the second pass
for package in &lockfile.packages {
let parent_index = nodes[&Dependency::from(package)];
for dependency in &package.dependencies {
if let Some(node_index) = nodes.get(dependency) {
graph.add_edge(parent_index, *node_index, dependency.clone());
} else {
return Err(Error::Resolution(format!(
"failed to find dependency: {dependency}"
)));
}
}
}
Ok(Self { graph, nodes })
}
/// Render the dependency graph for the given [`NodeIndex`] using the
/// default set of [`Symbols`].
pub fn render(
&self,
w: &mut impl io::Write,
node_index: NodeIndex,
direction: EdgeDirection,
exact: bool,
) -> io::Result<()> {
self.render_with_symbols(w, node_index, direction, &Symbols::default(), exact)
}
/// Render the dependency graph for the given [`NodeIndex`] using the
/// provided set of [`Symbols`].
pub fn render_with_symbols(
&self,
w: &mut impl io::Write,
node_index: NodeIndex,
direction: EdgeDirection,
symbols: &Symbols,
exact: bool,
) -> io::Result<()> {
Presenter::new(&self.graph, symbols).print_node(w, node_index, direction, exact)
}
/// Get the indexes of the root packages in the workspace
/// (i.e. toplevel packages which are not used as dependencies)
pub fn roots(&self) -> Vec<NodeIndex> {
self.graph.externals(EdgeDirection::Incoming).collect()
}
/// Get the `petgraph` dependency graph.
pub fn graph(&self) -> &Graph {
&self.graph
}
/// Get the nodes of the `petgraph` dependency graph.
pub fn nodes(&self) -> &Nodes {
&self.nodes
}
}
/// Symbols to use when printing the dependency tree
pub struct Symbols {
down: &'static str,
tee: &'static str,
ell: &'static str,
right: &'static str,
}
impl Default for Symbols {
fn default() -> Self {
Self {
down: "│",
tee: "├",
ell: "└",
right: "─",
}
}
}
/// Dependency tree presenter
struct Presenter<'g, 's> {
/// Dependency graph being displayed
graph: &'g Graph,
/// Symbols to use to display graph
symbols: &'s Symbols,
/// Are there continuing levels?
levels_continue: Vec<bool>,
/// Dependencies we've already visited
visited: Set<NodeIndex>,
}
impl<'g, 's> Presenter<'g, 's> {
/// Create a new dependency tree `Presenter`.
fn new(graph: &'g Graph, symbols: &'s Symbols) -> Self {
Self {
graph,
symbols,
levels_continue: vec![],
visited: Set::new(),
}
}
/// Print a node in the dependency tree.
fn print_node(
&mut self,
w: &mut impl io::Write,
node_index: NodeIndex,
direction: EdgeDirection,
exact: bool,
) -> io::Result<()> {
let package = &self.graph[node_index];
let new = self.visited.insert(node_index);
if let Some((&last_continues, rest)) = self.levels_continue.split_last() {
for &continues in rest {
let c = if continues { self.symbols.down } else { " " };
write!(w, "{c} ")?;
}
let c = if last_continues {
self.symbols.tee
} else {
self.symbols.ell
};
write!(w, "{0}{1}{1} ", c, self.symbols.right)?;
}
if exact {
let spec = if let Some(checksum) = &package.checksum {
format!("checksum:{checksum}")
} else if let Some(src) = &package.source {
src.to_string()
} else {
"inexact".to_string()
};
writeln!(w, "{} {} {}", package.name, package.version, spec)?;
} else {
writeln!(w, "{} {}", package.name, package.version)?;
}
if !new {
return Ok(());
}
use petgraph::visit::EdgeRef;
let dependencies = self
.graph
.edges_directed(node_index, direction)
.map(|edge| match direction {
EdgeDirection::Incoming => edge.source(),
EdgeDirection::Outgoing => edge.target(),
})
.collect::<Vec<_>>();
for (i, dependency) in dependencies.iter().enumerate() {
self.levels_continue.push(i < (dependencies.len() - 1));
self.print_node(w, *dependency, direction, exact)?;
self.levels_continue.pop();
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compute_tree_v3() {
// TODO(tarcieri): test dependency tree is computed correctly
let lockfile = Lockfile::load("tests/examples/Cargo.lock.v3").unwrap();
Tree::new(&lockfile).unwrap();
}
#[test]
fn compute_roots_v3() {
let lockfile = Lockfile::load("tests/examples/Cargo.lock.v3").unwrap();
let tree = Tree::new(&lockfile).unwrap();
let roots = tree.roots();
assert_eq!(roots.len(), 1);
let root_package = &tree.graph[roots[0]];
assert_eq!(root_package.name.as_str(), "cargo-lock");
}
#[test]
fn compute_tree_git_ref() {
let lockfile = Lockfile::load("tests/examples/Cargo.lock.git-ref").unwrap();
Tree::new(&lockfile).unwrap();
}
#[test]
fn load_same_git() {
let lockfile = Lockfile::load("tests/examples/Cargo.lock.same-git").unwrap();
Tree::new(&lockfile).unwrap();
}
}
+54
View File
@@ -0,0 +1,54 @@
//! Error types
use std::{fmt, io};
/// Result type with the `cargo-lock` crate's [`Error`] type.
pub type Result<T> = core::result::Result<T, Error>;
/// Error type.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
/// An error occurred performing an I/O operation (e.g. network, file)
Io(io::ErrorKind),
/// Couldn't parse response data
Parse(String),
/// Errors related to versions
Version(semver::Error),
/// Errors related to graph resolution
Resolution(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(kind) => write!(f, "I/O operation failed: {kind}"),
Self::Parse(s) => write!(f, "parse error: {s}"),
Self::Version(err) => write!(f, "version error: {err}"),
Self::Resolution(err) => write!(f, "resolution error: {err}"),
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::Io(err.kind())
}
}
impl From<semver::Error> for Error {
fn from(err: semver::Error) -> Self {
Self::Version(err)
}
}
impl From<std::num::ParseIntError> for Error {
fn from(err: std::num::ParseIntError) -> Self {
Self::Parse(err.to_string())
}
}
impl std::error::Error for Error {}
+176
View File
@@ -0,0 +1,176 @@
#![doc = include_str!("../README.md")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustSec/logos/main/rustsec-logo-lg.png")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
//! # Usage
//!
//! ```
//! use cargo_lock::Lockfile;
//!
//! let lockfile = Lockfile::load("tests/examples/Cargo.lock").unwrap();
//! println!("number of dependencies: {}", lockfile.packages.len());
//! ```
//!
//! # Dependency tree API
//!
//! When the `dependency-tree` feature of this crate is enabled, it supports
//! computing a directed graph of the dependency tree expressed in the
//! lockfile, modeled using the [`petgraph`] crate, along with support for
//! printing dependency trees ala the [`cargo-tree`] crate, a CLI interface
//! for which is provided by the `cargo lock tree` subcommand described above.
//!
//! This same graph representation of a `Cargo.lock` file is programmatically
//! available via this crate's API.
//!
//! # Command Line Interface
//!
//! This crate provides a `cargo lock` Cargo subcommand which can be installed
//! by running the following:
//!
//! ```text
//! $ cargo install cargo-lock --features cli
//! ```
//!
//! It supports the following subcommands:
//!
//! ### `list`: summarize packages in `Cargo.lock`
//!
//! The `cargo lock list` subcommand (which can be shortened to just
//! `cargo lock` if you prefer) provides a short synopsis of the packages
//! enumerated in `Cargo.lock`:
//!
//! ```text
//! $ cargo lock
//! - autocfg 1.0.0
//! - cargo-lock 4.0.1
//! - fixedbitset 0.2.0
//! - gumdrop 0.8.0
//! - gumdrop_derive 0.8.0
//! - idna 0.2.0
//! - indexmap 1.3.2
//! - matches 0.1.8
//! [...]
//! ```
//!
//! Adding a `-d` (or `--dependencies`) flag will show transitive dependencies:
//!
//! ```text
//! $ cargo lock -d
//! - autocfg 1.0.0
//! - cargo-lock 4.0.1
//! - gumdrop 0.8.0
//! - petgraph 0.5.1
//! - semver 0.10.0
//! - serde 1.0.116
//! - toml 0.5.6
//! - url 2.1.1
//! - fixedbitset 0.2.0
//! - gumdrop 0.8.0
//! - gumdrop_derive 0.8.0
//! - gumdrop_derive 0.8.0
//! - proc-macro2 1.0.21
//! - quote 1.0.3
//! - syn 1.0.40
//! - idna 0.2.0
//! - matches 0.1.8
//! - unicode-bidi 0.3.4
//! - unicode-normalization 0.1.12
//! [...]
//! ```
//!
//! Adding a `-s` (or `--source`) flag will show source information for each
//! package (when available):
//!
//! ```text
//! - autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)
//! - cargo-lock 4.0.1
//! - fixedbitset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)
//! - gumdrop 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)
//! - gumdrop_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)
//! - idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)
//! - indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)
//! [...]
//! ```
//!
//! ### `translate`: convert `Cargo.lock` files between the V1 and V2 formats
//!
//! The `cargo lock translate` subcommand can translate V1 Cargo.lock files to
//! the [V2 format] and vice versa:
//!
//! ```text
//! $ cargo lock translate
//! ```
//!
//! ...will translate Cargo.lock to the V2 format. To translate a V2 Cargo.lock
//! file back to the V1 format, use:
//!
//! ```text
//! $ cargo lock translate -v1
//! ```
//!
//! ### `tree`: provide information for how a dependency is included
//!
//! The `cargo lock tree` subcommand (similar to the `cargo-tree` command)
//! can provide a visualization of the current dependency tree or how a
//! particular dependency is being used in your project, by consulting
//! `Cargo.lock` alone:
//!
//! ```text
//! $ cargo lock tree
//! cargo-lock 4.0.1
//! ├── url 2.1.1
//! │ ├── percent-encoding 2.1.0
//! │ ├── matches 0.1.8
//! │ └── idna 0.2.0
//! │ ├── unicode-normalization 0.1.12
//! │ │ └── smallvec 1.2.0
//! │ ├── unicode-bidi 0.3.4
//! │ │ └── matches 0.1.8
//! │ └── matches 0.1.8
//! ├── toml 0.5.6
//! │ └── serde 1.0.116
//! │ └── serde_derive 1.0.116
//! [...]
//! ```
//!
//! ```text
//! $ cargo lock tree syn
//! syn 1.0.14
//! ├── serde_derive 1.0.104
//! │ └── serde 1.0.104
//! │ ├── toml 0.5.6
//! │ │ └── cargo-lock 3.0.0
//! │ ├── semver 0.9.0
//! │ │ └── cargo-lock 3.0.0
//! │ └── cargo-lock 3.0.0
//! └── gumdrop_derive 0.7.0
//! └── gumdrop 0.7.0
//! └── cargo-lock 3.0.0
//! ```
//!
//! [RustSec]: https://rustsec.org/
//! [V2 format]: https://github.com/rust-lang/cargo/pull/7070
//! [`petgraph`]: https://github.com/petgraph/petgraph
//! [`cargo-tree`]: https://github.com/sfackler/cargo-tree
pub mod dependency;
pub mod package;
mod error;
mod lockfile;
mod metadata;
mod patch;
pub use crate::{
dependency::Dependency,
error::{Error, Result},
lockfile::{Lockfile, ResolveVersion},
metadata::{Metadata, MetadataKey, MetadataValue},
package::{Checksum, Name, Package, SourceId, Version},
patch::Patch,
};
/// Use `BTreeMap` for all `Map` types in the crate
use std::collections::BTreeMap as Map;
+68
View File
@@ -0,0 +1,68 @@
//! Parser for `Cargo.lock` files
pub(crate) mod encoding;
pub(crate) mod version;
pub use self::version::ResolveVersion;
use self::encoding::EncodableLockfile;
use crate::{
error::{Error, Result},
metadata::Metadata,
package::Package,
patch::Patch,
};
use std::{fs, path::Path, str::FromStr, string::ToString};
#[cfg(feature = "dependency-tree")]
use crate::dependency::Tree;
/// Parsed Cargo.lock file containing dependencies
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Lockfile {
/// Version of the Lockfile
pub version: ResolveVersion,
/// Dependencies enumerated in the lockfile
pub packages: Vec<Package>,
/// Legacy "root" dependency for backwards compatibility
pub root: Option<Package>,
/// Package metadata
pub metadata: Metadata,
/// Patches
pub patch: Patch,
}
impl Lockfile {
/// Load lock data from a `Cargo.lock` file
pub fn load(path: impl AsRef<Path>) -> Result<Self> {
fs::read_to_string(path.as_ref())?.parse()
}
/// Get the dependency tree for this `Lockfile`. Returns an error if the
/// contents of this lockfile aren't well structured.
///
/// The `dependency-tree` Cargo feature must be enabled to use this.
#[cfg(feature = "dependency-tree")]
pub fn dependency_tree(&self) -> Result<Tree> {
Tree::new(self)
}
}
impl FromStr for Lockfile {
type Err = Error;
fn from_str(toml_string: &str) -> Result<Self> {
toml::from_str(toml_string).map_err(|e| Error::Parse(e.to_string()))
}
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for Lockfile {
fn to_string(&self) -> String {
EncodableLockfile::from(self).to_string()
}
}
+583
View File
@@ -0,0 +1,583 @@
//! serde-based `Cargo.lock` parser/serializer
//!
//! Customized to allow pre/postprocessing to detect and serialize both
//! the V1 vs V2 formats and ensure the end-user is supplied a consistent
//! representation regardless of which version is in use.
//!
//! Parts adapted from upstream Cargo.
//! Cargo is primarily distributed under the terms of both the MIT license and
//! the Apache License (Version 2.0).
use super::{Lockfile, ResolveVersion};
use crate::{
Checksum, Dependency, Error, Metadata, Name, Package, Patch, Result, SourceId, Version,
metadata,
};
use serde::{Deserialize, Serialize, de, ser};
use std::{fmt, fmt::Write, str::FromStr};
impl<'de> Deserialize<'de> for Lockfile {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> std::result::Result<Self, D::Error> {
EncodableLockfile::deserialize(deserializer)?
.try_into()
.map_err(de::Error::custom)
}
}
impl Serialize for Lockfile {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
EncodableLockfile::from(self).serialize(serializer)
}
}
/// Serialization-oriented equivalent to [`Lockfile`]
#[derive(Debug, Deserialize, Serialize)]
pub(super) struct EncodableLockfile {
/// Lockfile version
pub(super) version: Option<u32>,
/// Packages in the lockfile
#[serde(default)]
pub(super) package: Vec<EncodablePackage>,
/// Legacy root package (preserved for compatibility)
pub(super) root: Option<EncodablePackage>,
/// Metadata fields
#[serde(default, skip_serializing_if = "Metadata::is_empty")]
pub(super) metadata: Metadata,
/// Patch section
#[serde(default, skip_serializing_if = "Patch::is_empty")]
pub(super) patch: Patch,
}
impl EncodableLockfile {
/// Attempt to find a checksum for a package in a V1 lockfile
fn find_checksum(&self, package: &Package) -> Option<Checksum> {
for (key, value) in &self.metadata {
if let Ok(dep) = key.checksum_dependency() {
if dep.name == package.name && dep.version == package.version {
return value.checksum().ok();
}
}
}
None
}
}
impl TryFrom<EncodableLockfile> for Lockfile {
type Error = Error;
fn try_from(raw_lockfile: EncodableLockfile) -> Result<Self> {
let version = match raw_lockfile.version {
Some(n) => n.try_into()?,
None => ResolveVersion::detect(&raw_lockfile.package, &raw_lockfile.metadata)?,
};
let mut packages = Vec::with_capacity(raw_lockfile.package.len());
for raw_package in &raw_lockfile.package {
packages.push(if version == ResolveVersion::V1 {
// In the V1 format, all dependencies are fully qualified with
// their versions, but their checksums are stored in metadata.
let mut pkg = Package::try_from(raw_package)?;
pkg.checksum = raw_lockfile.find_checksum(&pkg);
pkg
} else {
// In newer versions, we may need to look up dependency versions
// from the other packages listed in the lockfile
raw_package.resolve(&raw_lockfile.package)?
})
}
Ok(Self {
version,
packages,
root: raw_lockfile
.root
.as_ref()
.map(|root| root.try_into())
.transpose()?,
metadata: raw_lockfile.metadata,
patch: raw_lockfile.patch,
})
}
}
impl From<&Lockfile> for EncodableLockfile {
fn from(lockfile: &Lockfile) -> Self {
let mut packages = Vec::with_capacity(lockfile.packages.len());
let mut metadata = lockfile.metadata.clone();
for package in &lockfile.packages {
let mut raw_pkg = EncodablePackage::from_package(package, lockfile.version);
let checksum_key = metadata::MetadataKey::for_checksum(&Dependency::from(package));
if lockfile.version == ResolveVersion::V1 {
// In the V1 format, we need to remove the checksum from
// packages and add it to metadata
if let Some(checksum) = raw_pkg.checksum.take() {
let value = checksum
.to_string()
.parse::<metadata::MetadataValue>()
.unwrap();
metadata.insert(checksum_key, value);
}
} else {
// In newer versions, we need to remove the version/source from
// unambiguous dependencies, and remove checksums from the
// metadata table if present
raw_pkg.v2_deps(&lockfile.packages);
metadata.remove(&checksum_key);
}
packages.push(raw_pkg);
}
let version = if lockfile.version.is_explicit() {
Some(lockfile.version.into())
} else {
None
};
Self {
version,
package: packages,
root: lockfile
.root
.as_ref()
.map(|root| EncodablePackage::from_package(root, lockfile.version)),
metadata,
patch: lockfile.patch.clone(),
}
}
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for EncodableLockfile {
/// Adapted from `serialize_resolve` in upstream Cargo:
/// <https://github.com/rust-lang/cargo/blob/0c70319/src/cargo/ops/lockfile.rs#L103-L174>
fn to_string(&self) -> String {
let toml = toml::Value::try_from(self).unwrap();
let mut out = String::new();
// At the start of the file we notify the reader that the file is generated.
// Specifically Phabricator ignores files containing "@generated", so we use that.
let marker_line = "# This file is automatically @generated by Cargo.";
let extra_line = "# It is not intended for manual editing.";
out.push_str(marker_line);
out.push('\n');
out.push_str(extra_line);
out.push('\n');
if let Some(value) = toml.get("version") {
if let Some(version) = value.as_integer() {
if version >= 3 {
writeln!(out, "version = {version}").unwrap();
}
}
}
out.push('\n');
let deps = toml["package"].as_array().unwrap();
for dep in deps {
let dep = dep.as_table().unwrap();
out.push_str("[[package]]\n");
emit_package(dep, &mut out);
}
if let Some(patch) = toml.get("patch") {
let list = patch["unused"].as_array().unwrap();
for entry in list {
out.push_str("[[patch.unused]]\n");
emit_package(entry.as_table().unwrap(), &mut out);
out.push('\n');
}
}
if let Some(meta) = toml.get("metadata") {
out.push_str("[metadata]\n");
out.push_str(&toml::to_string_pretty(&meta).unwrap());
}
// Trim redundant newlines
while out.ends_with("\n\n") {
out.pop();
}
out
}
}
/// Emit a single package from a lockfile.
///
/// This method is adapted from the same-named method in upstream Cargo:
/// <https://github.com/rust-lang/cargo/blob/0c70319/src/cargo/ops/lockfile.rs#L194-L221>
fn emit_package(dep: &toml::value::Table, out: &mut String) {
writeln!(out, "name = {}", dep["name"]).unwrap();
writeln!(out, "version = {}", dep["version"]).unwrap();
if dep.contains_key("source") {
writeln!(out, "source = {}", dep["source"]).unwrap();
}
if dep.contains_key("checksum") {
writeln!(out, "checksum = {}", dep["checksum"]).unwrap();
}
if let Some(s) = dep.get("dependencies") {
let slice = s.as_array().unwrap();
if !slice.is_empty() {
out.push_str("dependencies = [\n");
for child in slice.iter() {
writeln!(out, " {child},").unwrap();
}
out.push_str("]\n");
}
} else if dep.contains_key("replace") {
writeln!(out, "replace = {}", dep["replace"]).unwrap();
}
out.push('\n');
}
/// Serialization-oriented equivalent to [`Package`]
#[derive(Debug, Deserialize, Serialize)]
pub(crate) struct EncodablePackage {
/// Package name
pub(super) name: Name,
/// Package version
pub(super) version: Version,
/// Source of a package
pub(super) source: Option<EncodableSourceId>,
/// Package checksum
pub(super) checksum: Option<Checksum>,
/// Package dependencies
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub(super) dependencies: Vec<EncodableDependency>,
/// Replace directive
pub(super) replace: Option<EncodableDependency>,
}
impl EncodablePackage {
/// Resolve all of the dependencies of a package, which in the V2 format
/// may be abbreviated to prevent merge conflicts
fn resolve(&self, packages: &[Self]) -> Result<Package> {
let mut dependencies = Vec::with_capacity(self.dependencies.len());
for dep in &self.dependencies {
dependencies.push(dep.resolve(packages)?);
}
Ok(Package {
name: self.name.clone(),
version: self.version.clone(),
source: self.source.as_ref().map(|s| s.inner.clone()),
checksum: self.checksum.clone(),
dependencies,
replace: self
.replace
.as_ref()
.map(|rep| rep.try_into())
.transpose()?,
})
}
/// Prepare `ResolveVersion::V2` dependencies by removing ones which are unambiguous
fn v2_deps(&mut self, packages: &[Package]) {
for dependency in &mut self.dependencies {
dependency.v2(packages);
}
}
fn from_package(package: &Package, version: ResolveVersion) -> Self {
Self {
name: package.name.clone(),
version: package.version.clone(),
source: package
.source
.clone()
.and_then(|id| encodable_source_id(id, version)),
checksum: package.checksum.clone(),
dependencies: package
.dependencies
.iter()
.map(|dep| EncodableDependency::from_dependency(dep, version))
.collect::<Vec<_>>(),
replace: package
.replace
.as_ref()
.map(|rep| EncodableDependency::from_dependency(rep, version)),
}
}
}
fn encodable_source_id(id: SourceId, version: ResolveVersion) -> Option<EncodableSourceId> {
if id.is_path() {
None
} else {
Some(if version >= ResolveVersion::V4 {
EncodableSourceId::new(id)
} else {
EncodableSourceId::without_url_encoded(id)
})
}
}
/// Note: this only works for `ResolveVersion::V1` dependencies.
impl TryFrom<&EncodablePackage> for Package {
type Error = Error;
fn try_from(raw_package: &EncodablePackage) -> Result<Self> {
raw_package.resolve(&[])
}
}
/// Package dependencies
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub(crate) struct EncodableDependency {
/// Name of the dependency
pub(super) name: Name,
/// Version of the dependency
pub(super) version: Option<Version>,
/// Source for the dependency
pub(super) source: Option<EncodableSourceId>,
}
impl EncodableDependency {
/// Resolve this dependency, which in the V2 format may be abbreviated to
/// prevent merge conflicts
fn resolve(&self, packages: &[EncodablePackage]) -> Result<Dependency> {
for pkg in packages {
if pkg.name == self.name
&& (self.version.is_none() || self.version.as_ref() == Some(&pkg.version))
&& self.source.is_none()
{
return Ok(Dependency {
name: pkg.name.clone(),
version: pkg.version.clone(),
source: pkg.source.clone().map(|x| x.inner),
});
}
}
let version = self
.version
.clone()
.ok_or_else(|| Error::Parse(format!("couldn't resolve dependency: {}", self.name)))?;
Ok(Dependency {
name: self.name.clone(),
version,
source: self.source.clone().map(|x| x.inner),
})
}
/// Prepare `ResolveVersion::V2` dependencies by removing ones which are unambiguous
fn v2(&mut self, packages: &[Package]) {
let mut matching = vec![];
for package in packages {
if package.name == self.name {
matching.push(package);
}
}
if matching.len() == 1 {
// Unambiguous match by name, no need to specify version and source
self.version = None;
self.source = None;
return;
}
let Some(version) = self.version.as_ref() else {
// Version was already removed. This is unexpected. Maybe this function
// was already called before?
return;
};
if matching
.iter()
.filter(|package| &package.version == version)
.count()
== 1
{
// Unambiguous match by name and version, no need to specify source
self.source = None;
}
}
fn from_dependency(dep: &Dependency, version: ResolveVersion) -> Self {
Self {
name: dep.name.clone(),
version: Some(dep.version.clone()),
source: dep
.source
.clone()
.and_then(|id| encodable_source_id(id, version)),
}
}
}
/// Note: this only works for `ResolveVersion::V1` dependencies.
impl FromStr for EncodableDependency {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
let mut parts = s.split_whitespace();
let name = parts
.next()
.ok_or_else(|| Error::Parse("empty dependency string".to_owned()))?
.parse()?;
let version = parts.next().map(FromStr::from_str).transpose()?;
let source = parts
.next()
.map(|s| {
if s.len() < 2 || !s.starts_with('(') || !s.ends_with(')') {
Err(Error::Parse(format!("malformed source in dependency: {s}")))
} else {
s[1..(s.len() - 1)].parse::<SourceId>()
}
})
.transpose()?;
if parts.next().is_some() {
return Err(Error::Parse(format!("malformed dependency: {s}")));
}
Ok(Self {
name,
version,
// `EncodableDependency::from_str` is found only used by MetadataKey,
// which is only a thing in lockfile v1.
// Hence, no need for url encoding.
source: source.map(EncodableSourceId::without_url_encoded),
})
}
}
impl fmt::Display for EncodableDependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)?;
if let Some(version) = &self.version {
write!(f, " {version}")?;
}
if let Some(source) = &self.source {
write!(f, " ({})", source.as_url())?;
}
Ok(())
}
}
/// Note: this only works for `ResolveVersion::V1` dependencies.
impl TryFrom<&EncodableDependency> for Dependency {
type Error = Error;
fn try_from(raw_dependency: &EncodableDependency) -> Result<Self> {
raw_dependency.resolve(&[])
}
}
impl<'de> Deserialize<'de> for EncodableDependency {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> std::result::Result<Self, D::Error> {
String::deserialize(deserializer)?
.parse()
.map_err(de::Error::custom)
}
}
impl Serialize for EncodableDependency {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
/// Pretty much equivalent to [`SourceId`] with a different serialization method.
///
/// The serialization for `SourceId` doesn't do URL encode for parameters.
/// In contrast, this type is aware of that whenever [`ResolveVersion`] allows
/// us to do so (v4 or later).
#[derive(Deserialize, Debug, PartialOrd, Ord, Clone)]
#[serde(transparent)]
pub(super) struct EncodableSourceId {
inner: SourceId,
/// We don't care about the deserialization of this, as the `url` crate
/// will always decode as the URL was encoded.
#[serde(skip)]
encoded: bool,
}
impl EncodableSourceId {
/// Creates a `EncodableSourceId` that always encodes URL params.
fn new(inner: SourceId) -> Self {
Self {
inner,
encoded: true,
}
}
/// Creates a `EncodableSourceId` that doesn't encode URL params. This is
/// for backward compatibility for order lockfile version.
fn without_url_encoded(inner: SourceId) -> Self {
Self {
inner,
encoded: false,
}
}
/// Encodes the inner [`SourceId`] as a URL.
fn as_url(&self) -> impl fmt::Display + '_ {
self.inner.as_url(self.encoded)
}
}
impl std::ops::Deref for EncodableSourceId {
type Target = SourceId;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl Serialize for EncodableSourceId {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
serializer.collect_str(&self.as_url())
}
}
impl std::hash::Hash for EncodableSourceId {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state)
}
}
impl PartialEq for EncodableSourceId {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl Eq for EncodableSourceId {}
+105
View File
@@ -0,0 +1,105 @@
//! Lockfile versions
use super::encoding::EncodablePackage;
use crate::{
error::{Error, Result},
metadata::Metadata,
};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
/// Lockfile versions
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
#[non_exhaustive]
#[repr(u32)]
pub enum ResolveVersion {
/// Original `Cargo.lock` format which places checksums in the
/// `[[metadata]]` table.
V1 = 1,
/// Revised `Cargo.lock` format which is optimized to prevent merge
/// conflicts.
///
/// For more information, see:
/// <https://github.com/rust-lang/cargo/pull/7070>
V2 = 2,
/// Encodes Git dependencies with `branch = 'master'` in the manifest as
/// `?branch=master` in their URLs.
///
/// For more information, see:
/// <https://internals.rust-lang.org/t/upcoming-changes-to-cargo-lock/14017>
V3 = 3,
/// SourceId URL serialization is aware of URL encoding.
///
/// For more information, see:
/// <https://github.com/rust-lang/cargo/pull/12852>
V4 = 4,
}
impl ResolveVersion {
/// Autodetect the version of a lockfile from the packages
pub(super) fn detect(packages: &[EncodablePackage], metadata: &Metadata) -> Result<Self> {
// V1: look for [[metadata]] keys beginning with checksum
let is_v1 = metadata.keys().any(|key| key.is_checksum());
// V2: look for `checksum` fields in `[package]`
let is_v2 = packages.iter().any(|package| package.checksum.is_some());
if is_v1 && is_v2 {
return Err(Error::Parse("malformed lockfile: contains checksums in both [[package]] and [[metadata]] sections".to_string()));
}
if is_v1 {
Ok(Self::V1)
} else {
// Default to V2
Ok(Self::V2)
}
}
/// Should this version be explicitly encoded?
pub(super) fn is_explicit(self) -> bool {
u32::from(self) >= 3
}
}
/// V3 format is now the default.
impl Default for ResolveVersion {
fn default() -> Self {
Self::V3
}
}
impl From<ResolveVersion> for u32 {
fn from(version: ResolveVersion) -> Self {
version as Self
}
}
impl FromStr for ResolveVersion {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
u32::from_str(s)
.map_err(|_| Error::Parse(format!("invalid Cargo.lock format version: `{s}`")))
.and_then(Self::try_from)
}
}
impl TryFrom<u32> for ResolveVersion {
type Error = Error;
fn try_from(num: u32) -> Result<Self> {
match num {
1 => Ok(Self::V1),
2 => Ok(Self::V2),
3 => Ok(Self::V3),
4 => Ok(Self::V4),
_ => Err(Error::Parse(format!(
"invalid Cargo.lock format version: `{num}`"
))),
}
}
}
+260
View File
@@ -0,0 +1,260 @@
//! The `cargo lock` subcommand
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms, unused_qualifications)]
use cargo_lock::{
Dependency, Lockfile, Package, ResolveVersion, Version,
dependency::Tree,
dependency::graph::EdgeDirection,
package::{self},
};
use clap::Parser;
use petgraph::graph::NodeIndex;
use std::{
env, fs, io,
path::{Path, PathBuf},
process::exit,
str::FromStr,
};
/// `cargo lock` subcommands
#[derive(Debug, Parser)]
#[command(name = "cargo-lock")]
enum Command {
/// List packages in Cargo.lock
List(ListCmd),
/// Translate a Cargo.lock file
Translate(TranslateCmd),
/// Print a dependency tree for the given dependency
Tree(TreeCmd),
}
/// The `cargo lock list` subcommand
#[derive(Debug, Parser)]
struct ListCmd {
/// Input Cargo.lock file
#[arg(short, long)]
file: Option<PathBuf>,
/// Get information for a single package
#[arg(short, long)]
package: Option<package::Name>,
/// Show dependencies for each package
#[arg(short, long)]
dependencies: bool,
/// Show package sources in listing
#[arg(short, long)]
sources: bool,
}
impl ListCmd {
/// Display dependency summary from `Cargo.lock`
fn run(&self) {
for package in &load_lockfile(&self.file).packages {
if let Some(name) = &self.package {
if &package.name != name {
continue;
}
}
if self.sources {
println!("- {}", Dependency::from(package));
} else {
println!("- {} {}", package.name, package.version);
}
if self.dependencies {
for dep in &package.dependencies {
if self.sources {
println!(" - {}", dep);
} else {
println!(" - {} {}", dep.name, dep.version);
}
}
}
}
}
}
/// The `cargo lock translate` subcommand
#[derive(Debug, Parser)]
struct TranslateCmd {
/// Input Cargo.lock file to translate
#[arg(short, long)]
file: Option<PathBuf>,
/// Output Cargo.lock file (default STDOUT)
#[arg(short, long)]
output: Option<PathBuf>,
/// Cargo.lock resolve version to output
#[arg(short, long)]
version: Option<ResolveVersion>,
}
impl TranslateCmd {
/// Translate `Cargo.lock` to a different format version
fn run(&self) {
let output = self
.output
.as_ref()
.map(AsRef::as_ref)
.unwrap_or_else(|| Path::new("-"));
let mut lockfile = load_lockfile(&self.file);
lockfile.version = self.version.unwrap_or_default();
let lockfile_toml = lockfile.to_string();
if output == Path::new("-") {
println!("{}", lockfile_toml);
} else {
fs::write(output, lockfile_toml.as_bytes()).unwrap_or_else(|e| {
eprintln!("*** error: {}", e);
exit(1);
});
}
}
}
/// The `cargo lock tree` subcommand
#[derive(Debug, Parser)]
struct TreeCmd {
/// Input Cargo.lock file to translate
#[arg(short, long)]
file: Option<PathBuf>,
/// Show exact package identities (checksums or specific source versions) when available
#[arg(short = 'x', long)]
exact: bool,
/// Show inverse dependencies _on_ a package, rather than forward dependencies _of_ a package
#[arg(short, long = "invert")]
inverse: bool,
/// Dependency names or hashes to draw trees for
dependencies: Vec<String>,
}
fn package_matches_name(pkg: &Package, name: &str) -> bool {
pkg.name.as_str() == name
}
fn package_matches_ver(pkg: &Package, ver: &str) -> bool {
// Try interpreting ver as a semver string.
if let Ok(v) = Version::from_str(ver) {
return pkg.version == v;
}
// Try comparing ver to hashes in either the package checksum or the source
// precise field
if let Some(cksum) = &pkg.checksum {
if cksum.to_string() == ver {
return true;
}
}
if let Some(src) = &pkg.source {
if let Some(precise) = src.precise() {
if precise == ver {
return true;
}
}
}
false
}
fn package_matches(pkg: &Package, spec: &str) -> bool {
if let Some((name, ver)) = spec.split_once('@') {
package_matches_name(pkg, name) && package_matches_ver(pkg, ver)
} else {
package_matches_name(pkg, spec) || package_matches_ver(pkg, spec)
}
}
impl TreeCmd {
/// Display dependency trees from `Cargo.lock`
fn run(&self) {
let lockfile = load_lockfile(&self.file);
let tree = lockfile.dependency_tree().unwrap_or_else(|e| {
eprintln!("*** error: {}", e);
exit(1);
});
let indices: Vec<NodeIndex> = if self.dependencies.is_empty() {
tree.roots().to_vec()
} else {
self.dependencies
.iter()
.map(|dep| {
let package = lockfile
.packages
.iter()
.find(|pkg| package_matches(pkg, dep))
.unwrap_or_else(|| {
eprintln!("*** error: invalid dependency name: `{}`", dep);
exit(1);
});
tree.nodes()[&package.into()]
})
.collect()
};
self.dependency_tree(&tree, &indices);
}
/// Show dependency tree for the provided dependencies
fn dependency_tree(&self, tree: &Tree, indices: &[NodeIndex]) {
for (i, index) in indices.iter().enumerate() {
if i > 0 {
println!();
}
let direction = if self.inverse {
EdgeDirection::Incoming
} else {
EdgeDirection::Outgoing
};
tree.render(&mut io::stdout(), *index, direction, self.exact)
.unwrap();
}
}
}
/// Load a lockfile from the given path (or `Cargo.toml`)
fn load_lockfile(path: &Option<PathBuf>) -> Lockfile {
let path = path
.as_ref()
.map(AsRef::as_ref)
.unwrap_or_else(|| Path::new("Cargo.lock"));
Lockfile::load(path).unwrap_or_else(|e| {
eprintln!("*** error: {}", e);
exit(1);
})
}
fn main() {
let mut args = env::args().collect::<Vec<_>>();
// Remove the `lock` argument inserted by `cargo` when invoked as `cargo lock`
if args.get(1).map(String::as_str) == Some("lock") {
args.remove(1);
}
// If no command is specified, implicitly assume `list`
if args.len() < 2 || args[1].starts_with('-') {
ListCmd::parse_from(&args).run();
return;
}
// ...otherwise parse and run the subcommand
match Command::parse_from(&args) {
Command::List(list) => list.run(),
Command::Translate(translate) => translate.run(),
Command::Tree(tree) => tree.run(),
}
}
+142
View File
@@ -0,0 +1,142 @@
//! Package metadata
use crate::{
Checksum, Dependency, Map,
error::{Error, Result},
lockfile::encoding::EncodableDependency,
};
use serde::{Deserialize, Serialize, de, ser};
use std::{fmt, str::FromStr};
/// Prefix of metadata keys for checksum entries
const CHECKSUM_PREFIX: &str = "checksum ";
/// Package metadata
pub type Metadata = Map<MetadataKey, MetadataValue>;
/// Keys for the `[metadata]` table
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct MetadataKey(String);
impl MetadataKey {
/// Create a metadata key for a checksum for the given dependency
pub fn for_checksum(dep: &Dependency) -> Self {
Self(format!("{CHECKSUM_PREFIX}{dep}"))
}
/// Is this metadata key a checksum entry?
pub fn is_checksum(&self) -> bool {
self.0.starts_with(CHECKSUM_PREFIX)
}
/// Get the dependency for a particular checksum value (if applicable)
pub fn checksum_dependency(&self) -> Result<Dependency> {
self.try_into()
}
}
impl AsRef<str> for MetadataKey {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for MetadataKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for MetadataKey {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Ok(Self(s.to_owned()))
}
}
impl TryFrom<&MetadataKey> for Dependency {
type Error = Error;
fn try_from(key: &MetadataKey) -> Result<Self> {
if !key.is_checksum() {
return Err(Error::Parse(
"can only parse dependencies from `checksum` metadata".to_owned(),
));
}
let dep = EncodableDependency::from_str(&key.as_ref()[CHECKSUM_PREFIX.len()..])?;
(&dep).try_into()
}
}
impl<'de> Deserialize<'de> for MetadataKey {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> std::result::Result<Self, D::Error> {
String::deserialize(deserializer)?
.parse()
.map_err(de::Error::custom)
}
}
impl Serialize for MetadataKey {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
/// Values in the `[metadata]` table
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MetadataValue(String);
impl MetadataValue {
/// Get the associated checksum for this value (if applicable)
pub fn checksum(&self) -> Result<Checksum> {
self.try_into()
}
}
impl AsRef<str> for MetadataValue {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for MetadataValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for MetadataValue {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Ok(Self(s.to_owned()))
}
}
impl TryFrom<&MetadataValue> for Checksum {
type Error = Error;
fn try_from(value: &MetadataValue) -> Result<Self> {
value.as_ref().parse()
}
}
impl<'de> Deserialize<'de> for MetadataValue {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> std::result::Result<Self, D::Error> {
String::deserialize(deserializer)?
.parse()
.map_err(de::Error::custom)
}
}
impl Serialize for MetadataValue {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
+38
View File
@@ -0,0 +1,38 @@
//! Rust packages enumerated in `Cargo.lock`
mod checksum;
mod name;
mod source;
pub use self::{
checksum::Checksum,
name::Name,
source::{GitReference, SourceId, SourceKind},
};
pub use semver::Version;
use crate::dependency::Dependency;
use serde::{Deserialize, Serialize};
/// Information about a Rust package (as sourced from `Cargo.lock`)
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct Package {
/// Name of the package
pub name: Name,
/// Version of the package
pub version: Version,
/// Source identifier for the package
pub source: Option<SourceId>,
/// Checksum for this package
pub checksum: Option<Checksum>,
/// Dependencies of the package
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub dependencies: Vec<Dependency>,
/// Replace directive
pub replace: Option<Dependency>,
}
+130
View File
@@ -0,0 +1,130 @@
//! Package checksums (i.e. SHA-256 digests)
use crate::{Error, Result};
use serde::{Deserialize, Serialize, de, ser};
use std::{fmt, str::FromStr};
/// Cryptographic checksum (SHA-256) for a package
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Checksum {
/// SHA-256 digest of a package
Sha256([u8; 32]),
}
impl Checksum {
/// Is this checksum SHA-256?
pub fn is_sha256(&self) -> bool {
self.as_sha256().is_some()
}
/// If this is a SHA-256 checksum, get the raw bytes
pub fn as_sha256(&self) -> Option<[u8; 32]> {
match self {
Self::Sha256(digest) => Some(*digest),
}
}
}
impl From<[u8; 32]> for Checksum {
fn from(bytes: [u8; 32]) -> Self {
Self::Sha256(bytes)
}
}
impl FromStr for Checksum {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
if s.len() != 64 {
return Err(Error::Parse(format!(
"invalid checksum: expected 64 hex chars, got {}",
s.len()
)));
}
let mut digest = [0u8; 32];
for (i, byte) in digest.iter_mut().enumerate() {
*byte = u8::from_str_radix(&s[(i * 2)..=(i * 2) + 1], 16)?;
}
Ok(Self::Sha256(digest))
}
}
impl fmt::Debug for Checksum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sha256(_) => write!(f, "Sha256({self:x})"),
}
}
}
impl fmt::Display for Checksum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:x}")
}
}
impl fmt::LowerHex for Checksum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sha256(digest) => {
for b in digest {
write!(f, "{b:02x}")?;
}
}
}
Ok(())
}
}
impl fmt::UpperHex for Checksum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sha256(digest) => {
for b in digest {
write!(f, "{b:02X}")?;
}
}
}
Ok(())
}
}
impl<'de> Deserialize<'de> for Checksum {
fn deserialize<D: de::Deserializer<'de>>(
deserializer: D,
) -> std::result::Result<Self, D::Error> {
let hex = String::deserialize(deserializer)?;
hex.parse().map_err(de::Error::custom)
}
}
impl Serialize for Checksum {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::{Checksum, Error};
#[test]
fn checksum_round_trip() {
let checksum_str = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5";
let checksum = checksum_str.parse::<Checksum>().unwrap();
assert_eq!(checksum_str, checksum.to_string());
}
#[test]
fn invalid_checksum() {
// Missing one hex letter
let invalid_str = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f";
let error = invalid_str.parse::<Checksum>().err().unwrap();
assert!(matches!(error, Error::Parse(_)));
}
}
+43
View File
@@ -0,0 +1,43 @@
//! Package names
use crate::Error;
use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr};
/// Name of a Rust `[[package]]`
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct Name(String);
impl Name {
/// Get package name as an `&str`
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Name {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<Name> for String {
fn from(name: Name) -> Self {
name.0
}
}
impl FromStr for Name {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
// TODO(tarcieri): ensure name is valid
Ok(Self(s.into()))
}
}
+502
View File
@@ -0,0 +1,502 @@
//! Package source identifiers.
//!
//! Adapted from Cargo's `source_id.rs`:
//!
//! <https://github.com/rust-lang/cargo/blob/master/src/cargo/core/source/source_id.rs>
//!
//! Copyright (c) 2014 The Rust Project Developers
//! Licensed under the same terms as the `cargo-lock` crate: Apache 2.0 + MIT
use crate::error::{Error, Result};
use serde::{Deserialize, Serialize, de, ser};
use std::{
cmp::{Ord, Ordering},
fmt,
hash::Hash,
str::FromStr,
};
use url::Url;
#[cfg(any(unix, windows))]
use std::path::Path;
/// Location of the crates.io index
const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";
/// Location of the crates.io sparse HTTP index
const CRATES_IO_SPARSE_INDEX: &str = "sparse+https://index.crates.io/";
/// Unique identifier for a source of packages.
#[derive(Clone, Debug)]
pub struct SourceId {
/// The source URL.
url: Url,
/// The source kind.
kind: SourceKind,
/// For example, the exact Git revision of the specified branch for a Git Source.
precise: Option<String>,
/// Name of the registry source for alternative registries
name: Option<String>,
}
impl SourceId {
/// Creates a `SourceId` object from the kind and URL.
fn new(kind: SourceKind, url: Url) -> Result<Self> {
Ok(Self {
kind,
url,
precise: None,
name: None,
})
}
/// Parses a source URL and returns the corresponding ID.
///
/// ## Example
///
/// ```
/// use cargo_lock::SourceId;
/// SourceId::from_url("git+https://github.com/alexcrichton/\
/// libssh2-static-sys#80e71a3021618eb05\
/// 656c58fb7c5ef5f12bc747f");
/// ```
pub fn from_url(string: &str) -> Result<Self> {
let mut parts = string.splitn(2, '+');
let kind = parts.next().unwrap();
let url = parts
.next()
.ok_or_else(|| Error::Parse(format!("invalid source `{string}`")))?;
match kind {
"git" => {
let mut url = url.into_url()?;
let mut reference = GitReference::DefaultBranch;
for (k, v) in url.query_pairs() {
match &k[..] {
// Map older 'ref' to branch.
"branch" | "ref" => reference = GitReference::Branch(v.into_owned()),
"rev" => reference = GitReference::Rev(v.into_owned()),
"tag" => reference = GitReference::Tag(v.into_owned()),
_ => {}
}
}
let precise = url.fragment().map(|s| s.to_owned());
url.set_fragment(None);
url.set_query(None);
Ok(Self::for_git(&url, reference)?.with_precise(precise))
}
"registry" => {
let url = url.into_url()?;
Ok(Self::new(SourceKind::Registry, url)?.with_precise(Some("locked".to_string())))
}
"sparse" => {
let url = url.into_url()?;
Ok(Self::new(SourceKind::SparseRegistry, url)?
.with_precise(Some("locked".to_string())))
}
"path" => Self::new(SourceKind::Path, url.into_url()?),
kind => Err(Error::Parse(format!(
"unsupported source protocol: `{kind}` from `{string}`"
))),
}
}
/// Creates a `SourceId` from a filesystem path.
///
/// `path`: an absolute path.
#[cfg(any(unix, windows))]
pub fn for_path(path: &Path) -> Result<Self> {
Self::new(SourceKind::Path, path.into_url()?)
}
/// Creates a `SourceId` from a Git reference.
pub fn for_git(url: &Url, reference: GitReference) -> Result<Self> {
Self::new(SourceKind::Git(reference), url.clone())
}
/// Creates a SourceId from a remote registry URL.
pub fn for_registry(url: &Url) -> Result<Self> {
Self::new(SourceKind::Registry, url.clone())
}
/// Creates a SourceId from a local registry path.
#[cfg(any(unix, windows))]
pub fn for_local_registry(path: &Path) -> Result<Self> {
Self::new(SourceKind::LocalRegistry, path.into_url()?)
}
/// Creates a `SourceId` from a directory path.
#[cfg(any(unix, windows))]
pub fn for_directory(path: &Path) -> Result<Self> {
Self::new(SourceKind::Directory, path.into_url()?)
}
/// Gets this source URL.
pub fn url(&self) -> &Url {
&self.url
}
/// Get the kind of source.
pub fn kind(&self) -> &SourceKind {
&self.kind
}
/// Human-friendly description of an index
pub fn display_index(&self) -> String {
if self.is_default_registry() {
"crates.io index".to_string()
} else {
format!("`{}` index", self.url())
}
}
/// Human-friendly description of a registry name
pub fn display_registry_name(&self) -> String {
if self.is_default_registry() {
"crates.io".to_string()
} else if let Some(name) = &self.name {
name.clone()
} else {
self.url().to_string()
}
}
/// Returns `true` if this source is from a filesystem path.
pub fn is_path(&self) -> bool {
self.kind == SourceKind::Path
}
/// Returns `true` if this source is from a registry (either local or not).
pub fn is_registry(&self) -> bool {
matches!(
self.kind,
SourceKind::Registry | SourceKind::SparseRegistry | SourceKind::LocalRegistry
)
}
/// Returns `true` if this source is a "remote" registry.
///
/// "remote" may also mean a file URL to a git index, so it is not
/// necessarily "remote". This just means it is not `local-registry`.
pub fn is_remote_registry(&self) -> bool {
matches!(self.kind, SourceKind::Registry | SourceKind::SparseRegistry)
}
/// Returns `true` if this source from a Git repository.
pub fn is_git(&self) -> bool {
matches!(self.kind, SourceKind::Git(_))
}
/// Gets the value of the precise field.
pub fn precise(&self) -> Option<&str> {
self.precise.as_ref().map(AsRef::as_ref)
}
/// Gets the Git reference if this is a git source, otherwise `None`.
pub fn git_reference(&self) -> Option<&GitReference> {
if let SourceKind::Git(s) = &self.kind {
Some(s)
} else {
None
}
}
/// Creates a new `SourceId` from this source with the given `precise`.
pub fn with_precise(&self, v: Option<String>) -> Self {
Self {
precise: v,
..self.clone()
}
}
/// Returns `true` if the remote registry is the standard <https://crates.io>.
pub fn is_default_registry(&self) -> bool {
self.kind == SourceKind::Registry && self.url.as_str() == CRATES_IO_INDEX
|| self.kind == SourceKind::SparseRegistry
&& self.url.as_str() == &CRATES_IO_SPARSE_INDEX[7..]
}
/// A view of the [`SourceId`] that can be `Display`ed as a URL.
pub(crate) fn as_url(&self, encoded: bool) -> SourceIdAsUrl<'_> {
SourceIdAsUrl { id: self, encoded }
}
}
/// We've seen a number of subtle ways that dependency references (in `package.dependencies`)
/// can differ from the corresponding `package.source` field for git dependencies.
/// This `Ord` impl (which is used when storing `SourceId`s in a `BTreeMap`) tries to
/// account for these differences and treat them as equal.
///
/// The `package.source` field for a git dependency includes both the `tag`, `branch` or `rev`
/// (in a query string) used to fetch the dependency, as well as the full commit hash (in the
/// fragment), but the `package.dependencies` entry does not include the full commit hash.
///
/// Additionally, when the `rev` is specified for a dependency using a longer hash, the `rev`
/// used in the `package.source` may be an abbreviated hash.
impl Ord for SourceId {
fn cmp(&self, other: &Self) -> Ordering {
match self.url.cmp(&other.url) {
Ordering::Equal => {}
non_eq => return non_eq,
}
match self.name.cmp(&other.name) {
Ordering::Equal => {}
non_eq => return non_eq,
}
// Some special handling for git sources follows...
match (&self.kind, &other.kind) {
(SourceKind::Git(s), SourceKind::Git(o)) => (s, o),
(a, b) => return a.cmp(b),
};
if let (Some(s), Some(o)) = (&self.precise, &other.precise) {
// If the git hash is the same, we consider the sources equal
return s.cmp(o);
}
Ordering::Equal
}
}
impl PartialOrd for SourceId {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for SourceId {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.url.hash(state);
self.kind.hash(state);
self.precise.hash(state);
self.name.hash(state);
}
}
impl PartialEq for SourceId {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for SourceId {}
impl Serialize for SourceId {
fn serialize<S: ser::Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
if self.is_path() {
None::<String>.serialize(s)
} else {
s.collect_str(&self.to_string())
}
}
}
impl<'de> Deserialize<'de> for SourceId {
fn deserialize<D: de::Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
let string = String::deserialize(d)?;
Self::from_url(&string).map_err(de::Error::custom)
}
}
impl FromStr for SourceId {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
Self::from_url(s)
}
}
impl fmt::Display for SourceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_url(false).fmt(f)
}
}
impl Default for SourceId {
fn default() -> Self {
Self::for_registry(&CRATES_IO_INDEX.into_url().unwrap()).unwrap()
}
}
/// The possible kinds of code source.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SourceKind {
/// A git repository.
Git(GitReference),
/// A local path..
Path,
/// A remote registry.
Registry,
/// A sparse registry.
SparseRegistry,
/// A local filesystem-based registry.
LocalRegistry,
/// A directory-based registry.
#[cfg(any(unix, windows))]
Directory,
}
/// A `Display`able view into a `SourceId` that will write it as a url
pub(crate) struct SourceIdAsUrl<'a> {
id: &'a SourceId,
encoded: bool,
}
impl fmt::Display for SourceIdAsUrl<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.id {
SourceId {
kind: SourceKind::Path,
url,
..
} => write!(f, "path+{url}"),
SourceId {
kind: SourceKind::Git(reference),
url,
precise,
..
} => {
write!(f, "git+{url}")?;
// TODO: set it to true when the default is lockfile v4,
if let Some(pretty) = reference.pretty_ref(self.encoded) {
write!(f, "?{pretty}")?;
}
if let Some(precise) = precise.as_ref() {
write!(f, "#{precise}")?;
}
Ok(())
}
SourceId {
kind: SourceKind::Registry,
url,
..
} => write!(f, "registry+{url}"),
SourceId {
kind: SourceKind::SparseRegistry,
url,
..
} => write!(f, "sparse+{url}"),
SourceId {
kind: SourceKind::LocalRegistry,
url,
..
} => write!(f, "local-registry+{url}"),
#[cfg(any(unix, windows))]
SourceId {
kind: SourceKind::Directory,
url,
..
} => write!(f, "directory+{url}"),
}
}
}
/// Information to find a specific commit in a Git repository.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GitReference {
/// The default branch of the repository, the reference named `HEAD`.
DefaultBranch,
/// From a tag.
Tag(String),
/// From the HEAD of a branch.
Branch(String),
/// From a specific revision.
Rev(String),
}
impl GitReference {
/// Returns a `Display`able view of this git reference, or None if using
/// the head of the default branch
pub fn pretty_ref(&self, url_encoded: bool) -> Option<impl fmt::Display + '_> {
match self {
Self::DefaultBranch => None,
_ => Some(PrettyRef {
inner: self,
url_encoded,
}),
}
}
}
/// A git reference that can be `Display`ed
struct PrettyRef<'a> {
inner: &'a GitReference,
url_encoded: bool,
}
impl fmt::Display for PrettyRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value: &str = match self.inner {
GitReference::DefaultBranch => return Ok(()),
GitReference::Branch(s) => {
write!(f, "branch=")?;
s
}
GitReference::Tag(s) => {
write!(f, "tag=")?;
s
}
GitReference::Rev(s) => {
write!(f, "rev=")?;
s
}
};
if self.url_encoded {
for value in url::form_urlencoded::byte_serialize(value.as_bytes()) {
write!(f, "{value}")?;
}
} else {
write!(f, "{value}")?;
}
Ok(())
}
}
/// A type that can be converted to a Url
trait IntoUrl {
/// Performs the conversion
fn into_url(self) -> Result<Url>;
}
impl IntoUrl for &str {
fn into_url(self) -> Result<Url> {
Url::parse(self).map_err(|s| Error::Parse(format!("invalid url `{self}`: {s}")))
}
}
#[cfg(any(unix, windows))]
impl IntoUrl for &Path {
fn into_url(self) -> Result<Url> {
Url::from_file_path(self)
.map_err(|_| Error::Parse(format!("invalid path url `{}`", self.display())))
}
}
#[cfg(test)]
mod tests {
use super::SourceId;
#[test]
fn identifies_crates_io() {
assert!(SourceId::default().is_default_registry());
assert!(
SourceId::from_url(super::CRATES_IO_SPARSE_INDEX)
.expect("failed to parse sparse URL")
.is_default_registry()
);
}
}
+18
View File
@@ -0,0 +1,18 @@
//! The `[[patch]]` section
use crate::dependency::Dependency;
use serde::{Deserialize, Serialize};
/// The `[[patch]]` section of `Cargo.lock`
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct Patch {
/// Unused patches
pub unused: Vec<Dependency>,
}
impl Patch {
/// Is the `[patch]` section empty?
pub fn is_empty(&self) -> bool {
self.unused.is_empty()
}
}
+221
View File
@@ -0,0 +1,221 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cargo-lock"
version = "7.0.1"
dependencies = [
"gumdrop",
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "gumdrop"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3"
dependencies = [
"gumdrop_derive",
]
[[package]]
name = "gumdrop_derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
@@ -0,0 +1,39 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
# NOTE: This lockfile is artificial for testing purposes,
# and doesn't come from a real world example.
version = 3
[[package]]
name = "foo"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
dependencies = [
"branch 0.0.0",
"branch 0.0.0 (git+https://github.com/rustsec/rustsec?branch=mybranch)",
"tag 0.0.0",
"tag 0.0.0 (git+https://github.com/rustsec/rustsec?tag=mytag)",
]
[[package]]
name = "branch"
version = "0.0.0"
source = "git+https://github.com/rustsec/rustsec?branch=mybranch#b8e3025aa30ea65144372bd68d26090c0f31bea2"
[[package]]
name = "branch"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "tag"
version = "0.0.0"
source = "git+https://github.com/rustsec/rustsec?tag=mytag#c460e54ecd66a5da8d9725ee419b5199b552e0e6"
[[package]]
name = "tag"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
@@ -0,0 +1,47 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "foo"
version = "0.1.0"
dependencies = [
"tracing-tracy",
"tracy-client 0.15.0 (git+https://github.com/nagisa/rust_tracy_client?rev=tracy-client-v0.15.0)",
]
[[package]]
name = "tracing-tracy"
version = "0.10.1"
source = "git+https://github.com/nagisa/rust_tracy_client?rev=tracing-tracy-v0.10.1#d15b1ea01c6c9a496c2f169a212acd5b17fd0b1a"
dependencies = [
"tracy-client 0.15.0 (git+https://github.com/nagisa/rust_tracy_client?rev=tracing-tracy-v0.10.1)",
]
[[package]]
name = "tracy-client"
version = "0.15.0"
source = "git+https://github.com/nagisa/rust_tracy_client?rev=tracing-tracy-v0.10.1#d15b1ea01c6c9a496c2f169a212acd5b17fd0b1a"
dependencies = [
"tracy-client-sys 0.19.0 (git+https://github.com/nagisa/rust_tracy_client?rev=tracing-tracy-v0.10.1)",
]
[[package]]
name = "tracy-client"
version = "0.15.0"
source = "git+https://github.com/nagisa/rust_tracy_client?rev=tracy-client-v0.15.0#d15b1ea01c6c9a496c2f169a212acd5b17fd0b1a"
dependencies = [
"tracy-client-sys 0.19.0 (git+https://github.com/nagisa/rust_tracy_client?rev=tracy-client-v0.15.0)",
]
[[package]]
name = "tracy-client-sys"
version = "0.19.0"
source = "git+https://github.com/nagisa/rust_tracy_client?rev=tracing-tracy-v0.10.1#d15b1ea01c6c9a496c2f169a212acd5b17fd0b1a"
dependencies = []
[[package]]
name = "tracy-client-sys"
version = "0.19.0"
source = "git+https://github.com/nagisa/rust_tracy_client?rev=tracy-client-v0.15.0#d15b1ea01c6c9a496c2f169a212acd5b17fd0b1a"
dependencies = []
@@ -0,0 +1,21 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "rust-example"
version = "0.1.0"
dependencies = [
"bitflags",
]
[[patch.unused]]
name = "ryu"
version = "1.0.23"
source = "git+https://github.com/dtolnay/ryu?rev=f0b52bb194befe6fd242154f2182fafd43a819b8#f0b52bb194befe6fd242154f2182fafd43a819b8"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,220 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cargo-lock"
version = "7.0.1"
dependencies = [
"gumdrop",
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "gumdrop"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3"
dependencies = [
"gumdrop_derive",
]
[[package]]
name = "gumdrop_derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
@@ -0,0 +1,221 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cargo-lock"
version = "7.0.1"
dependencies = [
"gumdrop",
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "gumdrop"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3"
dependencies = [
"gumdrop_derive",
]
[[package]]
name = "gumdrop_derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
@@ -0,0 +1,221 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cargo-lock"
version = "7.0.1"
dependencies = [
"gumdrop",
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "gumdrop"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3"
dependencies = [
"gumdrop_derive",
]
[[package]]
name = "gumdrop_derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "semver"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.8.14"
source = "git+https://github.com/weihanglo/toml.git?branch=a-_%2B%23%24%29z#9e406273177740fa85b86b78e6d5105e932edef0"
dependencies = [
"serde",
"serde_spanned 0.6.6",
"toml_datetime 0.6.6",
"toml_edit 0.22.14",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.5.2"
source = "git+https://github.com/weihanglo/rust-url.git?tag=a-_%2B%23%24%29z#54346fa288e16b25b71c45149d7067c752b450e0"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
@@ -0,0 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rustsec/rustsec"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "bytestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a"
dependencies = [
"bytes 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"bytes 1.2.1 (registry+https://github.com/rustsec/rustsec)",
"bytestring",
]
@@ -0,0 +1,31 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "bytes"
version = "1.2.1"
source = "git+https://github.com/rustsec/rustsec#19152556777da5248ee0e7b562fdb37c76457c4b"
[[package]]
name = "bytestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a"
dependencies = [
"bytes 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"bytes 1.2.1 (git+https://github.com/rustsec/rustsec)",
"bytestring",
]
@@ -0,0 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "0.6.0"
source = "registry+https://github.com/rustsec/rustsec"
checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16"
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "bytestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a"
dependencies = [
"bytes 1.2.1",
]
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"bytes 0.6.0",
"bytestring",
]
@@ -0,0 +1,31 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "0.6.0"
source = "git+https://github.com/rustsec/rustsec#d6629dbc30725ed892f781042adb3393a43ad4be"
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "bytestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a"
dependencies = [
"bytes 1.2.1",
]
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"bytes 0.6.0",
"bytestring",
]
@@ -0,0 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16"
[[package]]
name = "bytes"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "bytestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a"
dependencies = [
"bytes 1.2.1",
]
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"bytes 0.6.0",
"bytestring",
]
@@ -0,0 +1,14 @@
# Source disambiguation test files
This directory holds example `Cargo.lock` files generated by `cargo`. The lock files are intended to exercise `cargo-lock` code paths related to the disambiguation of dependency specifications when the lock file contains multiple versions of the same crate and/or multiple sources for the same crate.
The following examples are provided, specifically:
* **single_version_different_registries** - The lock file has one version of a crate, from two different registries. The registries are expected to be encoded by `cargo-lock`, since they are needed for disambiguation.
* **single_version_different_source_types** - The lock file has one version of a crate, from two different sources: one from git, one from a registry. The sources are expected to be encoded by `cargo-lock`, since they are needed for disambiguation.
* **two_versions_different_registries** - The lock file has two versions of a crate, each from a different registry. The registries are **not** expected to be encoded by `cargo-lock`, since they are not needed for disambiguation.
* **two_versions_different_source_types** - The lock file has two versions of a crate, from two different sources: one from git, one from a registry. The sources are **not** expected to be encoded by `cargo-lock`, since they are not needed for disambiguation.
* **two_versions_same_registry** - The lock file has two versions of a crate, both from the same registry. The registry is **not** expected to be encoded by `cargo-lock`, since it is not needed for disambiguation.
+324
View File
@@ -0,0 +1,324 @@
//! Lockfile integration test
use std::fs;
use std::str::FromStr;
// TODO(tarcieri): add more example `Cargo.lock` files which cover more scenarios
use cargo_lock::{
Lockfile, MetadataKey, ResolveVersion, Version,
package::{GitReference, SourceKind},
};
/// Path to a V1 `Cargo.lock` file.
const V1_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v1";
/// Path to a V2 `Cargo.lock` file.
const V2_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v2";
/// Path to a V3 `Cargo.lock` file.
const V3_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v3";
/// Path to a V4 `Cargo.lock` file.
const V4_LOCKFILE_PATH: &str = "tests/examples/Cargo.lock.v4";
/// Load example V1 `Cargo.lock` file (from the Cargo project itself)
#[test]
fn load_example_v1_lockfile() {
let lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
assert_eq!(lockfile.version, ResolveVersion::V1);
assert_eq!(lockfile.packages.len(), 141);
assert_eq!(lockfile.metadata.len(), 136);
let package = &lockfile.packages[0];
assert_eq!(package.name.as_ref(), "adler32");
assert_eq!(package.version, Version::parse("1.0.4").unwrap());
let metadata_key: MetadataKey =
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)"
.parse()
.unwrap();
let metadata_value = &lockfile.metadata[&metadata_key];
assert_eq!(
metadata_value.as_ref(),
"5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
);
}
/// Load example V2 `Cargo.lock` file
#[test]
fn load_example_v2_lockfile() {
let lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
assert_eq!(lockfile.version, ResolveVersion::V2);
assert_eq!(lockfile.packages.len(), 25);
assert_eq!(lockfile.metadata.len(), 0);
}
/// Load example V3 `Cargo.lock` file
#[test]
fn load_example_v3_lockfile() {
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
assert_eq!(lockfile.version, ResolveVersion::V3);
assert_eq!(lockfile.packages.len(), 25);
assert_eq!(lockfile.metadata.len(), 0);
}
/// Ensure V3 lockfiles encode their version correctly.
#[test]
fn serialize_v3() {
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
let reserialized = lockfile.to_string();
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
assert_eq!(lockfile2.version, ResolveVersion::V3);
assert_eq!(lockfile2.packages, lockfile.packages);
}
/// Load example V4 `Cargo.lock` file
#[test]
fn load_example_v4_lockfile() {
let lockfile = Lockfile::load(V4_LOCKFILE_PATH).unwrap();
assert_eq!(lockfile.version, ResolveVersion::V4);
assert_eq!(lockfile.packages.len(), 25);
assert_eq!(lockfile.metadata.len(), 0);
let source_kind = lockfile
.packages
.iter()
.find(|pkg| pkg.name.as_str() == "url")
.and_then(|pkg| pkg.source.as_ref())
.map(|id| id.kind())
.unwrap();
assert_eq!(
source_kind,
&SourceKind::Git(GitReference::Tag("a-_+#$)z".into()))
);
let source_kind = lockfile
.packages
.iter()
.find(|pkg| pkg.name.as_str() == "toml")
.and_then(|pkg| pkg.source.as_ref())
.map(|id| id.kind())
.unwrap();
assert_eq!(
source_kind,
&SourceKind::Git(GitReference::Branch("a-_+#$)z".into()))
);
}
/// Ensure V4 lockfiles encode their version correctly.
#[test]
fn serialize_v4() {
let lockfile = Lockfile::load(V4_LOCKFILE_PATH).unwrap();
let reserialized = lockfile.to_string();
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
assert_eq!(lockfile2.version, ResolveVersion::V4);
assert_eq!(lockfile2.packages, lockfile.packages);
}
/// Ensure we can serialize a V2 lockfile as a V1 lockfile
#[test]
fn serialize_v2_to_v1() {
let mut lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
lockfile.version = ResolveVersion::V1;
let reserialized = lockfile.to_string();
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
assert_eq!(lockfile2.version, ResolveVersion::V1);
assert_eq!(lockfile2.packages, lockfile.packages);
}
/// Ensure we can serialize a V1 lockfile as a V2 lockfile
#[test]
fn serialize_v1_to_v2() {
let mut lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
lockfile.version = ResolveVersion::V2;
let reserialized = lockfile.to_string();
let lockfile2 = reserialized.parse::<Lockfile>().unwrap();
assert_eq!(lockfile.packages, lockfile2.packages);
}
/// Test that encoded V1 lockfiles match what Cargo would normally write.
#[test]
fn serde_matches_v1() {
let lockfile = Lockfile::load(V1_LOCKFILE_PATH).unwrap();
let reserialized = lockfile.to_string();
let file_content = fs::read_to_string(V1_LOCKFILE_PATH).unwrap();
assert_eq!(reserialized, file_content);
}
/// Test that encoded V2 lockfiles match what Cargo would normally write.
#[test]
fn serde_matches_v2() {
let lockfile = Lockfile::load(V2_LOCKFILE_PATH).unwrap();
let reserialized = lockfile.to_string();
let file_content = fs::read_to_string(V2_LOCKFILE_PATH).unwrap();
assert_eq!(reserialized, file_content);
}
/// Test that encoded V3 lockfiles match what Cargo would normally write.
#[test]
fn serde_matches_v3() {
let lockfile = Lockfile::load(V3_LOCKFILE_PATH).unwrap();
let reserialized = lockfile.to_string();
let file_content = fs::read_to_string(V3_LOCKFILE_PATH).unwrap();
assert_eq!(reserialized, file_content);
}
/// Test that encoded lockfiles with unused patch match what Cargo would normally write.
#[test]
fn serde_matches_unused_patch() {
let file_path = "tests/examples/Cargo.lock.unused-patch";
let lockfile = Lockfile::load(file_path).unwrap();
let reserialized = lockfile.to_string();
let file_content = fs::read_to_string(file_path).unwrap();
assert_eq!(reserialized, file_content);
}
/// Dependency tree tests
#[cfg(feature = "dependency-tree")]
mod tree {
use super::{Lockfile, V1_LOCKFILE_PATH, V2_LOCKFILE_PATH};
/// Compute a dependency graph from a non-trivial example V1 `Cargo.lock`
#[test]
fn compute_from_v1_example_lockfile() {
let tree = Lockfile::load(V1_LOCKFILE_PATH)
.unwrap()
.dependency_tree()
.unwrap();
assert_eq!(tree.nodes().len(), 141);
}
/// Compute a dependency graph from a non-trivial example V2 `Cargo.lock`
#[test]
fn compute_from_v2_example_lockfile() {
let tree = Lockfile::load(V2_LOCKFILE_PATH)
.unwrap()
.dependency_tree()
.unwrap();
assert_eq!(tree.nodes().len(), 25);
}
}
#[test]
fn source_disambiguation_single_version_different_registries() {
source_disambiguation("single_version_different_registries");
}
#[test]
fn source_disambiguation_single_version_different_source_types() {
source_disambiguation("single_version_different_source_types");
}
#[test]
fn source_disambiguation_two_versions_different_registries() {
source_disambiguation("two_versions_different_registries");
}
#[test]
fn source_disambiguation_two_versions_different_source_types() {
source_disambiguation("two_versions_different_source_types");
}
#[test]
fn source_disambiguation_two_versions_same_registry() {
source_disambiguation("two_versions_same_registry");
}
/// Test logic related to the disambiguation of dependency specifications when
/// the lock file contains multiple versions of the same crate and/or multiple
/// sources for the same crate.
fn source_disambiguation(test_file_suffix: &str) {
let original = fs::read_to_string(format!(
"tests/examples/source_disambiguation/Cargo.lock.{}",
test_file_suffix
))
.unwrap();
let re_encoded = Lockfile::from_str(&original).unwrap().to_string();
assert_eq!(original, re_encoded);
}
/// Test that a lockfile with git sources are correctly encoded
#[test]
fn encoding_registry_and_git() {
let lockfile = r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "tower-buffer"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a"
dependencies = [
"tracing 0.1.35",
]
[[package]]
name = "tracing"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
[[package]]
name = "tracing"
version = "0.2.0"
source = "git+https://github.com/tokio-rs/tracing.git?rev=1e09e50e8d15580b5929adbade9c782a6833e4a0#1e09e50e8d15580b5929adbade9c782a6833e4a0"
[[package]]
name = "example"
version = "0.1.0"
dependencies = [
"tower-buffer",
"tracing 0.2.0",
]
"#;
assert_eq!(lockfile, Lockfile::from_str(lockfile).unwrap().to_string(),);
}
#[cfg(feature = "dependency-tree")]
#[test]
fn hash_fragment_dep() {
use cargo_lock::Lockfile;
let lockfile_str = r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "parent"
version = "0.1.0"
source = "git+https://github.com/nope/parent?rev=xxxx#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
dependencies = [
"child 0.1.0 (git+https://github.com/nope/child?rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)",
"child 0.1.0 (git+https://github.com/nope/child?rev=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb)",
]
[[package]]
name = "child"
version = "0.1.0"
source = "git+https://github.com/nope/child?rev=aaaa#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[[package]]
name = "child"
version = "0.1.0"
source = "git+https://github.com/nope/child?rev=bbbb#bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
"#;
let lockfile = Lockfile::from_str(lockfile_str).unwrap();
assert_eq!(lockfile_str, lockfile.to_string(),);
// This will fail to resolve if child source URLs aren't normalized when deriving
// dependencies from packges.
let _tree = cargo_lock::dependency::tree::Tree::new(&lockfile).unwrap();
}