From 7675005c0c897b47d3d2932fa050fd36cd7a78f1 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Tue, 17 Sep 2024 18:26:44 -0400 Subject: [PATCH] Implement v1-v2 release conversion --- Cargo.lock | 47 +++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/meta/mod.rs | 2 +- src/meta/v1/mod.rs | 4 +-- src/release/mod.rs | 2 +- src/release/tests.rs | 5 ---- src/release/v1/mod.rs | 58 ++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 107 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f761414..d4ebfa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,6 +111,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.1.19" @@ -494,6 +500,7 @@ dependencies = [ "hex", "json-patch", "lexopt", + "rand", "relative-path", "semver", "serde", @@ -519,6 +526,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -537,6 +553,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "regex" version = "1.10.5" @@ -1026,6 +1072,7 @@ version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ + "byteorder", "zerocopy-derive", ] diff --git a/Cargo.toml b/Cargo.toml index 63801be..aa049ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ chrono = { version = "0.4.38", features = ["serde"] } email_address = "0.2.9" json-patch = "2.0.0" lexopt = "0.3.0" +rand = "0.8.5" relative-path = { version = "1.9", features = ["serde"] } semver = { version = "1.0", features = ["std", "serde"] } serde = { version = "1", features = ["derive"] } diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 9ef9181..d5a75b5 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -16,7 +16,7 @@ use semver::Version; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::Value; -mod v1; +pub(crate) mod v1; mod v2; /// Represents the `meta-spec` object in [`Distribution`]. diff --git a/src/meta/v1/mod.rs b/src/meta/v1/mod.rs index 56ac567..851bdaf 100644 --- a/src/meta/v1/mod.rs +++ b/src/meta/v1/mod.rs @@ -10,7 +10,7 @@ pub fn to_v2(v1: &Value) -> Result> { // Copy common fields. let mut v2 = v1_to_v2_common(v1); - // Convert maintainer. + // Convert maintainers. v2.insert("maintainers".to_string(), v1_to_v2_maintainers(v1)?); // Convert license. @@ -45,7 +45,7 @@ pub fn to_v2(v1: &Value) -> Result> { /// from_value parses v1, which contains PGXN v1 metadata, into a /// [`Distribution`] object containing valid PGXN v2 metadata. pub fn from_value(v1: Value) -> Result> { - Distribution::try_from(to_v2(&v1)?) + to_v2(&v1)?.try_into() } /// v1_to_v2_common sets up a new v2 map with compatible fields copied from v1 diff --git a/src/release/mod.rs b/src/release/mod.rs index 669d08d..35b0fe1 100644 --- a/src/release/mod.rs +++ b/src/release/mod.rs @@ -376,7 +376,7 @@ impl TryFrom<&[&Value]> for Release { // Convert the first doc to v2 if necessary. let mut v2 = match version { - // 1 => v1::to_v2(meta[0])?, + 1 => v1::to_v2(meta[0])?, 2 => meta[0].clone(), _ => unreachable!(), }; diff --git a/src/release/tests.rs b/src/release/tests.rs index ee36416..0dd3b76 100644 --- a/src/release/tests.rs +++ b/src/release/tests.rs @@ -39,11 +39,6 @@ fn test_corpus() -> Result<(), Box> { ), (2, release_meta()), ] { - // Skip version 1 for now. - if version == 1 { - continue; - } - let v_dir = format!("v{version}"); let dir: PathBuf = [env!("CARGO_MANIFEST_DIR"), "corpus", &v_dir] .iter() diff --git a/src/release/v1/mod.rs b/src/release/v1/mod.rs index a71bbab..e29bd03 100644 --- a/src/release/v1/mod.rs +++ b/src/release/v1/mod.rs @@ -1,7 +1,59 @@ use super::Release; -use serde_json::Value; +use crate::meta::v1 as dist; +use serde_json::{json, Value}; use std::error::Error; -pub fn from_value(_: Value) -> Result> { - Err("TODO".into()) +/// to_v2 parses v1, which contains PGXN v1 release metadata, into a JSON +/// object containing valid PGXN v2 release metadata. +pub fn to_v2(v1: &Value) -> Result> { + let mut v2_val = dist::to_v2(v1)?; + let v2 = v2_val + .as_object_mut() + .ok_or("Date returned from v1::to_v2 is not an object")?; + + // Convert release. + v2.insert("release".to_string(), v1_to_v2_release(v1)?); + + Ok(v2_val) +} + +/// from_value parses v1, which contains PGXN v1 metadata, into a +/// [`Release`] object containing valid PGXN v2 metadata. +pub fn from_value(v1: Value) -> Result> { + to_v2(&v1)?.try_into() +} + +/// v1_to_v2_release clones release metadata from v1 to the v2 format. The +/// included signature information will be random and un-verifiable, but +/// adequate for v2 JSON Schema validation. +fn v1_to_v2_release(v1: &Value) -> Result> { + use rand::distributions::{Alphanumeric, DistString}; + if let Some(Value::String(user)) = v1.get("user") { + if let Some(Value::String(date)) = v1.get("date") { + if let Some(Value::String(sha1)) = v1.get("sha1") { + if let Some(Value::String(name)) = v1.get("name") { + if let Some(Value::String(version)) = v1.get("version") { + let uri = format!( + "/dist/semver/{}/{}-{}.zip", + version.as_str(), + name.as_str(), + version.as_str() + ); + let mut rng = rand::thread_rng(); + return Ok(json!({ + "headers": [format!("eyJ{}", Alphanumeric.sample_string(&mut rng, 12))], + "signatures": [Alphanumeric.sample_string(&mut rng, 32)], + "payload": { + "user": user, + "date": date, + "uri": uri, + "digests": {"sha1": sha1}, + } + })); + } + } + } + } + } + Err(Box::from("release metadata missing")) }