| //! 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, |
| } |
| |
| 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(ResolveVersion::V1) |
| } else { |
| // Default to V2 |
| Ok(ResolveVersion::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 { |
| ResolveVersion::V3 |
| } |
| } |
| |
| impl From<ResolveVersion> for u32 { |
| fn from(version: ResolveVersion) -> u32 { |
| version as u32 |
| } |
| } |
| |
| 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(ResolveVersion::V1), |
| 2 => Ok(ResolveVersion::V2), |
| 3 => Ok(ResolveVersion::V3), |
| _ => Err(Error::Parse(format!( |
| "invalid Cargo.lock format version: `{}`", |
| num |
| ))), |
| } |
| } |
| } |