Add build instructions for Nix users and update niv sources
7 files changed, 93 insertions(+), 42 deletions(-)

M .hgignore
M README.md
A => default.nix
M nix/sources.json
M nix/sources.nix
M shell.nix
M sq.egg
M .hgignore +1 -0
@@ 6,4 6,5 @@ syntax: glob
 *.o
 *.so
 ./chicken/
+./result/
 ./sq

          
M README.md +20 -0
@@ 27,6 27,26 @@ chicken-install sq
 Because sq calls jq internally, you will also need to install jq according to
 the [download instructions][jq/download] for your platform.
 
+[Nix][] users can build the application with the following commands:
+
+``` sh
+nix-shell --run "chicken-install"
+nix-build
+```
+
+The result will be linked from `./result` and can be called via `./result/bin/sq`.
+This derivation includes jq, so there's no need to install it separately.
+
+Alternatively, you can produce a static binary with the following command:
+
+``` sh
+nix-shell --run "chicken-install -feature static-executable" --arg musl true
+```
+
+The resulting executable will be placed in the current directory at `./sq`, but
+can be freely relocated. Note this method does *not* include jq automatically.
+
+[Nix]: https://nixos.org/
 [CHICKEN 5.2]: https://code.call-cc.org/
 [jq/download]: https://stedolan.github.io/jq/download/
 

          
A => default.nix +9 -0
@@ 0,0 1,9 @@ 
+let
+  pkgs = import (import ./nix/sources.nix).nixpkgs {};
+in pkgs.stdenv.mkDerivation {
+  name = "sq";
+  src = ./.;
+  buildInputs = [ pkgs.makeWrapper ];
+  installPhase = "install -m 755 ./sq -D $out/bin/sq";
+  fixupPhase = "wrapProgram $out/bin/sq --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.jq ]}";
+}

          
M nix/sources.json +6 -6
@@ 12,15 12,15 @@ 
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     },
     "nixpkgs": {
-        "branch": "nixos-19.09",
-        "description": "DEPRECATED! This is an obsolete, read-only mirror of the NixOS/nixpkgs repository.",
+        "branch": "nixos-20.09",
+        "description": "Nix Packages collection",
         "homepage": "https://github.com/NixOS/nixpkgs",
         "owner": "NixOS",
-        "repo": "nixpkgs-channels",
-        "rev": "75f4ba05c63be3f147bcc2f7bd4ba1f029cedcb1",
-        "sha256": "157c64220lf825ll4c0cxsdwg7cxqdx4z559fdp7kpz0g6p8fhhr",
+        "repo": "nixpkgs",
+        "rev": "e065200fc90175a8f6e50e76ef10a48786126e1c",
+        "sha256": "157ih9h1j9r4rf5ppv4yhin73k664bzclsy9c791crx9j5db0l7a",
         "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs-channels/archive/75f4ba05c63be3f147bcc2f7bd4ba1f029cedcb1.tar.gz",
+        "url": "https://github.com/NixOS/nixpkgs/archive/e065200fc90175a8f6e50e76ef10a48786126e1c.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     }
 }

          
M nix/sources.nix +46 -32
@@ 12,36 12,29 @@ let
     else
       pkgs.fetchurl { inherit (spec) url sha256; };
 
-  fetch_tarball = pkgs: spec:
-    if spec.builtin or true then
-      builtins_fetchTarball { inherit (spec) url sha256; }
-    else
-      pkgs.fetchzip { inherit (spec) url sha256; };
+  fetch_tarball = pkgs: name: spec:
+    let
+      ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
+      # sanitize the name, though nix will still fail if name starts with period
+      name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
+    in
+      if spec.builtin or true then
+        builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
+      else
+        pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
 
   fetch_git = spec:
     builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
 
-  fetch_builtin-tarball = spec:
-    builtins.trace
-      ''
-        WARNING:
-          The niv type "builtin-tarball" will soon be deprecated. You should
-          instead use `builtin = true`.
-
-          $ niv modify <package> -a type=tarball -a builtin=true
-      ''
-      builtins_fetchTarball { inherit (spec) url sha256; };
+  fetch_local = spec: spec.path;
 
-  fetch_builtin-url = spec:
-    builtins.trace
-      ''
-        WARNING:
-          The niv type "builtin-url" will soon be deprecated. You should
-          instead use `builtin = true`.
+  fetch_builtin-tarball = name: throw
+    ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
+        $ niv modify ${name} -a type=tarball -a builtin=true'';
 
-          $ niv modify <package> -a type=file -a builtin=true
-      ''
-      (builtins_fetchurl { inherit (spec) url sha256; });
+  fetch_builtin-url = name: throw
+    ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
+        $ niv modify ${name} -a type=file -a builtin=true'';
 
   #
   # Various helpers

          
@@ 72,13 65,23 @@ let
     if ! builtins.hasAttr "type" spec then
       abort "ERROR: niv spec ${name} does not have a 'type' attribute"
     else if spec.type == "file" then fetch_file pkgs spec
-    else if spec.type == "tarball" then fetch_tarball pkgs spec
+    else if spec.type == "tarball" then fetch_tarball pkgs name spec
     else if spec.type == "git" then fetch_git spec
-    else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
-    else if spec.type == "builtin-url" then fetch_builtin-url spec
+    else if spec.type == "local" then fetch_local spec
+    else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
+    else if spec.type == "builtin-url" then fetch_builtin-url name
     else
       abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
 
+  # If the environment variable NIV_OVERRIDE_${name} is set, then use
+  # the path directly as opposed to the fetched source.
+  replace = name: drv:
+    let
+      saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
+      ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
+    in
+      if ersatz == "" then drv else ersatz;
+
   # Ports of functions for older nix versions
 
   # a Nix version of mapAttrs if the built-in doesn't exist

          
@@ 87,13 90,23 @@ let
     listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
   );
 
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
+  range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
+
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
+  stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
+
+  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
+  stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+  concatStrings = builtins.concatStringsSep "";
+
   # fetchTarball version that is compatible between all the versions of Nix
-  builtins_fetchTarball = { url, sha256 }@attrs:
+  builtins_fetchTarball = { url, name, sha256 }@attrs:
     let
       inherit (builtins) lessThan nixVersion fetchTarball;
     in
       if lessThan nixVersion "1.12" then
-        fetchTarball { inherit url; }
+        fetchTarball { inherit name url; }
       else
         fetchTarball attrs;
 

          
@@ 115,13 128,13 @@ let
         then abort
           "The values in sources.json should not have an 'outPath' attribute"
         else
-          spec // { outPath = fetch config.pkgs name spec; }
+          spec // { outPath = replace name (fetch config.pkgs name spec); }
     ) config.sources;
 
   # The "config" used by the fetchers
   mkConfig =
-    { sourcesFile ? ./sources.json
-    , sources ? builtins.fromJSON (builtins.readFile sourcesFile)
+    { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
+    , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
     , pkgs ? mkPkgs sources
     }: rec {
       # The sources, i.e. the attribute set of spec name to spec

          
@@ 130,5 143,6 @@ let
       # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
       inherit pkgs;
     };
+
 in
 mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

          
M shell.nix +6 -3
@@ 1,9 1,12 @@ 
+{ musl ? false }:
 let
-  repo = "${builtins.getEnv "PWD"}/chicken";
+  repo = "${builtins.toString ./.}/chicken";
   pkgs = import (import ./nix/sources.nix).nixpkgs {};
+  chicken = if musl then pkgs.pkgsMusl.chicken else pkgs.chicken;
 in pkgs.mkShell {
-  CHICKEN_REPOSITORY_PATH = repo;
-  CHICKEN_INSTALL_REPOSITORY = repo;
+  CHICKEN_INSTALL_PREFIX = "${repo}";
+  CHICKEN_REPOSITORY_PATH = "${repo}/lib";
+  CHICKEN_INSTALL_REPOSITORY = "${repo}/lib";
   propagatedBuildInputs = with pkgs; with haskellPackages; [
     chicken
     jq

          
M sq.egg +5 -1
@@ 6,4 6,8 @@ 
  (dependencies optimism r7rs simple-exceptions srfi-18 srfi-60 srfi-145)
  (component-options (csc-options "-X" "module-declarations"))
  (components (extension sq.srfi.180 (source "srfi-180.scm"))
-             (program sq (component-dependencies sq.srfi.180))))
+             (program sq (component-dependencies sq.srfi.180)
+                         (cond-expand (static-extensions (csc-options "-static"))
+                                      (else))
+                         (cond-expand (static-executable (csc-options "-static" "-L" "-static"))
+                                      (else)))))