From 247712582abebc783b94bf299f6263640b7f7119 Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 17 Sep 2026 01:14:58 -0400 Subject: [PATCH] chore: remove unused Rust projects --- Cargo.lock | 57 ---- Cargo.toml | 2 - src/nix-style-linter/BUILD | 24 -- src/nix-style-linter/Cargo.toml | 19 -- src/nix-style-linter/lib.rs | 522 ------------------------------- src/nix-style-linter/lib_test.rs | 281 ----------------- src/nix-style-linter/main.rs | 16 - src/xatu/BUILD | 20 -- src/xatu/Cargo.toml | 13 - src/xatu/lib.rs | 5 - src/xatu/lib_test.rs | 4 - src/xatu/main.rs | 3 - 12 files changed, 966 deletions(-) delete mode 100644 src/nix-style-linter/BUILD delete mode 100644 src/nix-style-linter/Cargo.toml delete mode 100644 src/nix-style-linter/lib.rs delete mode 100644 src/nix-style-linter/lib_test.rs delete mode 100644 src/nix-style-linter/main.rs delete mode 100644 src/xatu/BUILD delete mode 100644 src/xatu/Cargo.toml delete mode 100644 src/xatu/lib.rs delete mode 100644 src/xatu/lib_test.rs delete mode 100644 src/xatu/main.rs diff --git a/Cargo.lock b/Cargo.lock index fec6a7d..6fb8080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,18 +107,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" -[[package]] -name = "countme" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "heck" version = "0.5.0" @@ -147,14 +135,6 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" -[[package]] -name = "nix-style-linter" -version = "0.1.0" -dependencies = [ - "rnix", - "rowan", -] - [[package]] name = "once_cell_polyfill" version = "1.70.2" @@ -179,33 +159,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rnix" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c163bd17372eecdf10d351c34584b7de7c1a33be4e92a32f3fb3f5a7fe3f579b" -dependencies = [ - "rowan", -] - -[[package]] -name = "rowan" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" -dependencies = [ - "countme", - "hashbrown", - "rustc-hash", - "text-size", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "serde" version = "1.0.229" @@ -266,12 +219,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "text-size" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" - [[package]] name = "unicode-ident" version = "1.0.25" @@ -299,10 +246,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "xatu" -version = "0.1.0" - [[package]] name = "zmij" version = "1.0.23" diff --git a/Cargo.toml b/Cargo.toml index 2945153..10b9230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [workspace] members = [ "src/ariadne", - "src/nix-style-linter", - "src/xatu", "src/machoke", ] resolver = "3" diff --git a/src/nix-style-linter/BUILD b/src/nix-style-linter/BUILD deleted file mode 100644 index 02bf38a..0000000 --- a/src/nix-style-linter/BUILD +++ /dev/null @@ -1,24 +0,0 @@ -load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") - -rust_library( - name = "nix_style_linter_lib", - crate_name = "nix_style_linter", - srcs = ["lib.rs"], - deps = [ - "//third_party/crates:rnix", - "//third_party/crates:rowan", - ], -) - -rust_binary( - name = "nix-style-linter", - crate_name = "nix_style_linter_cli", - srcs = ["main.rs"], - deps = [":nix_style_linter_lib"], -) - -rust_test( - name = "lib_test", - srcs = ["lib_test.rs"], - deps = [":nix_style_linter_lib"], -) diff --git a/src/nix-style-linter/Cargo.toml b/src/nix-style-linter/Cargo.toml deleted file mode 100644 index 3856d77..0000000 --- a/src/nix-style-linter/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "nix-style-linter" -version = "0.1.0" -edition = "2024" - -[lib] -path = "lib.rs" - -[[bin]] -name = "nix-style-linter" -path = "main.rs" - -[[test]] -name = "lib_test" -path = "lib_test.rs" - -[dependencies] -rnix = "0.14.0" -rowan = "0.16.1" diff --git a/src/nix-style-linter/lib.rs b/src/nix-style-linter/lib.rs deleted file mode 100644 index 3ef7f07..0000000 --- a/src/nix-style-linter/lib.rs +++ /dev/null @@ -1,522 +0,0 @@ -use std::collections::HashSet; -use std::ffi::OsStr; -use std::fmt; -use std::fs; -use std::io::{self, Write}; -use std::path::{Path, PathBuf}; - -use rnix::SyntaxKind; -use rnix::ast::{self, HasEntry}; -use rowan::ast::AstNode; - -const PARSE_ERROR_RULE: &str = "parse-error"; -const LET_ORDER_RULE: &str = "let-order"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RunStatus { - Clean, - Diagnostics, - ToolError, -} - -impl RunStatus { - pub fn code(self) -> u8 { - match self { - RunStatus::Clean => 0, - RunStatus::Diagnostics => 1, - RunStatus::ToolError => 2, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Diagnostic { - pub path: PathBuf, - pub line: usize, - pub column: usize, - pub rule: &'static str, - pub message: String, -} - -impl fmt::Display for Diagnostic { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - formatter, - "{}:{}:{}: {}: {}", - self.path.display(), - self.line, - self.column, - self.rule, - self.message - ) - } -} - -pub fn run( - paths: &[PathBuf], - stdout: &mut impl Write, - stderr: &mut impl Write, -) -> io::Result { - if paths.is_empty() { - writeln!(stderr, "error: expected at least one path")?; - return Ok(RunStatus::ToolError); - } - - let mut found_diagnostics = false; - let mut found_tool_errors = false; - - for path in paths { - let path = resolve_workspace_path(path); - match collect_nix_files(&path) { - Ok(files) => { - for file in files { - match lint_file(&file) { - Ok(diagnostics) => { - for diagnostic in diagnostics { - found_diagnostics = true; - writeln!(stdout, "{diagnostic}")?; - } - } - Err(error) => { - found_tool_errors = true; - writeln!( - stderr, - "error: failed to read {path}: {error}", - path = file.display() - )?; - } - } - } - } - Err(error) => { - found_tool_errors = true; - writeln!(stderr, "error: {error}")?; - } - } - } - - if found_tool_errors { - Ok(RunStatus::ToolError) - } else if found_diagnostics { - Ok(RunStatus::Diagnostics) - } else { - Ok(RunStatus::Clean) - } -} - -fn resolve_workspace_path(path: &Path) -> PathBuf { - if path.is_absolute() { - return path.to_path_buf(); - } - - if let Some(workspace) = std::env::var_os("BUILD_WORKSPACE_DIRECTORY") { - return PathBuf::from(workspace).join(path); - } - - path.to_path_buf() -} - -pub fn lint_file(path: &Path) -> io::Result> { - let source = fs::read_to_string(path)?; - let parse = rnix::Root::parse(&source); - let parse_diagnostics = parse_diagnostics(path, &source, parse.errors()); - - if !parse_diagnostics.is_empty() { - return Ok(parse_diagnostics); - } - - Ok(let_order_diagnostics(path, &source, &parse.tree())) -} - -fn parse_diagnostics( - path: &Path, - source: &str, - errors: &[rnix::ParseError], -) -> Vec { - errors - .iter() - .map(|error| { - let (line, column) = line_column(source, parse_error_offset(error, source.len())); - Diagnostic { - path: path.to_path_buf(), - line, - column, - rule: PARSE_ERROR_RULE, - message: error.to_string(), - } - }) - .collect() -} - -fn let_order_diagnostics(path: &Path, source: &str, root: &ast::Root) -> Vec { - root.syntax() - .descendants() - .filter_map(ast::LetIn::cast) - .flat_map(|let_in| let_order_diagnostics_for_let(path, source, &let_in)) - .collect() -} - -fn let_order_diagnostics_for_let( - path: &Path, - source: &str, - let_in: &ast::LetIn, -) -> Vec { - let bindings: Vec<_> = let_in - .attrpath_values() - .filter_map(|binding| plain_binding(source, &binding)) - .collect(); - let names: Vec<_> = bindings - .iter() - .map(|binding| binding.name.clone()) - .collect(); - let mut diagnostics = Vec::new(); - - for (index, binding) in bindings.iter().enumerate() { - let later_names: HashSet<_> = names.iter().skip(index + 1).cloned().collect(); - if let Some(referenced_name) = - first_forward_reference(binding.value.syntax(), &later_names, &mut HashSet::new()) - { - if is_suppressed(source, binding.line, LET_ORDER_RULE) { - continue; - } - - diagnostics.push(Diagnostic { - path: path.to_path_buf(), - line: binding.line, - column: binding.column, - rule: LET_ORDER_RULE, - message: format!( - "`{binding}` references later let binding `{referenced}`", - binding = binding.name, - referenced = referenced_name - ), - }); - } - } - - diagnostics -} - -#[derive(Debug, Clone)] -struct Binding { - name: String, - line: usize, - column: usize, - value: ast::Expr, -} - -fn plain_binding(source: &str, binding: &ast::AttrpathValue) -> Option { - let attr = plain_attr(binding.attrpath()?)?; - let value = binding.value()?; - let offset = usize::from(attr.text_range().start()); - let (line, column) = line_column(source, offset); - - Some(Binding { - name: attr.text().to_string(), - line, - column, - value, - }) -} - -fn plain_attrpath_name(binding: &ast::AttrpathValue) -> Option { - let attr = plain_attr(binding.attrpath()?)?; - Some(attr.text().to_string()) -} - -fn plain_attr(attrpath: ast::Attrpath) -> Option { - let mut attrs = attrpath.attrs(); - let attr = attrs.next()?; - - if attrs.next().is_some() { - return None; - } - - match attr { - ast::Attr::Ident(ident) => ident.ident_token(), - ast::Attr::Dynamic(_) | ast::Attr::Str(_) => None, - } -} - -fn first_forward_reference( - node: &rnix::SyntaxNode, - later_names: &HashSet, - shadowed: &mut HashSet, -) -> Option { - match node.kind() { - SyntaxKind::NODE_LAMBDA => { - return with_shadowed(shadowed, lambda_bound_names(node), |shadowed| { - first_forward_reference_in_children(node, later_names, shadowed) - }); - } - SyntaxKind::NODE_LET_IN => { - return with_shadowed(shadowed, plain_let_binding_names(node), |shadowed| { - first_forward_reference_in_children(node, later_names, shadowed) - }); - } - SyntaxKind::NODE_ATTR_SET if rec_attrset_binds_names(node) => { - return with_shadowed(shadowed, plain_attrset_binding_names(node), |shadowed| { - first_forward_reference_in_children(node, later_names, shadowed) - }); - } - _ => {} - } - - if is_reference_ident(node) { - if let Some(name) = ident_name(node) { - if later_names.contains(&name) && !shadowed.contains(&name) { - return Some(name); - } - } - } - - first_forward_reference_in_children(node, later_names, shadowed) -} - -fn first_forward_reference_in_children( - node: &rnix::SyntaxNode, - later_names: &HashSet, - shadowed: &mut HashSet, -) -> Option { - node.children() - .find_map(|child| first_forward_reference(&child, later_names, shadowed)) -} - -fn with_shadowed( - shadowed: &mut HashSet, - names: Vec, - action: impl FnOnce(&mut HashSet) -> R, -) -> R { - let inserted: Vec<_> = names - .into_iter() - .filter(|name| shadowed.insert(name.clone())) - .collect(); - let result = action(shadowed); - - for name in inserted { - shadowed.remove(&name); - } - - result -} - -fn is_reference_ident(node: &rnix::SyntaxNode) -> bool { - if node.kind() != SyntaxKind::NODE_IDENT { - return false; - } - - !matches!( - node.parent().map(|parent| parent.kind()), - Some( - SyntaxKind::NODE_ATTRPATH - | SyntaxKind::NODE_IDENT_PARAM - | SyntaxKind::NODE_PAT_BIND - | SyntaxKind::NODE_PAT_ENTRY - ) - ) -} - -fn ident_name(node: &rnix::SyntaxNode) -> Option { - ast::Ident::cast(node.clone()) - .and_then(|ident| ident.ident_token()) - .map(|token| token.text().to_string()) -} - -fn lambda_bound_names(node: &rnix::SyntaxNode) -> Vec { - let Some(lambda) = ast::Lambda::cast(node.clone()) else { - return Vec::new(); - }; - let Some(param) = lambda.param() else { - return Vec::new(); - }; - - match param { - ast::Param::IdentParam(param) => param - .ident() - .and_then(|ident| ident.ident_token()) - .map(|token| vec![token.text().to_string()]) - .unwrap_or_default(), - ast::Param::Pattern(pattern) => { - let mut names: Vec<_> = pattern - .pat_entries() - .filter_map(|entry| entry.ident()) - .filter_map(|ident| ident.ident_token()) - .map(|token| token.text().to_string()) - .collect(); - - if let Some(name) = pattern - .pat_bind() - .and_then(|bind| bind.ident()) - .and_then(|ident| ident.ident_token()) - .map(|token| token.text().to_string()) - { - names.push(name); - } - - names - } - } -} - -fn plain_let_binding_names(node: &rnix::SyntaxNode) -> Vec { - ast::LetIn::cast(node.clone()) - .map(|let_in| { - let_in - .attrpath_values() - .filter_map(|binding| plain_attrpath_name(&binding)) - .collect() - }) - .unwrap_or_default() -} - -fn rec_attrset_binds_names(node: &rnix::SyntaxNode) -> bool { - ast::AttrSet::cast(node.clone()) - .and_then(|attrset| attrset.rec_token()) - .is_some() -} - -fn plain_attrset_binding_names(node: &rnix::SyntaxNode) -> Vec { - ast::AttrSet::cast(node.clone()) - .map(|attrset| { - attrset - .attrpath_values() - .filter_map(|binding| plain_attrpath_name(&binding)) - .collect() - }) - .unwrap_or_default() -} - -fn is_suppressed(source: &str, line: usize, rule: &str) -> bool { - let Some(previous_line_index) = line.checked_sub(2) else { - return false; - }; - let Some(previous_line) = source.lines().nth(previous_line_index) else { - return false; - }; - let Some(comment) = previous_line.trim_start().strip_prefix('#') else { - return false; - }; - let Some(rest) = comment.trim().strip_prefix("nix-style-linter:") else { - return false; - }; - let Some((directive, reason)) = rest.trim().split_once("--") else { - return false; - }; - let mut words = directive.split_whitespace(); - - words.next() == Some("disable-next-line") - && words.any(|word| word == rule) - && !reason.trim().is_empty() -} - -fn collect_nix_files(path: &Path) -> Result, InputError> { - let metadata = fs::metadata(path).map_err(|source| InputError::Metadata { - path: path.to_path_buf(), - source, - })?; - - if metadata.is_file() { - return Ok(is_nix_file(path) - .then(|| path.to_path_buf()) - .into_iter() - .collect()); - } - - if metadata.is_dir() { - let mut files = Vec::new(); - collect_nix_files_from_dir(path, &mut files)?; - files.sort(); - return Ok(files); - } - - Err(InputError::UnsupportedPath(path.to_path_buf())) -} - -fn collect_nix_files_from_dir(path: &Path, files: &mut Vec) -> Result<(), InputError> { - let entries = fs::read_dir(path).map_err(|source| InputError::ReadDir { - path: path.to_path_buf(), - source, - })?; - - for entry in entries { - let entry = entry.map_err(|source| InputError::ReadDir { - path: path.to_path_buf(), - source, - })?; - let entry_path = entry.path(); - let file_type = entry.file_type().map_err(|source| InputError::Metadata { - path: entry_path.clone(), - source, - })?; - - if file_type.is_dir() { - collect_nix_files_from_dir(&entry_path, files)?; - } else if file_type.is_file() && is_nix_file(&entry_path) { - files.push(entry_path); - } - } - - Ok(()) -} - -fn is_nix_file(path: &Path) -> bool { - path.extension() == Some(OsStr::new("nix")) -} - -fn parse_error_offset(error: &rnix::ParseError, end_offset: usize) -> usize { - match error { - rnix::ParseError::Unexpected(range) - | rnix::ParseError::UnexpectedExtra(range) - | rnix::ParseError::UnexpectedWanted(_, range, _) - | rnix::ParseError::UnexpectedDoubleBind(range) - | rnix::ParseError::DuplicatedArgs(range, _) => usize::from(range.start()), - rnix::ParseError::UnexpectedEOF - | rnix::ParseError::UnexpectedEOFWanted(_) - | rnix::ParseError::RecursionLimitExceeded => end_offset, - _ => end_offset, - } -} - -fn line_column(source: &str, offset: usize) -> (usize, usize) { - let target = offset.min(source.len()); - let mut line = 1; - let mut column = 1; - - for (index, character) in source.char_indices() { - if index >= target { - break; - } - - if character == '\n' { - line += 1; - column = 1; - } else { - column += 1; - } - } - - (line, column) -} - -#[derive(Debug)] -enum InputError { - Metadata { path: PathBuf, source: io::Error }, - ReadDir { path: PathBuf, source: io::Error }, - UnsupportedPath(PathBuf), -} - -impl fmt::Display for InputError { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - InputError::Metadata { path, source } => { - write!(formatter, "failed to inspect {}: {source}", path.display()) - } - InputError::ReadDir { path, source } => { - write!(formatter, "failed to read directory {}: {source}", path.display()) - } - InputError::UnsupportedPath(path) => { - write!(formatter, "unsupported path type: {}", path.display()) - } - } - } -} diff --git a/src/nix-style-linter/lib_test.rs b/src/nix-style-linter/lib_test.rs deleted file mode 100644 index a76df4f..0000000 --- a/src/nix-style-linter/lib_test.rs +++ /dev/null @@ -1,281 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicUsize, Ordering}; - -use nix_style_linter::RunStatus; - -static TEST_DIRECTORY_ID: AtomicUsize = AtomicUsize::new(0); - -#[test] -fn malformed_file_reports_parse_error() { - let workspace = TestWorkspace::new("malformed_file_reports_parse_error"); - let path = workspace.write("broken.nix", "let x = ; in x\n"); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Diagnostics); - assert_eq!(output.stderr, ""); - assert!(output.stdout.starts_with(&format!( - "{}:1:9: parse-error: unexpected TOKEN_SEMICOLON at 8..9", - workspace.path("broken.nix").display() - ))); - assert!(!output.stdout.contains("let-order")); -} - -#[test] -fn forward_reference_reports_let_order() { - let workspace = TestWorkspace::new("forward_reference_reports_let_order"); - let path = workspace.write( - "forward.nix", - "let\n app = package;\n package = \"hello\";\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Diagnostics); - assert_eq!(output.stderr, ""); - assert_eq!( - output.stdout, - format!( - "{}:2:3: let-order: `app` references later let binding `package`\n", - workspace.path("forward.nix").display() - ) - ); -} - -#[test] -fn dependency_ordered_bindings_exit_clean() { - let workspace = TestWorkspace::new("dependency_ordered_bindings_exit_clean"); - let path = workspace.write( - "ordered.nix", - "let\n package = \"hello\";\n app = package;\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn outer_scope_reference_exits_clean() { - let workspace = TestWorkspace::new("outer_scope_reference_exits_clean"); - let path = workspace.write( - "outer.nix", - "let\n package = \"hello\";\nin\nlet\n app = package;\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn nested_lambda_parameter_shadows_later_binding() { - let workspace = TestWorkspace::new("nested_lambda_parameter_shadows_later_binding"); - let path = workspace.write( - "lambda.nix", - "let\n call = package: package;\n package = \"hello\";\nin call\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn nested_let_binding_shadows_later_binding() { - let workspace = TestWorkspace::new("nested_let_binding_shadows_later_binding"); - let path = workspace.write( - "nested-let.nix", - "let\n app = let package = \"inner\"; in package;\n package = \"outer\";\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn earlier_sibling_constant_shared_by_multiple_bindings_exits_clean() { - let workspace = TestWorkspace::new("earlier_sibling_constant_shared_by_multiple_bindings"); - let path = workspace.write( - "shared.nix", - "let\n package = \"hello\";\n app = package;\n shell = package;\nin [ app shell ]\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn previous_line_suppression_disables_let_order() { - let workspace = TestWorkspace::new("previous_line_suppression_disables_let_order"); - let path = workspace.write( - "suppressed.nix", - "let\n # nix-style-linter: disable-next-line let-order -- intentional recursion\n app = package;\n package = app;\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn malformed_suppression_does_not_disable_let_order() { - let workspace = TestWorkspace::new("malformed_suppression_does_not_disable_let_order"); - let path = workspace.write( - "unsuppressed.nix", - "let\n # nix-style-linter: disable-next-line let-order\n app = package;\n package = \"hello\";\nin app\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Diagnostics); - assert_eq!( - output.stdout, - format!( - "{}:3:3: let-order: `app` references later let binding `package`\n", - workspace.path("unsuppressed.nix").display() - ) - ); - assert_eq!(output.stderr, ""); -} - -#[test] -fn unsupported_binding_syntax_is_skipped() { - let workspace = TestWorkspace::new("unsupported_binding_syntax_is_skipped"); - let path = workspace.write( - "unsupported.nix", - "let\n attrs.value = package;\n inherit package;\n package = \"hello\";\nin attrs\n", - ); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn valid_file_exits_clean() { - let workspace = TestWorkspace::new("valid_file_exits_clean"); - let path = workspace.write("valid.nix", "let x = 1; in x\n"); - - let output = run_linter(&[path]); - - assert_eq!(output.status, RunStatus::Clean); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, ""); -} - -#[test] -fn missing_path_reports_tool_error() { - let workspace = TestWorkspace::new("missing_path_reports_tool_error"); - let path = workspace.path("missing.nix"); - - let output = run_linter(&[path.clone()]); - - assert_eq!(output.status, RunStatus::ToolError); - assert_eq!(output.stdout, ""); - assert!(output.stderr.starts_with(&format!( - "error: failed to inspect {}:", - path.display() - ))); -} - -#[test] -fn directory_inputs_recurse_through_nix_files() { - let workspace = TestWorkspace::new("directory_inputs_recurse_through_nix_files"); - workspace.write("ignored.txt", "let x = ; in x\n"); - workspace.write("nested/broken.nix", "let\n x = 1;\n y = ;\nin y\n"); - - let output = run_linter(&[workspace.root.clone()]); - - assert_eq!(output.status, RunStatus::Diagnostics); - assert_eq!(output.stderr, ""); - assert!(output.stdout.starts_with(&format!( - "{}:3:7: parse-error: unexpected TOKEN_SEMICOLON at 19..20", - workspace.path("nested/broken.nix").display() - ))); - assert!(!output.stdout.contains("ignored.txt")); -} - -#[test] -fn empty_invocation_reports_tool_error() { - let output = run_linter(&[]); - - assert_eq!(output.status, RunStatus::ToolError); - assert_eq!(output.stdout, ""); - assert_eq!(output.stderr, "error: expected at least one path\n"); -} - -struct LinterOutput { - status: RunStatus, - stdout: String, - stderr: String, -} - -fn run_linter(paths: &[PathBuf]) -> LinterOutput { - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let status = nix_style_linter::run(paths, &mut stdout, &mut stderr).unwrap(); - - LinterOutput { - status, - stdout: String::from_utf8(stdout).unwrap(), - stderr: String::from_utf8(stderr).unwrap(), - } -} - -struct TestWorkspace { - root: PathBuf, -} - -impl TestWorkspace { - fn new(name: &str) -> Self { - let id = TEST_DIRECTORY_ID.fetch_add(1, Ordering::Relaxed); - let root = std::env::temp_dir().join(format!( - "nix-style-linter-{process}-{name}-{id}", - process = std::process::id() - )); - - if root.exists() { - fs::remove_dir_all(&root).unwrap(); - } - fs::create_dir_all(&root).unwrap(); - - Self { root } - } - - fn path(&self, relative: impl AsRef) -> PathBuf { - self.root.join(relative) - } - - fn write(&self, relative: impl AsRef, contents: &str) -> PathBuf { - let path = self.path(relative); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).unwrap(); - } - fs::write(&path, contents).unwrap(); - path - } -} - -impl Drop for TestWorkspace { - fn drop(&mut self) { - fs::remove_dir_all(&self.root).unwrap(); - } -} diff --git a/src/nix-style-linter/main.rs b/src/nix-style-linter/main.rs deleted file mode 100644 index 4237fbb..0000000 --- a/src/nix-style-linter/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::path::PathBuf; -use std::process::ExitCode; - -fn main() -> ExitCode { - let paths: Vec = std::env::args_os().skip(1).map(PathBuf::from).collect(); - let mut stdout = std::io::stdout().lock(); - let mut stderr = std::io::stderr().lock(); - - match nix_style_linter::run(&paths, &mut stdout, &mut stderr) { - Ok(status) => ExitCode::from(status.code()), - Err(error) => { - eprintln!("error: internal error: {error}"); - ExitCode::from(2) - } - } -} diff --git a/src/xatu/BUILD b/src/xatu/BUILD deleted file mode 100644 index c51e802..0000000 --- a/src/xatu/BUILD +++ /dev/null @@ -1,20 +0,0 @@ -load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") - -rust_library( - name = "xatu_lib", - crate_name = "xatu", - srcs = ["lib.rs"], -) - -rust_binary( - name = "xatu", - crate_name = "xatu_cli", - srcs = ["main.rs"], - deps = [":xatu_lib"], -) - -rust_test( - name = "lib_test", - srcs = ["lib_test.rs"], - deps = [":xatu_lib"], -) diff --git a/src/xatu/Cargo.toml b/src/xatu/Cargo.toml deleted file mode 100644 index 1989b10..0000000 --- a/src/xatu/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "xatu" -version = "0.1.0" -edition = "2024" - -[lib] -path = "lib.rs" - -[[bin]] -name = "xatu" -path = "main.rs" - -[dependencies] diff --git a/src/xatu/lib.rs b/src/xatu/lib.rs deleted file mode 100644 index e3fa985..0000000 --- a/src/xatu/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub const GREETING: &str = "Hello from Xatu"; - -pub fn greeting() -> &'static str { - GREETING -} diff --git a/src/xatu/lib_test.rs b/src/xatu/lib_test.rs deleted file mode 100644 index d38e6d4..0000000 --- a/src/xatu/lib_test.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn greeting_returns_hello_message() { - assert_eq!(xatu::greeting(), "Hello from Xatu"); -} diff --git a/src/xatu/main.rs b/src/xatu/main.rs deleted file mode 100644 index c532cbf..0000000 --- a/src/xatu/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("{}", xatu::greeting()); -}