Skip to content

Commit

Permalink
Rewrite sources.nix to support several use cases
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
nlewo committed Apr 8, 2019
1 parent f57c85d commit d7a25ec
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 16 deletions.
82 changes: 66 additions & 16 deletions Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -668,39 +668,89 @@ 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 '<nixpkgs>' is defined and not set to the current path,
# it is imported and fetchers come from it.
# - If '<nixpkgs>' 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 <nixpkgs> {};
nixPathHasNixpkgs = (builtins.tryEval <nixpkgs>).success;
# If nixpkgs is defined in sources.json
sourcesHasNixpkgs = builtins.hasAttr "nixpkgs" sources;
# `<nixpkgs> != ./.` leads to infinite recursion
useNixpkgsFromNixPath = nixPathHasNixpkgs && <nixpkgs> != ./.;
nixpkgsTypeIsTarball = (
# For backward compatibility
! builtins.hasAttr "type" sources.nixpkgs
|| (builtins.hasAttr "type" sources.nixpkgs && sources.nixpkgs.type == "tarball"));

pkgs =
if useNixpkgsFromNixPath
then import <nixpkgs> {}
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);

mapAttrs = builtins.mapAttrs or
(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@
Expand Down
38 changes: 38 additions & 0 deletions script/test-sources
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d7a25ec

Please sign in to comment.