diff --git a/doc/build-helpers/testers.chapter.md b/doc/build-helpers/testers.chapter.md index 632b11ab12ea..5de01694e718 100644 --- a/doc/build-helpers/testers.chapter.md +++ b/doc/build-helpers/testers.chapter.md @@ -98,6 +98,14 @@ It has two modes: : The path to the files to check. +`relocatable` (boolean, optional) {#tester-lycheeLinkCheck-param-relocatable} + +: Whether the site is expected to be relocatable, i.e. servable from any URL path prefix. + + When `true` (the default), root-relative links (starting with `/`) are treated as errors, because they break when the site is served from a subpath or opened via `file://` URLs. + + When `false`, root-relative links are resolved against the `site` directory. + `remap` (attribute set, optional) {#tester-lycheeLinkCheck-param-remap} : An attribute set where the attribute names are regular expressions. diff --git a/pkgs/build-support/testers/lychee.nix b/pkgs/build-support/testers/lychee.nix index 493ef3e880f9..eb2ddef13152 100644 --- a/pkgs/build-support/testers/lychee.nix +++ b/pkgs/build-support/testers/lychee.nix @@ -7,7 +7,7 @@ deps@{ writeShellApplication, }: let - inherit (lib) mapAttrsToList throwIf; + inherit (lib) mapAttrsToList optionalString throwIf; inherit (lib.strings) hasInfix hasPrefix escapeNixString; toURL = @@ -34,6 +34,7 @@ let lycheeLinkCheck = { site, + relocatable ? null, remap ? { }, lychee ? deps.lychee, extraConfig ? { }, @@ -55,6 +56,11 @@ let inherit lychee remap; config = { include_fragments = "full"; + root_dir = + if relocatable == false then + finalAttrs.site + else + "/root-relative-links-are-forbidden-use-relative-links"; } // lib.optionalAttrs (finalAttrs.passthru.remap != { }) { remap = mapAttrsToList ( @@ -62,6 +68,9 @@ let ) finalAttrs.passthru.remap; } // extraConfig; + # NOTE: The online wrapper does not implement the relocatable hint message. + # It uses the same configFile (with the fake root_dir), so root-relative + # links still fail, but without the custom explanation. online = writeShellApplication { name = "run-lychee-online"; runtimeInputs = [ finalAttrs.passthru.lychee ]; @@ -77,7 +86,33 @@ let }; buildCommand = '' echo Checking internal links on $site - lychee --offline --config $configFile "''${extraArgs[@]}" $site + rc=0 + lychee --offline --config $configFile "''${extraArgs[@]}" $site 2>&1 | tee lychee.log || rc="''${PIPESTATUS[0]}" + ${optionalString (relocatable != false) '' + if [ "$rc" -ne 0 ] && grep -qF "[ERROR] file:///root-relative-links-are-forbidden" lychee.log; then + echo + ${ + if relocatable == null then + '' + echo "❄️ ⚠️ Your site contains root-relative links (starting with '/')." + echo "Please set the relocatable parameter in lycheeLinkCheck:" + echo " - relocatable = true: root-relative links are forbidden because they" + echo " break when the site is served from a subpath or opened via file:// URLs." + echo " - relocatable = false: root-relative links are allowed because the" + echo " site is always served from the root." + '' + else + '' + echo "❄️ ⚠️ Root-relative links (starting with '/') are not allowed because this" + echo "site is marked as relocatable (relocatable = true)." + '' + } + echo "See https://nixos.org/manual/nixpkgs/unstable/#tester-lycheeLinkCheck-param-relocatable" + fi + ''} + if [ "$rc" -ne 0 ]; then + exit "$rc" + fi touch $out ''; }); diff --git a/pkgs/by-name/ly/lychee/package.nix b/pkgs/by-name/ly/lychee/package.nix index 523513c1e1e5..97422a46de71 100644 --- a/pkgs/by-name/ly/lychee/package.nix +++ b/pkgs/by-name/ly/lychee/package.nix @@ -84,6 +84,7 @@ rustPlatform.buildRustPackage (finalAttrs: { ok = callPackage ./tests/ok.nix { }; fail = callPackage ./tests/fail.nix { }; fail-emptyDirectory = callPackage ./tests/fail-emptyDirectory.nix { }; + fail-rootRelative = callPackage ./tests/fail-rootRelative.nix { }; network = testers.runNixOSTest ./tests/network.nix; }; diff --git a/pkgs/by-name/ly/lychee/tests/fail-rootRelative.nix b/pkgs/by-name/ly/lychee/tests/fail-rootRelative.nix new file mode 100644 index 000000000000..3fa5defac3ee --- /dev/null +++ b/pkgs/by-name/ly/lychee/tests/fail-rootRelative.nix @@ -0,0 +1,21 @@ +{ runCommand, testers }: +let + sitePkg = runCommand "site" { } '' + dist=$out/dist + mkdir -p $dist + echo "
hi" > $dist/index.html + echo "home" > $dist/page.html + ''; + + linkCheck = testers.lycheeLinkCheck { + site = sitePkg + "/dist"; + }; + + failure = testers.testBuildFailure linkCheck; + +in +runCommand "link-check-fail" { inherit failure; } '' + grep -F "root-relative-links-are-forbidden-use-relative-links/index.html" $failure/testBuildFailure.log >/dev/null + grep -F "Please set the relocatable parameter" $failure/testBuildFailure.log >/dev/null + touch $out +'' diff --git a/pkgs/by-name/ly/lychee/tests/ok.nix b/pkgs/by-name/ly/lychee/tests/ok.nix index b93b93384ba1..e2eb4f9f939f 100644 --- a/pkgs/by-name/ly/lychee/tests/ok.nix +++ b/pkgs/by-name/ly/lychee/tests/ok.nix @@ -5,10 +5,12 @@ let mkdir -p $dist echo "foobar" > $dist/index.html echo "index" > $dist/foo.html + echo "home" > $dist/root-relative.html ''; in testers.lycheeLinkCheck rec { site = sitePkg + "/dist"; + relocatable = false; remap = { "https://example.com" = site; };