mirror of
https://github.com/DeterminateSystems/flake-checker.git
synced 2024-10-26 15:08:23 +03:00
Merge pull request #50 from DeterminateSystems/node-enum-variants
This commit is contained in:
commit
639f58fb99
@ -1,9 +1,19 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
//! A library for parsing Nix [`flake.lock`][lock] files
|
||||
//! into a structured Rust representation. [Determinate Systems][detsys] currently uses this library
|
||||
//! for its [Nix Flake Checker][checker] and [Nix Flake Checker Action][action] but it's designed to
|
||||
//! be generally useful.
|
||||
//!
|
||||
//! [action]: https://github.com/DeterminateSystems/flake-checker-action
|
||||
//! [checker]: https://github.com/DeterminateSystems/flake-checker
|
||||
//! [detsys]: https://determinate.systems
|
||||
//! [lock]: https://zero-to-nix.com/concepts/flakes#lockfile
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::de::{self, MapAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
@ -135,13 +145,15 @@ fn chase_input_node(
|
||||
let mut node = &nodes[&next_input];
|
||||
for input in inputs {
|
||||
let maybe_node_inputs = match node {
|
||||
Node::Root(_) => None,
|
||||
Node::Repo(node) => node.inputs.to_owned(),
|
||||
Node::Indirect(node) => node.inputs.to_owned(),
|
||||
Node::Path(node) => node.inputs.to_owned(),
|
||||
Node::Fallthrough(node) => match node.get("inputs") {
|
||||
Some(node_inputs) => serde_json::from_value(node_inputs.clone())
|
||||
.map_err(FlakeLockParseError::Json)?,
|
||||
None => None,
|
||||
},
|
||||
Node::Root(_) => None,
|
||||
};
|
||||
|
||||
let node_inputs = match maybe_node_inputs {
|
||||
@ -181,21 +193,29 @@ impl FlakeLock {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Node {
|
||||
/// A [RootNode] specifying an [Input] map.
|
||||
Root(RootNode),
|
||||
/// A [RepoNode] flake input for a [Git](https://git-scm.com) repository (or another version
|
||||
/// control system).
|
||||
Repo(Box<RepoNode>),
|
||||
/// A [RootNode] specifying an [Input] map.
|
||||
Root(RootNode),
|
||||
/// An [IndirectNode] flake input stemming from an indirect flake reference like `inputs.nixpkgs.url =
|
||||
/// "nixpkgs";`.
|
||||
Indirect(IndirectNode),
|
||||
/// A [PathNode] flake input stemming from a filesystem path.
|
||||
Path(PathNode),
|
||||
/// A "catch-all" variant for node types that don't (yet) have explicit struct definitions in
|
||||
/// this crate.
|
||||
Fallthrough(serde_json::value::Value), // Covers all other node types
|
||||
}
|
||||
|
||||
// A string representation of the node variant (for logging).
|
||||
impl Node {
|
||||
fn variant(&self) -> &'static str {
|
||||
match self {
|
||||
Node::Root(_) => "Root",
|
||||
Node::Repo(_) => "Repo",
|
||||
Node::Indirect(_) => "Indirect",
|
||||
Node::Path(_) => "Path",
|
||||
Node::Fallthrough(_) => "Fallthrough", // Covers all other node types
|
||||
}
|
||||
}
|
||||
@ -205,7 +225,9 @@ impl Node {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Input {
|
||||
/// An input expressed as a string.
|
||||
String(String),
|
||||
/// An input expressed as a list of strings.
|
||||
List(Vec<String>),
|
||||
}
|
||||
|
||||
@ -222,6 +244,8 @@ pub struct RootNode {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RepoNode {
|
||||
/// Whether the input is itself a flake.
|
||||
pub flake: Option<bool>,
|
||||
/// The node's inputs.
|
||||
pub inputs: Option<HashMap<String, Input>>,
|
||||
/// The "locked" attributes of the input (set by Nix).
|
||||
@ -230,25 +254,102 @@ pub struct RepoNode {
|
||||
pub original: RepoOriginal,
|
||||
}
|
||||
|
||||
/// Information about the repository input that's "locked" because it's supplied by Nix.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct RepoLocked {
|
||||
/// The timestamp for when the input was last modified.
|
||||
#[serde(alias = "lastModified")]
|
||||
pub last_modified: i64,
|
||||
/// The NAR hash of the input.
|
||||
#[serde(alias = "narHash")]
|
||||
pub nar_hash: String,
|
||||
/// The repository owner.
|
||||
pub owner: String,
|
||||
/// The repository.
|
||||
pub repo: String,
|
||||
/// The Git revision.
|
||||
pub rev: String,
|
||||
/// The type of the node (either `"repo"` or `"indirect"`).
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
/// The `original` field of a [Repo][Node::Repo] node.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct RepoOriginal {
|
||||
/// The repository owner.
|
||||
pub owner: String,
|
||||
/// The repository.
|
||||
pub repo: String,
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
/// The Git reference of the input.
|
||||
#[serde(alias = "ref")]
|
||||
pub git_ref: Option<String>,
|
||||
/// The type of the node (always `"repo"`).
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
/// An indirect flake input (using the [flake
|
||||
/// registry](https://nixos.org/manual/nix/stable/command-ref/conf-file.html#conf-flake-registry)).
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct IndirectNode {
|
||||
/// The "locked" attributes of the input (set by Nix).
|
||||
pub locked: RepoLocked,
|
||||
/// The node's inputs.
|
||||
pub inputs: Option<HashMap<String, Input>>,
|
||||
/// The "original" (user-supplied) attributes of the input.
|
||||
pub original: IndirectOriginal,
|
||||
}
|
||||
|
||||
/// The `original` field of an [Indirect][Node::Indirect] node.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct IndirectOriginal {
|
||||
/// The ID of the input (recognized by the [flake
|
||||
/// registry]((https://nixos.org/manual/nix/stable/command-ref/conf-file.html#conf-flake-registry))).
|
||||
pub id: String,
|
||||
/// The type of the node (always `"indirect"`).
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
/// A flake input as a filesystem path, e.g. `inputs.local.url = "path:./subdir";`.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PathNode {
|
||||
/// The "locked" attributes of the input (set by Nix).
|
||||
pub locked: PathLocked,
|
||||
/// The node's inputs.
|
||||
pub inputs: Option<HashMap<String, Input>>,
|
||||
/// The "original" (user-supplied) attributes of the input.
|
||||
pub original: PathOriginal,
|
||||
}
|
||||
|
||||
/// Information about the path input that's "locked" because it's supplied by Nix.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct PathLocked {
|
||||
/// The timestamp for when the input was last modified.
|
||||
#[serde(alias = "lastModified")]
|
||||
pub last_modified: i64,
|
||||
/// The NAR hash of the input.
|
||||
#[serde(alias = "narHash")]
|
||||
pub nar_hash: String,
|
||||
/// The relative filesystem path for the input.
|
||||
pub path: PathBuf,
|
||||
/// The type of the node (always `"path"`).
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
}
|
||||
|
||||
/// The user-supplied path input info.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct PathOriginal {
|
||||
/// The relative filesystem path for the input.
|
||||
pub path: PathBuf,
|
||||
/// The Git reference of the input.
|
||||
#[serde(alias = "ref")]
|
||||
pub git_ref: Option<String>,
|
||||
/// The type of the node (always `"path"`).
|
||||
#[serde(alias = "type")]
|
||||
pub node_type: String,
|
||||
}
|
||||
|
23
src/flake.rs
23
src/flake.rs
@ -49,12 +49,20 @@ fn nixpkgs_deps(
|
||||
) -> Result<HashMap<String, Node>, FlakeCheckerError> {
|
||||
let mut deps: HashMap<String, Node> = HashMap::new();
|
||||
|
||||
for (key, node) in flake_lock.root.clone() {
|
||||
if let Node::Repo(_) = node {
|
||||
if keys.contains(&key) {
|
||||
deps.insert(key, node);
|
||||
for (ref key, node) in flake_lock.root.clone() {
|
||||
if let Node::Repo(_) = &node {
|
||||
if keys.contains(key) {
|
||||
deps.insert(key.to_string(), node.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Node::Indirect(indirect_node) = &node {
|
||||
if &indirect_node.original.id == key {
|
||||
deps.insert(key.to_string(), node);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: it's unclear that a path node for Nixpkgs should be accepted
|
||||
}
|
||||
let missing: Vec<String> = keys
|
||||
.iter()
|
||||
@ -139,15 +147,16 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_clean_flake_locks() {
|
||||
for n in 0..=4 {
|
||||
for n in 0..=6 {
|
||||
let path = PathBuf::from(format!("tests/flake.clean.{n}.lock"));
|
||||
let flake_lock = FlakeLock::new(&path).expect("couldn't create flake.lock");
|
||||
let config = FlakeCheckConfig {
|
||||
check_outdated: false,
|
||||
..Default::default()
|
||||
};
|
||||
let issues = check_flake_lock(&flake_lock, &config)
|
||||
.expect("couldn't run check_flake_lock function");
|
||||
let issues = check_flake_lock(&flake_lock, &config).expect(&format!(
|
||||
"couldn't run check_flake_lock function in {path:?}"
|
||||
));
|
||||
assert!(issues.is_empty());
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,36 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs-test": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1685573264,
|
||||
"narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=",
|
||||
"owner": "nixos",
|
||||
"lastModified": 1689078114,
|
||||
"narHash": "sha256-osG8BrX5RpKJ7wH+vI6auOU+ctvNOblT4XXCgknK47c=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "380be19fbd2d9079f677978361792cb25e8a3635",
|
||||
"rev": "b6cc7ff8fee93789bc871a267ab876c3fca042cb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "release-22.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-test"
|
||||
],
|
||||
"nixpkgs-test": "nixpkgs-test"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"sub": "sub"
|
||||
}
|
||||
},
|
||||
"sub": {
|
||||
"locked": {
|
||||
"lastModified": 1,
|
||||
"narHash": "sha256-+qUhj8mkS6BsSFAOMQek346MHTEDkmoaojSBbLefq7w=",
|
||||
"path": "./sub",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"path": "./sub",
|
||||
"type": "path"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user