Skip to content

Commit e73b9db

Browse files
committed
tests.nixpkgs-check-by-name: Apply feedback from review
NixOS/nixpkgs#285089 (review) Many thanks, Philip Taron!
1 parent 8298339 commit e73b9db

File tree

7 files changed

+247
-274
lines changed

7 files changed

+247
-274
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ lazy_static = "1.4.0"
1515
colored = "2.0.4"
1616
itertools = "0.11.0"
1717
rowan = "0.15.11"
18-
indoc = "2.0.4"
1918

2019
[dev-dependencies]
2120
temp-env = "0.3.5"
21+
indoc = "2.0.4"

src/eval.rs

Lines changed: 163 additions & 159 deletions
Large diffs are not rendered by default.

src/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::nix_file::NixFileCache;
1+
use crate::nix_file::NixFileStore;
22
mod eval;
33
mod nix_file;
44
mod nixpkgs_problem;
@@ -118,7 +118,7 @@ pub fn check_nixpkgs<W: io::Write>(
118118
keep_nix_path: bool,
119119
error_writer: &mut W,
120120
) -> validation::Result<ratchet::Nixpkgs> {
121-
let mut nix_file_cache = NixFileCache::new();
121+
let mut nix_file_store = NixFileStore::default();
122122

123123
Ok({
124124
let nixpkgs_path = nixpkgs_path.canonicalize().with_context(|| {
@@ -136,9 +136,9 @@ pub fn check_nixpkgs<W: io::Write>(
136136
)?;
137137
Success(ratchet::Nixpkgs::default())
138138
} else {
139-
check_structure(&nixpkgs_path, &mut nix_file_cache)?.result_map(|package_names|
139+
check_structure(&nixpkgs_path, &mut nix_file_store)?.result_map(|package_names|
140140
// Only if we could successfully parse the structure, we do the evaluation checks
141-
eval::check_values(&nixpkgs_path, &mut nix_file_cache, package_names, keep_nix_path))?
141+
eval::check_values(&nixpkgs_path, &mut nix_file_store, package_names, keep_nix_path))?
142142
}
143143
})
144144
}

src/nix_file.rs

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,27 @@ use std::fs::read_to_string;
1515
use std::path::Path;
1616
use std::path::PathBuf;
1717

18-
/// A structure to indefinitely cache parse results of Nix files in memory,
18+
/// A structure to store parse results of Nix files in memory,
1919
/// making sure that the same file never has to be parsed twice
20-
pub struct NixFileCache {
21-
entries: HashMap<PathBuf, NixFileResult>,
20+
#[derive(Default)]
21+
pub struct NixFileStore {
22+
entries: HashMap<PathBuf, NixFile>,
2223
}
2324

24-
impl NixFileCache {
25-
/// Creates a new empty NixFileCache
26-
pub fn new() -> NixFileCache {
27-
NixFileCache {
28-
entries: HashMap::new(),
29-
}
30-
}
31-
32-
/// Get the cache entry for a Nix file if it exists, otherwise parse the file, insert it into
33-
/// the cache, and return the value
25+
impl NixFileStore {
26+
/// Get the store entry for a Nix file if it exists, otherwise parse the file, insert it into
27+
/// the store, and return the value
3428
///
3529
/// Note that this function only gives an anyhow::Result::Err for I/O errors.
3630
/// A parse error is anyhow::Result::Ok(Result::Err(error))
37-
pub fn get(&mut self, path: &Path) -> anyhow::Result<&NixFileResult> {
31+
pub fn get(&mut self, path: &Path) -> anyhow::Result<&NixFile> {
3832
match self.entries.entry(path.to_owned()) {
3933
Entry::Occupied(entry) => Ok(entry.into_mut()),
4034
Entry::Vacant(entry) => Ok(entry.insert(NixFile::new(path)?)),
4135
}
4236
}
4337
}
4438

45-
/// A type to represent the result when trying to initialise a `NixFile`.
46-
type NixFileResult = Result<NixFile, rnix::parser::ParseError>;
47-
4839
/// A structure for storing a successfully parsed Nix file
4940
pub struct NixFile {
5041
/// The parent directory of the Nix file, for more convenient error handling
@@ -57,7 +48,7 @@ pub struct NixFile {
5748

5849
impl NixFile {
5950
/// Creates a new NixFile, failing for I/O or parse errors
60-
fn new(path: impl AsRef<Path>) -> anyhow::Result<NixFileResult> {
51+
fn new(path: impl AsRef<Path>) -> anyhow::Result<NixFile> {
6152
let Some(parent_dir) = path.as_ref().parent() else {
6253
anyhow::bail!("Could not get parent of path {}", path.as_ref().display())
6354
};
@@ -66,14 +57,21 @@ impl NixFile {
6657
.with_context(|| format!("Could not read file {}", path.as_ref().display()))?;
6758
let line_index = LineIndex::new(&contents);
6859

69-
Ok(rnix::Root::parse(&contents)
60+
// NOTE: There's now another Nixpkgs CI check to make sure all changed Nix files parse
61+
// correctly, though that uses mainline Nix instead of rnix, so it doesn't give the same
62+
// errors. In the future we should unify these two checks, ideally moving the other CI
63+
// check into this tool as well and checking for both mainline Nix and rnix.
64+
rnix::Root::parse(&contents)
65+
// rnix's ::ok returns Result<_, _> , so no error is thrown away like it would be with
66+
// std::result's ::ok
7067
.ok()
7168
.map(|syntax_root| NixFile {
7269
parent_dir: parent_dir.to_path_buf(),
7370
path: path.as_ref().to_owned(),
7471
syntax_root,
7572
line_index,
76-
}))
73+
})
74+
.with_context(|| format!("Could not parse file {} with rnix", path.as_ref().display()))
7775
}
7876
}
7977

@@ -88,7 +86,11 @@ pub struct CallPackageArgumentInfo {
8886

8987
impl NixFile {
9088
/// Returns information about callPackage arguments for an attribute at a specific line/column
91-
/// index. If there's no guaranteed `callPackage` at that location, `None` is returned.
89+
/// index.
90+
/// If the location is not of the form `<attr> = callPackage <arg1> <arg2>;`, `None` is
91+
/// returned.
92+
/// This function only returns `Err` for problems that can't be caused by the Nix contents,
93+
/// but rather problems in this programs code itself.
9294
///
9395
/// This is meant to be used with the location returned from `builtins.unsafeGetAttrPos`, e.g.:
9496
/// - Create file `default.nix` with contents
@@ -102,7 +104,7 @@ impl NixFile {
102104
/// builtins.unsafeGetAttrPos "foo" (import ./default.nix { })
103105
/// ```
104106
/// results in `{ file = ./default.nix; line = 2; column = 3; }`
105-
/// - Get the NixFile for `.file` from a `NixFileCache`
107+
/// - Get the NixFile for `.file` from a `NixFileStore`
106108
/// - Call this function with `.line`, `.column` and `relative_to` as the (absolute) current directory
107109
///
108110
/// You'll get back
@@ -165,6 +167,7 @@ impl NixFile {
165167
};
166168

167169
if attrpath_node.kind() != SyntaxKind::NODE_ATTRPATH {
170+
// This can happen for e.g. `inherit foo`, so definitely not a syntactic `callPackage`
168171
return Ok(None);
169172
}
170173
// attrpath_node looks like "foo.bar"
@@ -183,7 +186,9 @@ impl NixFile {
183186
}
184187
// attrpath_value_node looks like "foo.bar = 10;"
185188

186-
// unwrap is fine because we confirmed that we can cast with the above check
189+
// unwrap is fine because we confirmed that we can cast with the above check.
190+
// We could avoid this `unwrap` for a `clone`, since `cast` consumes the argument,
191+
// but we still need it for the error message when the cast fails.
187192
Ok(Some(ast::AttrpathValue::cast(attrpath_value_node).unwrap()))
188193
}
189194

@@ -272,9 +277,8 @@ impl NixFile {
272277

273278
// Check that <fun2> is an identifier, or an attribute path with an identifier at the end
274279
let ident = match function2 {
275-
Expr::Ident(ident) =>
276-
// This means it's something like `foo = callPackage <arg2> <arg1>`
277-
{
280+
Expr::Ident(ident) => {
281+
// This means it's something like `foo = callPackage <arg2> <arg1>`
278282
ident
279283
}
280284
Expr::Select(select) => {
@@ -340,13 +344,12 @@ pub enum ResolvedPath {
340344

341345
impl NixFile {
342346
/// Statically resolves a Nix path expression and checks that it's within an absolute path
343-
/// path
344347
///
345348
/// E.g. for the path expression `./bar.nix` in `./foo.nix` and an absolute path of the
346349
/// current directory, the function returns `ResolvedPath::Within(./bar.nix)`
347350
pub fn static_resolve_path(&self, node: ast::Path, relative_to: &Path) -> ResolvedPath {
348351
if node.parts().count() != 1 {
349-
// Only if there's more than 1 interpolated part, it's of the form `./foo/${bar}/baz`.
352+
// If there's more than 1 interpolated part, it's of the form `./foo/${bar}/baz`.
350353
return ResolvedPath::Interpolated;
351354
}
352355

@@ -364,9 +367,8 @@ impl NixFile {
364367
// That should be checked more strictly
365368
match self.parent_dir.join(Path::new(&text)).canonicalize() {
366369
Err(resolution_error) => ResolvedPath::Unresolvable(resolution_error),
367-
Ok(resolved) =>
368-
// Check if it's within relative_to
369-
{
370+
Ok(resolved) => {
371+
// Check if it's within relative_to
370372
match resolved.strip_prefix(relative_to) {
371373
Err(_prefix_error) => ResolvedPath::Outside,
372374
Ok(suffix) => ResolvedPath::Within(suffix.to_path_buf()),
@@ -411,7 +413,7 @@ mod tests {
411413

412414
std::fs::write(&file, contents)?;
413415

414-
let nix_file = NixFile::new(&file)??;
416+
let nix_file = NixFile::new(&file)?;
415417

416418
// These are builtins.unsafeGetAttrPos locations for the attributes
417419
let cases = [
@@ -454,7 +456,7 @@ mod tests {
454456

455457
std::fs::write(&file, contents)?;
456458

457-
let nix_file = NixFile::new(&file)??;
459+
let nix_file = NixFile::new(&file)?;
458460

459461
let cases = [
460462
(2, None),

src/nixpkgs_problem.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::structure;
22
use crate::utils::PACKAGE_NIX_FILENAME;
3-
use rnix::parser::ParseError;
43
use std::ffi::OsString;
54
use std::fmt;
65
use std::io;
@@ -58,11 +57,6 @@ pub enum NixpkgsProblem {
5857
subpath: PathBuf,
5958
io_error: io::Error,
6059
},
61-
CouldNotParseNix {
62-
relative_package_dir: PathBuf,
63-
subpath: PathBuf,
64-
error: ParseError,
65-
},
6660
PathInterpolation {
6761
relative_package_dir: PathBuf,
6862
subpath: PathBuf,
@@ -184,14 +178,6 @@ impl fmt::Display for NixpkgsProblem {
184178
relative_package_dir.display(),
185179
subpath.display(),
186180
),
187-
NixpkgsProblem::CouldNotParseNix { relative_package_dir, subpath, error } =>
188-
write!(
189-
f,
190-
"{}: File {} could not be parsed by rnix: {}",
191-
relative_package_dir.display(),
192-
subpath.display(),
193-
error,
194-
),
195181
NixpkgsProblem::PathInterpolation { relative_package_dir, subpath, line, text } =>
196182
write!(
197183
f,

0 commit comments

Comments
 (0)