From 00815fa7032feb6b8a5c6178a56cb53943b7ad22 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Wed, 8 Jan 2025 23:17:41 +0100 Subject: [PATCH] Introduce boilerplate for checking Nix files --- src/eval.rs | 7 +++--- src/files.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 34 +++++++++++++++++--------- src/ratchet.rs | 18 ++++++++++++++ 4 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 src/files.rs diff --git a/src/eval.rs b/src/eval.rs index a43630c..d2e11e7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::{env, fs, process}; @@ -156,7 +157,7 @@ pub fn check_values( nixpkgs_path: &Path, nix_file_store: &mut NixFileStore, package_names: &[String], -) -> validation::Result { +) -> validation::Result> { let work_dir = tempfile::Builder::new() .prefix("nixpkgs-vet") .tempdir() @@ -255,9 +256,7 @@ pub fn check_values( .collect_vec()?, ); - Ok(check_result.map(|elems| ratchet::Nixpkgs { - packages: elems.into_iter().collect(), - })) + Ok(check_result.map(|elems| elems.into_iter().collect())) } /// Handle the evaluation result for an attribute in `pkgs/by-name`, making it a validation result. diff --git a/src/files.rs b/src/files.rs new file mode 100644 index 0000000..320933e --- /dev/null +++ b/src/files.rs @@ -0,0 +1,66 @@ +use crate::problem::npv_170; +use relative_path::RelativePath; +use relative_path::RelativePathBuf; +use rnix::ast::Expr::Str; +use std::collections::BTreeMap; +use std::path::Path; + +use crate::nix_file::NixFileStore; +use crate::validation::ResultIteratorExt; +use crate::validation::Validation::Success; +use crate::{nix_file, ratchet, structure, validation}; + +pub fn check_files( + nixpkgs_path: &Path, + nix_file_store: &mut NixFileStore, +) -> validation::Result> { + process_nix_files(nixpkgs_path, nix_file_store, |nix_file| { + Ok(Success(ratchet::File {})) + }) +} + +fn collect_nix_files( + base: &Path, + dir: &RelativePath, + files: &mut Vec, +) -> anyhow::Result<()> { + for entry in structure::read_dir_sorted(&dir.to_path(base))? { + let mut relative_path = dir.to_relative_path_buf(); + relative_path.push(entry.file_name().to_string_lossy().into_owned()); + + let absolute_path = entry.path(); + + if absolute_path.is_symlink() { + continue; + } + if absolute_path.is_dir() { + collect_nix_files(base, &relative_path, files)? + } else if absolute_path.extension().is_some_and(|x| x == "nix") { + files.push(relative_path) + } + } + Ok(()) +} + +fn process_nix_files validation::Result>( + nixpkgs_path: &Path, + nix_file_store: &mut NixFileStore, + f: F, +) -> validation::Result> { + let files = { + let mut files = vec![]; + collect_nix_files(nixpkgs_path, &RelativePathBuf::new(), &mut files)?; + files + }; + + let file_results: Vec> = files + .into_iter() + .map(|path| { + let nix_file = nix_file_store.get(&path.to_path(nixpkgs_path))?; + let val = f(nix_file)?.map(|file| (path, file)); + Ok::<_, anyhow::Error>(val) + }) + .collect_vec()?; + + Ok(validation::sequence(file_results).map(|entries| entries.into_iter().collect())) +} diff --git a/src/main.rs b/src/main.rs index 4ca532e..4ca9d98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ // #![allow(clippy::missing_const_for_fn)] mod eval; +mod files; mod location; mod nix_file; mod problem; @@ -21,6 +22,7 @@ mod validation; use anyhow::Context as _; use clap::Parser; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::process::ExitCode; use std::{panic, thread}; @@ -113,20 +115,30 @@ fn check_nixpkgs(nixpkgs_path: &Path) -> validation::Result { ) })?; - if !nixpkgs_path.join(structure::BASE_SUBPATH).exists() { - // No pkgs/by-name directory, always valid - return Ok(Success(ratchet::Nixpkgs::default())); - } - let mut nix_file_store = NixFileStore::default(); - let structure = check_structure(&nixpkgs_path, &mut nix_file_store)?; - // Only if we could successfully parse the structure, we do the evaluation checks - let result = structure.result_map(|package_names| { - eval::check_values(&nixpkgs_path, &mut nix_file_store, package_names.as_slice()) - })?; + let package_result = { + if !nixpkgs_path.join(structure::BASE_SUBPATH).exists() { + // No pkgs/by-name directory, always valid + Success(BTreeMap::new()) + } else { + let structure = check_structure(&nixpkgs_path, &mut nix_file_store)?; + + // Only if we could successfully parse the structure, we do the evaluation checks + structure.result_map(|package_names| { + eval::check_values(&nixpkgs_path, &mut nix_file_store, package_names.as_slice()) + })? + } + }; + + let file_result = files::check_files(&nixpkgs_path, &mut nix_file_store)?; - Ok(result) + Ok( + package_result.and(file_result, |packages, files| ratchet::Nixpkgs { + packages, + files, + }), + ) } #[cfg(test)] diff --git a/src/ratchet.rs b/src/ratchet.rs index 10e7e90..8c220c9 100644 --- a/src/ratchet.rs +++ b/src/ratchet.rs @@ -2,6 +2,7 @@ //! //! Each type has a `compare` method that validates the ratchet checks for that item. +use relative_path::RelativePath; use std::collections::BTreeMap; use relative_path::RelativePathBuf; @@ -15,6 +16,7 @@ use crate::validation::{self, Validation, Validation::Success}; pub struct Nixpkgs { /// The ratchet values for all packages pub packages: BTreeMap, + pub files: BTreeMap, } impl Nixpkgs { @@ -27,6 +29,9 @@ impl Nixpkgs { .into_iter() .map(|(name, pkg)| Package::compare(&name, from.packages.get(&name), &pkg)), ) + .and_(validation::sequence_(to.files.into_iter().map( + |(name, file)| File::compare(&name, from.files.get(&name), &file), + ))) } } @@ -57,6 +62,19 @@ impl Package { } } +pub struct File {} + +impl File { + /// Validates the ratchet checks for a top-level package + pub fn compare( + _name: &RelativePath, + _optional_from: Option<&Self>, + _to: &Self, + ) -> Validation<()> { + Success(()) + } +} + /// The ratchet state of a generic ratchet check. pub enum RatchetState { /// The ratchet is loose. It can be tightened more. In other words, this is the legacy state