Skip to content

Commit a7fcef2

Browse files
committed
refactor: move IndexPackage and RegistryDependency to cargo-util-schemas for better modularity
Signed-off-by: 0xPoe <[email protected]>
1 parent dfcf4c2 commit a7fcef2

File tree

6 files changed

+243
-238
lines changed

6 files changed

+243
-238
lines changed

crates/cargo-util-schemas/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ workspace = true
2525

2626
[dev-dependencies]
2727
snapbox.workspace = true
28+
serde_json.workspace = true
2829

2930
[features]
3031
unstable-schema = ["dep:schemars", "dep:serde_json"]
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use crate::manifest::RustVersion;
2+
use semver::Version;
3+
use serde::{Deserialize, Serialize};
4+
use std::{borrow::Cow, collections::BTreeMap};
5+
6+
/// A single line in the index representing a single version of a package.
7+
#[derive(Deserialize, Serialize)]
8+
pub struct IndexPackage<'a> {
9+
/// Name of the package.
10+
#[serde(borrow)]
11+
pub name: Cow<'a, str>,
12+
/// The version of this dependency.
13+
pub vers: Version,
14+
/// All kinds of direct dependencies of the package, including dev and
15+
/// build dependencies.
16+
#[serde(borrow)]
17+
pub deps: Vec<RegistryDependency<'a>>,
18+
/// Set of features defined for the package, i.e., `[features]` table.
19+
#[serde(default)]
20+
pub features: BTreeMap<Cow<'a, str>, Vec<Cow<'a, str>>>,
21+
/// This field contains features with new, extended syntax. Specifically,
22+
/// namespaced features (`dep:`) and weak dependencies (`pkg?/feat`).
23+
///
24+
/// This is separated from `features` because versions older than 1.19
25+
/// will fail to load due to not being able to parse the new syntax, even
26+
/// with a `Cargo.lock` file.
27+
pub features2: Option<BTreeMap<Cow<'a, str>, Vec<Cow<'a, str>>>>,
28+
/// Checksum for verifying the integrity of the corresponding downloaded package.
29+
pub cksum: String,
30+
/// If `true`, Cargo will skip this version when resolving.
31+
///
32+
/// This was added in 2014. Everything in the crates.io index has this set
33+
/// now, so this probably doesn't need to be an option anymore.
34+
pub yanked: Option<bool>,
35+
/// Native library name this package links to.
36+
///
37+
/// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>),
38+
/// can be `None` if published before then.
39+
pub links: Option<Cow<'a, str>>,
40+
/// Required version of rust
41+
///
42+
/// Corresponds to `package.rust-version`.
43+
///
44+
/// Added in 2023 (see <https://github.com/rust-lang/crates.io/pull/6267>),
45+
/// can be `None` if published before then or if not set in the manifest.
46+
pub rust_version: Option<RustVersion>,
47+
/// The schema version for this entry.
48+
///
49+
/// If this is None, it defaults to version `1`. Entries with unknown
50+
/// versions are ignored.
51+
///
52+
/// Version `2` schema adds the `features2` field.
53+
///
54+
/// Version `3` schema adds `artifact`, `bindep_targes`, and `lib` for
55+
/// artifact dependencies support.
56+
///
57+
/// This provides a method to safely introduce changes to index entries
58+
/// and allow older versions of cargo to ignore newer entries it doesn't
59+
/// understand. This is honored as of 1.51, so unfortunately older
60+
/// versions will ignore it, and potentially misinterpret version 2 and
61+
/// newer entries.
62+
///
63+
/// The intent is that versions older than 1.51 will work with a
64+
/// pre-existing `Cargo.lock`, but they may not correctly process `cargo
65+
/// update` or build a lock from scratch. In that case, cargo may
66+
/// incorrectly select a new package that uses a new index schema. A
67+
/// workaround is to downgrade any packages that are incompatible with the
68+
/// `--precise` flag of `cargo update`.
69+
pub v: Option<u32>,
70+
}
71+
72+
/// A dependency as encoded in the [`IndexPackage`] index JSON.
73+
#[derive(Deserialize, Serialize, Clone)]
74+
pub struct RegistryDependency<'a> {
75+
/// Name of the dependency. If the dependency is renamed, the original
76+
/// would be stored in [`RegistryDependency::package`].
77+
#[serde(borrow)]
78+
pub name: Cow<'a, str>,
79+
/// The SemVer requirement for this dependency.
80+
#[serde(borrow)]
81+
pub req: Cow<'a, str>,
82+
/// Set of features enabled for this dependency.
83+
#[serde(default)]
84+
pub features: Vec<Cow<'a, str>>,
85+
/// Whether or not this is an optional dependency.
86+
#[serde(default)]
87+
pub optional: bool,
88+
/// Whether or not default features are enabled.
89+
#[serde(default = "default_true")]
90+
pub default_features: bool,
91+
/// The target platform for this dependency.
92+
pub target: Option<Cow<'a, str>>,
93+
/// The dependency kind. "dev", "build", and "normal".
94+
pub kind: Option<Cow<'a, str>>,
95+
// The URL of the index of the registry where this dependency is from.
96+
// `None` if it is from the same index.
97+
pub registry: Option<Cow<'a, str>>,
98+
/// The original name if the dependency is renamed.
99+
pub package: Option<Cow<'a, str>>,
100+
/// Whether or not this is a public dependency. Unstable. See [RFC 1977].
101+
///
102+
/// [RFC 1977]: https://rust-lang.github.io/rfcs/1977-public-private-dependencies.html
103+
pub public: Option<bool>,
104+
pub artifact: Option<Vec<Cow<'a, str>>>,
105+
pub bindep_target: Option<Cow<'a, str>>,
106+
#[serde(default)]
107+
pub lib: bool,
108+
}
109+
110+
fn default_true() -> bool {
111+
true
112+
}
113+
114+
#[test]
115+
fn escaped_char_in_index_json_blob() {
116+
let _: IndexPackage<'_> = serde_json::from_str(
117+
r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{}}"#,
118+
)
119+
.unwrap();
120+
let _: IndexPackage<'_> = serde_json::from_str(
121+
r#"{"name":"a","vers":"0.0.1","deps":[],"cksum":"bae3","features":{"test":["k","q"]},"links":"a-sys"}"#
122+
).unwrap();
123+
124+
// Now we add escaped cher all the places they can go
125+
// these are not valid, but it should error later than json parsing
126+
let _: IndexPackage<'_> = serde_json::from_str(
127+
r#"{
128+
"name":"This name has a escaped cher in it \n\t\" ",
129+
"vers":"0.0.1",
130+
"deps":[{
131+
"name": " \n\t\" ",
132+
"req": " \n\t\" ",
133+
"features": [" \n\t\" "],
134+
"optional": true,
135+
"default_features": true,
136+
"target": " \n\t\" ",
137+
"kind": " \n\t\" ",
138+
"registry": " \n\t\" "
139+
}],
140+
"cksum":"bae3",
141+
"features":{"test \n\t\" ":["k \n\t\" ","q \n\t\" "]},
142+
"links":" \n\t\" "}"#,
143+
)
144+
.unwrap();
145+
}

crates/cargo-util-schemas/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! > ecosystem. This crate follows semver compatibility for its APIs.
1010
1111
pub mod core;
12+
pub mod index;
1213
pub mod manifest;
1314
pub mod messages;
1415
#[cfg(feature = "unstable-schema")]

src/cargo/ops/cargo_package/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
1919
use crate::ops::lockfile::LOCKFILE_NAME;
2020
use crate::ops::registry::{RegistryOrIndex, infer_registry};
2121
use crate::sources::path::PathEntry;
22-
use crate::sources::registry::index::{IndexPackage, RegistryDependency};
2322
use crate::sources::{CRATES_IO_REGISTRY, PathSource};
2423
use crate::util::FileLock;
2524
use crate::util::Filesystem;
@@ -35,6 +34,7 @@ use crate::util::toml::prepare_for_publish;
3534
use crate::{drop_println, ops};
3635
use anyhow::{Context as _, bail};
3736
use cargo_util::paths;
37+
use cargo_util_schemas::index::{IndexPackage, RegistryDependency};
3838
use cargo_util_schemas::messages;
3939
use flate2::{Compression, GzBuilder};
4040
use tar::{Builder, EntryType, Header, HeaderMode};

0 commit comments

Comments
 (0)