diff --git a/Cargo.lock b/Cargo.lock index 02a35d2..f4e72c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,6 +168,7 @@ dependencies = [ "pretty_assertions", "serde", "serde_json", + "smart-default", ] [[package]] @@ -341,6 +342,17 @@ dependencies = [ "serde", ] +[[package]] +name = "smart-default" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 1e5d4e5..ece1847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ petgraph = { version = "0.6.4", features = ["serde-1"] } clap = { version = "4.5.26", features = ["derive"] } log = "0.4.24" env_logger = "0.11.6" +smart-default = "0.7.1" [dev-dependencies] pretty_assertions = "1.4.1" diff --git a/src/graph.rs b/src/graph.rs index f74aa08..0d73ee4 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -24,6 +24,7 @@ impl Node { } lock::NodeRef::Indirect(indirect) => format!("indirect::{}", indirect.id), lock::NodeRef::Tarball(tarball) => format!("tarball::{}", tarball.url), + lock::NodeRef::File(file) => format!("file::{}", file.url), lock::NodeRef::Path(path) => format!("path::{}", path.path), }) } diff --git a/src/lock.rs b/src/lock.rs index 767d853..e199f28 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use smart_default::SmartDefault; use std::collections::HashMap; #[derive(Deserialize, Serialize, PartialEq, Debug)] @@ -19,7 +20,7 @@ pub struct Node { #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct NodeLock { - pub last_modified: u32, + pub last_modified: Option, pub nar_hash: String, #[serde(flatten)] pub reference: NodeRef, @@ -33,6 +34,7 @@ pub enum NodeRef { GitLab(NodeRefGitLab), Indirect(NodeRefIndirect), Tarball(NodeRefTarball), + File(NodeRefFile), Path(NodeRefPath), } @@ -55,7 +57,11 @@ pub struct NodeRefGitHub { pub repo: String, } -#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] +fn gitlab_default_host() -> String { + "gitlab.com".to_string() +} + +#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, SmartDefault)] pub struct NodeRefGitLab { pub owner: String, #[serde(rename = "ref", skip_serializing_if = "Option::is_none")] @@ -63,6 +69,8 @@ pub struct NodeRefGitLab { #[serde(rename = "rev", skip_serializing_if = "Option::is_none")] pub revision: Option, pub repo: String, + #[default = "gitlab.com"] + #[serde(default = "gitlab_default_host")] pub host: String, } @@ -76,6 +84,11 @@ pub struct NodeRefTarball { pub url: String, } +#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] +pub struct NodeRefFile { + pub url: String, +} + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] pub struct NodeRefPath { pub path: String, diff --git a/tests/common/missing_fields_flake.lock b/tests/common/missing_fields_flake.lock new file mode 100644 index 0000000..75fd47f --- /dev/null +++ b/tests/common/missing_fields_flake.lock @@ -0,0 +1,40 @@ +{ + "nodes": { + "root": { + "inputs": { + "determinate-nixd-aarch64-darwin": "determinate-nixd-aarch64-darwin", + "nmd": "nmd" + } + }, + "nmd": { + "flake": false, + "locked": { + "lastModified": 1666190571, + "narHash": "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=", + "owner": "rycee", + "repo": "nmd", + "rev": "b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmd", + "type": "gitlab" + } + }, + "determinate-nixd-aarch64-darwin": { + "flake": false, + "locked": { + "narHash": "sha256-LNvx0qZsH8tbdgNfaig/x5Cf4r4UrXfU1m+0bO3D0E4=", + "type": "file", + "url": "https://install.determinate.systems/determinate-nixd/tag/v3.21.0/macOS" + }, + "original": { + "type": "file", + "url": "https://install.determinate.systems/determinate-nixd/tag/v3.21.0/macOS" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 6c2a2c0..ebfb9d9 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,10 +1,13 @@ -use flake_graph::lock::{FlakeLock, Node, NodeInput, NodeLock, NodeRef, NodeRefGit, NodeRefGitHub}; +use flake_graph::lock::{ + FlakeLock, Node, NodeInput, NodeLock, NodeRef, NodeRefFile, NodeRefGit, NodeRefGitHub, + NodeRefGitLab, +}; use std::collections::HashMap; fn nixpkgs_node() -> Node { Node { locked: Some(NodeLock { - last_modified: 1692742407, + last_modified: Some(1692742407), nar_hash: "sha256-faLzZ2u3Wki8h9ykEfzQr19B464eyADP3Ux7A/vjKIY=".to_string(), reference: NodeRef::GitHub(NodeRefGitHub { owner: "NixOS".to_string(), @@ -51,7 +54,7 @@ pub fn simple_lock() -> FlakeLock { "yants".to_string(), Node { locked: Some(NodeLock { - last_modified: 1645270620, + last_modified: Some(1645270620), nar_hash: "sha256-wwkl3K200UbW9Z7BRlVH8HOEXCaVYP2MqZpsF9EhgZg=".to_string(), reference: NodeRef::Git(NodeRefGit { url: "https://code.tvl.fyi/depot.git:/nix/yants.git".to_string(), @@ -84,7 +87,7 @@ pub fn bound_lock() -> FlakeLock { "home-manager".to_string(), Node { locked: Some(NodeLock { - last_modified: 1693187908, + last_modified: Some(1693187908), nar_hash: "sha256-cTcNpsqi1llmUFl9bmCdD0mTyfjhBrNFPhu2W12WXzA=".to_string(), reference: NodeRef::GitHub(NodeRefGitHub { owner: "nix-community".to_string(), @@ -127,5 +130,72 @@ pub fn bound_lock() -> FlakeLock { } } +/// JSON string of a valid lock file with some missing fields in its inputs. +pub const MISSING_FIELDS_LOCK_STR: &str = include_str!("./missing_fields_flake.lock"); + +/// Struct representation of a valid lock file with some missing fields in its inputs. +pub fn missing_fields_lock() -> FlakeLock { + FlakeLock { + root: "root".to_string(), + version: 7, + nodes: HashMap::from([ + ( + "root".to_string(), + Node { + locked: None, + original: None, + inputs: HashMap::from([ + ("nmd".to_string(), NodeInput::Direct("nmd".to_string())), + ( + "determinate-nixd-aarch64-darwin".to_string(), + NodeInput::Direct("determinate-nixd-aarch64-darwin".to_string()), + ), + ]), + }, + ), + ( + "nmd".to_string(), + Node { + locked: Some(NodeLock { + last_modified: Some(1666190571), + nar_hash: "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=".to_string(), + reference: NodeRef::GitLab(NodeRefGitLab { + owner: "rycee".to_string(), + reference: None, + revision: Some("b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169".to_string()), + repo: "nmd".to_string(), + host: "gitlab.com".to_string(), + }), + }), + original: Some(NodeRef::GitLab(NodeRefGitLab { + owner: "rycee".to_string(), + reference: None, + revision: None, + repo: "nmd".to_string(), + host: "gitlab.com".to_string(), + })), + inputs: HashMap::default(), + }, + ), + ( + "determinate-nixd-aarch64-darwin".to_string(), + Node { + locked: Some(NodeLock { + last_modified: None, + nar_hash: "sha256-LNvx0qZsH8tbdgNfaig/x5Cf4r4UrXfU1m+0bO3D0E4=".to_string(), + reference: NodeRef::File(NodeRefFile { + url: "https://install.determinate.systems/determinate-nixd/tag/v3.21.0/macOS".to_string(), + }), + }), + original: Some(NodeRef::File(NodeRefFile { + url: "https://install.determinate.systems/determinate-nixd/tag/v3.21.0/macOS".to_string(), + })), + inputs: HashMap::default(), + }, + ), + ]), + } +} + /// JSON string of a lock file with an input loop pub const LOOPED_LOCK_STR: &str = include_str!("./looped_flake.lock"); diff --git a/tests/graph.rs b/tests/graph.rs index 379229c..3c739b7 100644 --- a/tests/graph.rs +++ b/tests/graph.rs @@ -1,6 +1,6 @@ pub mod common; -use common::{bound_lock, simple_lock, LOOPED_LOCK_STR}; +use common::{bound_lock, missing_fields_lock, simple_lock, LOOPED_LOCK_STR}; use flake_graph::{ graph::{NodeGraph, SizeSummary}, lock::FlakeLock, @@ -15,6 +15,13 @@ fn build_simple_lock_graph() { println!("{}", graph.to_dot(None)); } +#[test] +fn build_missing_field_lock_graph() { + let lock = missing_fields_lock(); + let graph = NodeGraph::from(lock); + println!("{}", graph.to_dot(None)); +} + #[test] fn build_bound_lock_graph() { let lock = bound_lock(); diff --git a/tests/parse_lock.rs b/tests/parse_lock.rs index b4a096b..4dd6336 100644 --- a/tests/parse_lock.rs +++ b/tests/parse_lock.rs @@ -1,7 +1,10 @@ pub mod common; use pretty_assertions::assert_eq; -use common::{bound_lock, simple_lock, BOUND_LOCK_STR, SIMPLE_LOCK_STR}; +use common::{ + bound_lock, missing_fields_lock, simple_lock, BOUND_LOCK_STR, MISSING_FIELDS_LOCK_STR, + SIMPLE_LOCK_STR, +}; use flake_graph::lock::FlakeLock; #[test] @@ -10,6 +13,12 @@ fn parse_simple_lock() { assert_eq!(parsed, simple_lock()); } +#[test] +fn parse_missing_fields_lock() { + let parsed: FlakeLock = serde_json::from_str(MISSING_FIELDS_LOCK_STR).unwrap(); + assert_eq!(parsed, missing_fields_lock()); +} + #[test] fn parse_bound_lock() { let parsed: FlakeLock = serde_json::from_str(BOUND_LOCK_STR).unwrap();