From d7a25ecef73ee465a8d746977f6a5eea53fee52e Mon Sep 17 00:00:00 2001 From: Antoine Eiche Date: Mon, 8 Apr 2019 01:19:11 +0200 Subject: [PATCH] Rewrite sources.nix to support several use cases sources.nix now supports the following use cases: - nixpkgs is not set in the NIX_PATH - nixpkgs is set to ./. - sources.nix is evaluated with the restricted mode (no builtins) --- Main.hs | 82 ++++++++++++++++++++++++++++++++++++--------- script/test-sources | 38 +++++++++++++++++++++ 2 files changed, 104 insertions(+), 16 deletions(-) create mode 100755 script/test-sources diff --git a/Main.hs b/Main.hs index e0b37a9..d86215e 100644 --- a/Main.hs +++ b/Main.hs @@ -668,10 +668,48 @@ initNixSourcesNixContent :: String initNixSourcesNixContent = [s| # This file has been generated by Niv. -# A record, from name to path, of the third-party packages +# These expressions are in charge of fetching sources defined in the +# sources.json file. +# +# We try to use as much as possilbe fetchers from `nixpkgs` because +# - they are supported by the Nix restricted evaluation mode +# - they provide error messages cleaner than builtins fetchers. +# When nixpkgs can not be found, we fallback to builtins fetchers. +# +# - If '' is defined and not set to the current path, +# it is imported and fetchers come from it. +# - If '' is not defined or set to the current path, we try to +# find a `nixpkgs` attribute in `source.json`. +# - If the `nixpkgs` attribute exists, it is fetched with `builtins.fetchTarball` +# and it is imported. It then provides fetchers for other sources. +# - If the `nixpkgs` attribute is not found, we still try to use builtins +# fetchers when possible. + with rec { - pkgs = import {}; + nixPathHasNixpkgs = (builtins.tryEval ).success; + # If nixpkgs is defined in sources.json + sourcesHasNixpkgs = builtins.hasAttr "nixpkgs" sources; + # ` != ./.` leads to infinite recursion + useNixpkgsFromNixPath = nixPathHasNixpkgs && != ./.; + nixpkgsTypeIsTarball = ( + # For backward compatibility + ! builtins.hasAttr "type" sources.nixpkgs + || (builtins.hasAttr "type" sources.nixpkgs && sources.nixpkgs.type == "tarball")); + + pkgs = + if useNixpkgsFromNixPath + then import {} + else if sourcesHasNixpkgs + then pkgsFromSources + else abort "nixpkgs is not found while it is required. You should either set nixpkgs in your NIX_PATH or niv add nixpkgs."; + + # Import nixpkgs from sources.json by using `builtins.fetchTarball` + # to fetch it. + pkgsFromSources = + if nixpkgsTypeIsTarball + then import (builtins.fetchTarball { inherit (sources.nixpkgs) url sha256; }) {} + else abort "The type of nixpkgs must be either tarball or not specified"; sources = builtins.fromJSON (builtins.readFile ./sources.json); @@ -679,28 +717,40 @@ with rec (f: set: with builtins; listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))); + fetchers = { + file = + if useNixpkgsFromNixPath || sourcesHasNixpkgs + then pkgs.fetchurl + else builtins.fetchurl; + tarball = + if useNixpkgsFromNixPath || sourcesHasNixpkgs + then pkgs.fetchzip + else builtins.fetchTarball; + }; + getFetcher = spec: let fetcherName = if builtins.hasAttr "type" spec then builtins.getAttr "type" spec + # For backward compatibility else "tarball"; in builtins.getAttr fetcherName { - "tarball" = pkgs.fetchzip; - "file" = pkgs.fetchurl; + "tarball" = fetchers.tarball; + "file" = fetchers.file; }; + + outPath = spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + if builtins.hasAttr "url" spec && builtins.hasAttr "sha256" spec + then spec // + { outPath = getFetcher spec { inherit (spec) url sha256; } ; } + else spec; + }; -# NOTE: spec must _not_ have an "outPath" attribute -mapAttrs (_: spec: - if builtins.hasAttr "outPath" spec - then abort - "The values in sources.json should not have an 'outPath' attribute" - else - if builtins.hasAttr "url" spec && builtins.hasAttr "sha256" spec - then - spec // - { outPath = getFetcher spec { inherit (spec) url sha256; } ; } - else spec - ) sources +mapAttrs (_: outPath) sources |] -- | @nix/default.nix@ diff --git a/script/test-sources b/script/test-sources new file mode 100755 index 0000000..b707136 --- /dev/null +++ b/script/test-sources @@ -0,0 +1,38 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash +#!nix-shell -I nixpkgs=./nix +#!nix-shell -p nix +#!nix-shell --pure + +set -euo pipefail + +echo "*** Building Niv" +NIV=$(nix-build -A niv)/bin/niv + +echo "*** Running niv init" +TEMPDIR=$(mktemp -d) +pushd $TEMPDIR +$NIV init + +echo "*** Fetching niv sources: classical" +echo " - nixpkgs is not in the NIX_PATH" +echo " - nixpkgs in sources.json" +nix-build nix/sources.nix -A niv + +echo "*** Fetching niv sources: restricted evaluation mode" +echo " - nixpkgs is not in the NIX_PATH" +echo " - nixpkgs in sources.json" +echo " - restrict-eval is true" +export NIX_PATH=./ +nix-build nix/sources.nix -A niv \ + --option restrict-eval true \ + --option allowed-uris https://github.com + +echo "*** Fetching niv sources: only builtins" +echo " - nixpkgs is not in the NIX_PATH" +echo " - nixpkgs not in sources.json" +$NIV drop nixpkgs +nix-build nix/sources.nix -A niv + +echo "*** Tear down" +rm -rf $TEMPDIR