diff --git a/doc/manual/change-authors.yml b/doc/manual/change-authors.yml index f58bb1fc5..22628fccd 100644 --- a/doc/manual/change-authors.yml +++ b/doc/manual/change-authors.yml @@ -62,6 +62,9 @@ ericson: display_name: John Ericson github: ericson2314 +gilice: + forgejo: gilice + goldstein: display_name: goldstein forgejo: goldstein diff --git a/doc/manual/rl-next/flake-lockfile-crash.md b/doc/manual/rl-next/flake-lockfile-crash.md new file mode 100644 index 000000000..4c7d98d0b --- /dev/null +++ b/doc/manual/rl-next/flake-lockfile-crash.md @@ -0,0 +1,18 @@ +--- +synopsis: "Parsing failures in flake.lock no longer crash Lix" +issues: [fj#559] +cls: [2401] +category: "Fixes" +credits: ["gilice"] +--- +Failure to parse `flake.lock` no longer hard-crashes Lix and instead produces a nice error message. + +``` +error: + … while updating the lock file of flake 'git+file:///Users/jade/lix/lix2' + + … while parsing the lock file at /nix/store/mm5dqh8a729yazzj82cjffxl97n5c62s-source//flake.lock + + error: [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; + last read: '#' +``` diff --git a/lix/libexpr/flake/lockfile.cc b/lix/libexpr/flake/lockfile.cc index e1379c116..b56c9025b 100644 --- a/lix/libexpr/flake/lockfile.cc +++ b/lix/libexpr/flake/lockfile.cc @@ -1,5 +1,7 @@ #include "lix/libexpr/flake/lockfile.hh" +#include "json-to-value.hh" #include "lix/libstore/store-api.hh" +#include "lix/libutil/error.hh" #include "lix/libutil/url-parts.hh" #include @@ -186,8 +188,16 @@ std::string LockFile::to_string() const LockFile LockFile::read(const Path & path) { - if (!pathExists(path)) return LockFile(); - return LockFile(nlohmann::json::parse(readFile(path)), path); + if (!pathExists(path)) { + return LockFile(); + } + try { + return LockFile(nlohmann::json::parse(readFile(path)), path); + } catch (nlohmann::json::parse_error &nlohmann_json_parse_exc) { + auto json_parse_error = JSONParseError(nlohmann_json_parse_exc.what()); + json_parse_error.addTrace(nullptr, "while parsing the lock file at %s", path); + throw json_parse_error; + } } std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile) diff --git a/tests/functional2/flakes/test_invalid_flake_lock.py b/tests/functional2/flakes/test_invalid_flake_lock.py new file mode 100644 index 000000000..6480364a0 --- /dev/null +++ b/tests/functional2/flakes/test_invalid_flake_lock.py @@ -0,0 +1,30 @@ +from pathlib import Path +from textwrap import dedent +from functional2.testlib.fixtures import Nix +import re + +def test_invalid_flake_lock(nix: Nix, tmp_path: Path): + flake_dir = tmp_path / 'flake' + flake_dir.mkdir() + + (flake_dir / 'flake.nix').write_text(dedent(""" + { + inputs = {}; + outputs = inputs: {}; + } + """)) + (flake_dir / 'flake.lock').write_text(dedent(""" + { + this flake.lock is obviously invalid + } + """)) + + cmd = nix.nix(["build"], flake=True) + cmd.cwd = flake_dir + res = cmd.run().expect(1) + print(res.stderr_plain) + + ERROR_RE1 = re.compile(fr"while updating the lock file of flake 'path:{flake_dir}.+'") + ERROR_RE2 = re.compile(fr"while parsing the lock file at .+") + assert ERROR_RE1.search(res.stderr_plain) + assert ERROR_RE2.search(res.stderr_plain) diff --git a/version.json b/version.json index 7a7159108..3fe954a5b 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "2.92.0", + "version": "2.92.1", "official_release": false, "release_name": "Bombe glacée" }