docs: Add Lockfile schemas docs (#15989)

### What does this PR try to resolve?

Add documentation efforts to the lockfile schemas.

Continuation of #15980

### How to test and review this PR?
This commit is contained in:
Weihang Lo 2025-09-20 01:40:06 +00:00 committed by GitHub
commit ee515e6def
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 88 additions and 15 deletions

View File

@ -1,10 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TomlLockfile",
"description": "The `Cargo.lock` structure.",
"description": "Serialization of `Cargo.lock`",
"type": "object",
"properties": {
"version": {
"description": "The lockfile format version (`version =` field).\n\nThis field is optional for backward compatibility. Older lockfiles, i.e. V1 and V2, does\nnot have the version field serialized.",
"type": [
"integer",
"null"
@ -13,6 +14,7 @@
"minimum": 0
},
"package": {
"description": "The list of `[[package]]` entries describing each resolved dependency.",
"type": [
"array",
"null"
@ -22,7 +24,7 @@
}
},
"root": {
"description": "`root` is optional to allow backward compatibility.",
"description": "The `[root]` table describing the root package.\n\nThis field is optional for backward compatibility. Older lockfiles have the root package\nseparated, whereas newer lockfiles have the root package as part of `[[package]]`.",
"anyOf": [
{
"$ref": "#/$defs/TomlLockfileDependency"
@ -33,6 +35,7 @@
]
},
"metadata": {
"description": "The `[metadata]` table\n\n\nIn older lockfile versions, dependency checksums were stored here instead of alongside each\npackage entry.",
"type": [
"object",
"null"
@ -42,32 +45,43 @@
}
},
"patch": {
"description": "The `[patch]` table describing unused patches.\n\nThe lockfile stores them as a list of `[[patch.unused]]` entries.",
"$ref": "#/$defs/TomlLockfilePatch"
}
},
"$defs": {
"TomlLockfileDependency": {
"description": "Serialization of lockfiles dependencies",
"type": "object",
"properties": {
"name": {
"description": "The name of the dependency.",
"type": "string"
},
"version": {
"description": "The version of the dependency.",
"type": "string"
},
"source": {
"type": [
"string",
"null"
"description": "The source of the dependency.\n\nCargo does not serialize path dependencies.",
"anyOf": [
{
"$ref": "#/$defs/TomlLockfileSourceId"
},
{
"type": "null"
}
]
},
"checksum": {
"description": "The checksum of the dependency.\n\nIn older lockfiles, checksums were not stored here and instead on a separate `[metadata]`\ntable (see [`TomlLockfileMetadata`]).",
"type": [
"string",
"null"
]
},
"dependencies": {
"description": "The transitive dependencies used by this dependency.",
"type": [
"array",
"null"
@ -77,6 +91,7 @@
}
},
"replace": {
"description": "The replace of the dependency.",
"anyOf": [
{
"$ref": "#/$defs/TomlLockfilePackageId"
@ -92,7 +107,12 @@
"version"
]
},
"TomlLockfileSourceId": {
"description": "Serialization of dependency's source",
"type": "string"
},
"TomlLockfilePackageId": {
"description": "Serialization of package IDs.\n\nThe version and source are only included when necessary to disambiguate between packages:\n- If multiple packages share the same name, the version is included.\n- If multiple packages share the same name and version, the source is included.",
"type": "object",
"properties": {
"name": {
@ -105,9 +125,13 @@
]
},
"source": {
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/$defs/TomlLockfileSourceId"
},
{
"type": "null"
}
]
}
},
@ -116,9 +140,11 @@
]
},
"TomlLockfilePatch": {
"description": "Serialization of unused patches\n\nCargo stores patches that were declared but not used during resolution.",
"type": "object",
"properties": {
"unused": {
"description": "The list of unused dependency patches.",
"type": "array",
"items": {
"$ref": "#/$defs/TomlLockfileDependency"

View File

@ -1,3 +1,5 @@
//! `Cargo.lock` / Lockfile schema definition
use std::collections::BTreeMap;
use std::fmt;
use std::{cmp::Ordering, str::FromStr};
@ -7,44 +9,80 @@ use url::Url;
use crate::core::{GitReference, SourceKind};
/// The `Cargo.lock` structure.
/// Serialization of `Cargo.lock`
#[derive(Serialize, Deserialize, Debug)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlLockfile {
/// The lockfile format version (`version =` field).
///
/// This field is optional for backward compatibility. Older lockfiles, i.e. V1 and V2, does
/// not have the version field serialized.
pub version: Option<u32>,
/// The list of `[[package]]` entries describing each resolved dependency.
pub package: Option<Vec<TomlLockfileDependency>>,
/// `root` is optional to allow backward compatibility.
/// The `[root]` table describing the root package.
///
/// This field is optional for backward compatibility. Older lockfiles have the root package
/// separated, whereas newer lockfiles have the root package as part of `[[package]]`.
pub root: Option<TomlLockfileDependency>,
/// The `[metadata]` table
///
///
/// In older lockfile versions, dependency checksums were stored here instead of alongside each
/// package entry.
pub metadata: Option<TomlLockfileMetadata>,
/// The `[patch]` table describing unused patches.
///
/// The lockfile stores them as a list of `[[patch.unused]]` entries.
#[serde(default, skip_serializing_if = "TomlLockfilePatch::is_empty")]
pub patch: TomlLockfilePatch,
}
/// Serialization of lockfiles metadata
///
/// Older versions of lockfiles have their dependencies' checksums on this `[metadata]` table.
pub type TomlLockfileMetadata = BTreeMap<String, String>;
/// Serialization of unused patches
///
/// Cargo stores patches that were declared but not used during resolution.
#[derive(Serialize, Deserialize, Debug, Default)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlLockfilePatch {
/// The list of unused dependency patches.
pub unused: Vec<TomlLockfileDependency>,
}
pub type TomlLockfileMetadata = BTreeMap<String, String>;
impl TomlLockfilePatch {
fn is_empty(&self) -> bool {
self.unused.is_empty()
}
}
/// Serialization of lockfiles dependencies
#[derive(Serialize, Deserialize, Debug, PartialOrd, Ord, PartialEq, Eq)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlLockfileDependency {
/// The name of the dependency.
pub name: String,
/// The version of the dependency.
pub version: String,
/// The source of the dependency.
///
/// Cargo does not serialize path dependencies.
pub source: Option<TomlLockfileSourceId>,
/// The checksum of the dependency.
///
/// In older lockfiles, checksums were not stored here and instead on a separate `[metadata]`
/// table (see [`TomlLockfileMetadata`]).
pub checksum: Option<String>,
/// The transitive dependencies used by this dependency.
pub dependencies: Option<Vec<TomlLockfilePackageId>>,
/// The replace of the dependency.
pub replace: Option<TomlLockfilePackageId>,
}
/// Serialization of dependency's source
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "unstable-schema",
@ -52,11 +90,15 @@ pub struct TomlLockfileDependency {
schemars(with = "String")
)]
pub struct TomlLockfileSourceId {
/// Full string of the source
/// The string representation of the source as it appears in the lockfile.
source_str: String,
/// Used for sources ordering
/// The parsed source type, e.g. `git`, `registry`.
///
/// Used for sources ordering.
kind: SourceKind,
/// Used for sources ordering
/// The parsed URL of the source.
///
/// Used for sources ordering.
url: Url,
}
@ -157,6 +199,11 @@ impl Ord for TomlLockfileSourceId {
}
}
/// Serialization of package IDs.
///
/// The version and source are only included when necessary to disambiguate between packages:
/// - If multiple packages share the same name, the version is included.
/// - If multiple packages share the same name and version, the source is included.
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
#[cfg_attr(feature = "unstable-schema", derive(schemars::JsonSchema))]
pub struct TomlLockfilePackageId {