Skip to content

Commit

Permalink
Move lockfile to its own module (#29)
Browse files Browse the repository at this point in the history
## Issue
Closes #27.

`rules_multitool` suggests using a `$schema` field but this CLI doesn't support that field.

## Summary
Refactor lockfile handling to its own module, update struct names for legibility, and add support for specifying `$schema`. Additionally, validate `$schema` matches expectation, always serialize a value for `$schema`, and add some debug prints for tool updates. Last, move regex initialization into a static block.
  • Loading branch information
mark-thm authored May 28, 2024
1 parent 67727c5 commit cde0477
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 154 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ regex = "1.10.4"
serde = { version = "1.0.200", features = ["derive"] }
serde_json = "1.0.116"
sha256 = "1.5.0"
once_cell = "1.19.0"

# The profile that 'cargo dist' will build with
[profile.dist]
Expand Down
151 changes: 151 additions & 0 deletions src/lockfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeMap, HashMap},
fmt::Display,
};

pub const SCHEMA: &str =
"https://raw.githubusercontent.com/theoremlp/rules_multitool/main/lockfile.schema.json";

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SupportedOs {
Linux,
MacOS,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SupportedCpu {
Arm64,
X86_64,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct FileBinary {
pub url: String,
pub sha256: String,
pub os: SupportedOs,
pub cpu: SupportedCpu,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct ArchiveBinary {
pub url: String,
pub file: String,
pub sha256: String,
pub os: SupportedOs,
pub cpu: SupportedCpu,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub type_: Option<String>, // TODO(mark): we should probably make this an enum
}

#[derive(Clone, Serialize, Deserialize)]
pub struct PkgBinary {
pub url: String,
pub file: String,
pub sha256: String,
pub os: SupportedOs,
pub cpu: SupportedCpu,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
}

#[derive(Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum Binary {
File(FileBinary),
Archive(ArchiveBinary),
Pkg(PkgBinary),
}

#[derive(Serialize, Deserialize)]
pub struct ToolDefinition {
pub binaries: Vec<Binary>,
}

impl Display for SupportedCpu {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
SupportedCpu::Arm64 => write!(f, "arm64"),
SupportedCpu::X86_64 => write!(f, "x86_64"),
}
}
}

impl Display for SupportedOs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
SupportedOs::Linux => write!(f, "linux"),
SupportedOs::MacOS => write!(f, "macos"),
}
}
}

fn schema() -> String {
SCHEMA.to_owned()
}

#[derive(Serialize, Deserialize)]
pub struct Lockfile {
#[serde(rename = "$schema", default = "schema")]
pub schema: String,

#[serde(flatten)]
pub tools: BTreeMap<String, ToolDefinition>,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn deserialize_empty_lockfile() {
let lockfile: Lockfile = serde_json::from_str("{}").unwrap();
assert_eq!(lockfile.schema, schema());
assert_eq!(lockfile.tools.len(), 0);
}

#[test]
fn deserialize_lockfile_with_schema_and_no_tools() {
let lockfile: Lockfile = serde_json::from_str(r#"{
"$schema": "https://raw.githubusercontent.com/theoremlp/rules_multitool/main/lockfile.schema.json"
}"#).unwrap();
assert_eq!(
lockfile.schema,
"https://raw.githubusercontent.com/theoremlp/rules_multitool/main/lockfile.schema.json"
.to_owned()
);
assert_eq!(lockfile.tools.len(), 0);
}

#[test]
fn deserialize_lockfile_with_schema_and_tools() {
let lockfile: Lockfile = serde_json::from_str(r#"{
"$schema": "https://raw.githubusercontent.com/theoremlp/rules_multitool/main/lockfile.schema.json",
"tool-name": {
"binaries": [
{
"kind": "file",
"url": "https://github.com/theoremlp/multitool/releases/download/v0.2.1/multitool-x86_64-unknown-linux-gnu.tar.xz",
"sha256": "9523faf97e4e3fea5f98ba9d051e67c90799182580d8ae56cba2e45c7de0b4ce",
"os": "linux",
"cpu": "x86_64"
}
]
}
}"#).unwrap();
assert_eq!(
lockfile.schema,
"https://raw.githubusercontent.com/theoremlp/rules_multitool/main/lockfile.schema.json"
.to_owned()
);
assert_eq!(lockfile.tools.len(), 1);
assert_eq!(lockfile.tools["tool-name"].binaries.len(), 1);
// TOOD(mark): richer tests
}
}
Loading

0 comments on commit cde0477

Please sign in to comment.