summaryrefslogtreecommitdiff
path: root/Biz
diff options
context:
space:
mode:
Diffstat (limited to 'Biz')
-rw-r--r--Biz/Bild/Deps.nix60
-rw-r--r--Biz/Bild/Nixpkgs.nix13
-rw-r--r--Biz/Bild/Overlay.nix56
-rw-r--r--Biz/Bild/Repl.nix1
-rw-r--r--Biz/Bild/Rules.nix149
-rw-r--r--Biz/Bild/ShellHook.sh98
-rw-r--r--Biz/Bild/Sources.json103
-rw-r--r--Biz/Bild/Sources.nix138
-rw-r--r--Biz/Bild/Wemux.nix12
9 files changed, 630 insertions, 0 deletions
diff --git a/Biz/Bild/Deps.nix b/Biz/Bild/Deps.nix
new file mode 100644
index 0000000..dccbd81
--- /dev/null
+++ b/Biz/Bild/Deps.nix
@@ -0,0 +1,60 @@
+[
+ "MonadRandom"
+ "QuickCheck"
+ "acid-state"
+ "aeson"
+ "async"
+ "bytestring"
+ "capability"
+ "clay"
+ "config-ini"
+ "containers"
+ "directory"
+ "ekg"
+ "envy"
+ "fast-logger"
+ "filepath"
+ "ghcjs-base"
+ "haskeline"
+ "http-types"
+ "ixset"
+ "katip"
+ "lucid"
+ "miso"
+ "monad-logger"
+ "monad-metrics"
+ "mtl"
+ "network-uri"
+ "optparse-simple"
+ "parsec"
+ "process"
+ "protolude"
+ "quickcheck-instances"
+ "random"
+ "regex-applicative"
+ "req"
+ "safecopy"
+ "scotty"
+ "servant"
+ "servant-auth"
+ "servant-auth-server"
+ "servant-lucid"
+ "servant-server"
+ "split"
+ "stm"
+ "string-quote"
+ "tasty"
+ "text"
+ "time"
+ "transformers"
+ "unagi-chan"
+ "unix"
+ "unordered-containers"
+ "vector"
+ "wai"
+ "wai-app-static"
+ "wai-extra"
+ "wai-middleware-metrics"
+ "warp"
+ "x509"
+]
diff --git a/Biz/Bild/Nixpkgs.nix b/Biz/Bild/Nixpkgs.nix
new file mode 100644
index 0000000..21be382
--- /dev/null
+++ b/Biz/Bild/Nixpkgs.nix
@@ -0,0 +1,13 @@
+let
+ sources = import ./Sources.nix;
+ nixpkgs = import sources.nixpkgs {
+ system = __currentSystem;
+ overlays = [
+ (_: _: { inherit sources; })
+ (import ./Overlay.nix)
+ (_: pkgs: pkgs.overridePinnedDeps pkgs.overrideSource)
+ (_: _: { niv = import sources.niv {}; })
+ (_: pkgs: { wemux = pkgs.callPackage ./Wemux.nix {}; })
+ ];
+ };
+in nixpkgs
diff --git a/Biz/Bild/Overlay.nix b/Biz/Bild/Overlay.nix
new file mode 100644
index 0000000..b8fe269
--- /dev/null
+++ b/Biz/Bild/Overlay.nix
@@ -0,0 +1,56 @@
+_: pkgs:
+
+let
+ simpleCabalBuilder = self: name:
+ self.callCabal2nix name pkgs.sources.${name} {};
+ buildCabal = self: name: subdir:
+ if isNull subdir then
+ self.callCabal2nix name pkgs.sources.${name} {}
+ else
+ self.callCabal2nix name (pkgs.sources.${name} + "/${subdir}") {};
+in rec
+{
+ pinnedDeps = builtins.attrNames
+ (builtins.removeAttrs pkgs.sources ["__functor"]);
+ overridePinnedDeps = builder: pkgs.lib.genAttrs pinnedDeps builder;
+
+ # Modifies a derivation with our source and version, keeping old build
+ # rules. This will fail if build steps have changed, or if no build
+ # rules are available upstream..
+ overrideSource = name: pkgs.${name}.overrideAttrs (old: old // rec {
+ name = "${name}-${version}";
+ version = pkgs.sources.${name}.version or pkgs.sources.${name}.rev;
+ src = pkgs.sources.${name};
+ });
+
+ haskell = pkgs.haskell // {
+ packages = pkgs.haskell.packages // {
+ ghc865 = pkgs.haskell.packages.ghc865.override (old: {
+ overrides = with pkgs.pkgs.haskell.lib; self: super:
+ overridePinnedDeps (simpleCabalBuilder self) // {
+ acid-state = dontCheck super.acid-state; # mac: "too many open files"
+ servant-auth = buildCabal self "servant-auth" "servant-auth";
+ wai-middleware-metrics = dontCheck super.wai-middleware-metrics;
+ };
+ });
+ ghcjs = pkgs.haskell.packages.ghcjs.override (old: {
+ overrides = with pkgs.haskell.lib; self: super:
+ overridePinnedDeps (simpleCabalBuilder self) // {
+ Glob = dontCheck super.Glob;
+ QuickCheck = dontCheck super.QuickCheck;
+ base-compat-batteries = dontCheck super.http-types;
+ clay = dontCheck super.clay;
+ comonad = dontCheck super.comonad;
+ jsaddle-warp = dontCheck (self.callCabal2nix "jsaddle-warp" "${pkgs.sources.jsaddle}/jsaddle-warp" {});
+ http-types = dontCheck super.http-types;
+ network-uri= dontCheck super.network-uri;
+ scientific = dontCheck super.scientific; # takes forever
+ servant = dontCheck super.servant;
+ servant-auth = buildCabal self "servant-auth" "servant-auth";
+ tasty-quickcheck = dontCheck super.tasty-quickcheck;
+ time-compat = dontCheck super.time-compat;
+ };
+ });
+ };
+ };
+}
diff --git a/Biz/Bild/Repl.nix b/Biz/Bild/Repl.nix
new file mode 100644
index 0000000..94edf3a
--- /dev/null
+++ b/Biz/Bild/Repl.nix
@@ -0,0 +1 @@
+{ nixpkgs = import ./.; }
diff --git a/Biz/Bild/Rules.nix b/Biz/Bild/Rules.nix
new file mode 100644
index 0000000..6afe9a0
--- /dev/null
+++ b/Biz/Bild/Rules.nix
@@ -0,0 +1,149 @@
+{ nixpkgs }:
+
+with nixpkgs;
+
+let
+ # provided by .envrc
+ root = builtins.getEnv "BIZ_ROOT";
+
+ # general functions to put in a lib
+ lines = s: lib.strings.splitString "\n" s;
+ removeNull = ls: builtins.filter (x: x != null) ls;
+
+ depsToPackageSet = packageSet: deps:
+ lib.attrsets.attrVals deps packageSet;
+
+ # returns true if a is a subset of b, where a and b are attrsets
+ subset = a: b: builtins.all
+ (x: builtins.elem x b) a;
+
+ allDeps = import ./Deps.nix;
+
+ # gather data needed for compiling by analyzing the main module
+ analyze = main: rec {
+ # path to the module relative to the git root
+ relpath = builtins.replaceStrings ["${root}/"] [""]
+ (builtins.toString main);
+ # Haskell-appropriate name of the module
+ module = builtins.replaceStrings ["/" ".hs"] ["." ""] relpath;
+ # file contents
+ content = builtins.readFile main;
+ # search for the ': exe' declaration
+ exe = builtins.head (lib.lists.flatten (removeNull
+ (map (builtins.match "^-- : exe ([[:alnum:]._-]*)$")
+ (lines content))));
+ # collect all of the ': dep' declarations
+ deps = lib.lists.flatten (removeNull
+ (map (builtins.match "^-- : dep ([[:alnum:]._-]*)$")
+ (lines content)));
+ };
+
+ mkGhc = compiler: (deps: compiler (hp:
+ if (subset deps allDeps)
+ then depsToPackageSet hp deps
+ else throw ''
+ missing from nix/haskell-deps.nix:
+ ${toString (lib.lists.subtractLists allDeps deps)}
+ ''));
+
+ ghc_ = mkGhc pkgs.haskell.packages.ghc865.ghcWithHoogle;
+ ghcjs_ = mkGhc pkgs.haskell.packages.ghcjs.ghcWithPackages;
+in {
+ ghc = main:
+ let
+ data = analyze main;
+ ghc = ghc_ data.deps;
+ in stdenv.mkDerivation {
+ name = data.module;
+ src = ../.;
+ nativeBuildInputs = [ ghc ];
+ strictDeps = true;
+ buildPhase = ''
+ mkdir -p $out/bin
+ # compile with ghc
+ ${ghc}/bin/ghc -Werror -Weverything -i. \
+ --make ${main} \
+ -main-is ${data.module} \
+ -o $out/bin/${data.exe}
+ '';
+ # the install process was handled above
+ installPhase = "exit 0";
+ } // { env = ghc; };
+
+ ghcjs = main:
+ let
+ data = analyze main;
+ ghcjs = ghcjs_ data.deps;
+ in stdenv.mkDerivation {
+ name = data.module;
+ src = ../.;
+ nativeBuildInputs = [ ghcjs ];
+ strictDeps = true;
+ buildPhase = ''
+ mkdir -p $out/static
+ # compile with ghcjs
+ ${ghcjs}/bin/ghcjs -Werror -Weverything -i. \
+ --make ${main} \
+ -main-is ${data.module} \
+ -o ${data.exe}
+ # optimize js output
+ ${pkgs.closurecompiler}/bin/closure-compiler \
+ ${data.exe}/all.js > $out/static/${data.exe}
+ '';
+ installPhase = "exit 0";
+ } // { env = ghcjs; };
+
+ env = mkShell {
+ name = "bizdev";
+ buildInputs = [
+ (ghc_ allDeps)
+ # ghcjs doesn't need everything, and many things fail to build
+ (ghcjs_ [
+ "aeson"
+ "clay"
+ "containers"
+ "miso"
+ "protolude"
+ "servant"
+ "split"
+ "string-quote"
+ "text"
+ "ghcjs-base"
+ ])
+
+ nixpkgs.figlet
+ nixpkgs.hlint
+ nixpkgs.lolcat
+ nixpkgs.niv.niv
+ nixpkgs.ormolu
+ nixpkgs.python37Packages.black
+ nixpkgs.python37Packages.pylint
+ nixpkgs.wemux
+ ];
+ shellHook = ". ${./ShellHook.sh}";
+ };
+
+ os = cfg: (nixos (args: lib.attrsets.recursiveUpdate cfg {
+ boot.cleanTmpDir = true;
+ networking.firewall.allowPing = true;
+ nix.binaryCaches = [ "https://cache.nixos.org" ];
+ nix.gc.automatic = true;
+ nix.gc.dates = "Sunday 02:15";
+ nix.optimise.automatic = true;
+ nix.optimise.dates = [ "Sunday 02:30" ];
+ nixpkgs.overlays = overlays;
+ programs.mosh.enable = true;
+ programs.mosh.withUtempter = true;
+ security.acme.email = "ben@bsima.me";
+ security.acme.acceptTerms = true;
+ security.sudo.wheelNeedsPassword = false;
+ services.clamav.daemon.enable = true; # security
+ services.clamav.updater.enable = true; # security
+ services.fail2ban.enable = true; # security
+ services.openssh.enable = true;
+ services.openssh.openFirewall = true;
+ services.openssh.forwardX11 = true;
+ services.openssh.passwordAuthentication = false;
+ system.autoUpgrade.enable = false; # 'true' breaks our nixpkgs pin
+ })).toplevel;
+}
diff --git a/Biz/Bild/ShellHook.sh b/Biz/Bild/ShellHook.sh
new file mode 100644
index 0000000..75a0842
--- /dev/null
+++ b/Biz/Bild/ShellHook.sh
@@ -0,0 +1,98 @@
+function help() {
+ echo ""
+ echo "bizdev" | figlet | lolcat
+ echo ""
+ echo " bild compile code"
+ echo " deps manage dependencies with niv"
+ echo " ghci start ghci with correct options"
+ echo " help show this message"
+ echo " hero compile and start a dev server for herocomics.app"
+ echo " lint auto-lint all changed files"
+ echo " pie product improvement engine"
+ echo " push send a namespace to the cloud"
+ echo " ship lint, bild, and push one (or all) namespace(s)"
+}
+
+function bild() {
+ runghc Biz.Bild $@
+}
+
+function deps() {
+ niv --sources-file $BIZ_ROOT/Biz/Bild/Sources.json $@
+}
+
+alias ghci="ghci -i$BIZ_ROOT -ghci-script $BIZ_ROOT/.ghci"
+
+function hero() {
+ export HERO_PORT=3000
+ export HERO_KEEP=$BIZ_ROOT/_/keep
+ export HERO_SKEY=$BIZ_ROOT/_/skey
+ bild="runghc Biz.Bild"
+ if [[ ! -z "${IN_NIX_SHELL}" ]]
+ then
+ out="_/bild/dev"
+ # in dev mode, mmc.js is a directory of js assets
+ export HERO_NODE=$BIZ_ROOT/$out/static/mmc.js
+ rg --files \
+ | entr -rcs \
+ "$bild Hero.Host.hs && $bild Hero.Node.hs && $out/bin/mmc"
+ else
+ out="_/bild/nix"
+ export HERO_NODE=$BIZ_ROOT/$out/Hero.Node/static
+ rg --files \
+ | entr -rcs \
+ "$bild Hero.Host && $bild Hero.Node && $out/Hero.Host/bin/mmc"
+ fi
+}
+
+function lint() {
+ alias lint=$BIZ_ROOT/Biz/lint.py
+}
+
+function pie() {
+ runghc Biz.Pie $@
+}
+
+# TODO: convert to haskell
+function push() {
+ prefix=$(echo $PWD | sed -e "s|^$BIZ_ROOT/*||g" -e "s|/|.|g")
+ if [[ "$prefix" == "" ]]
+ then
+ target="$1"
+ else
+ target="$prefix.$1"
+ fi
+ what=$(realpath "$BIZ_ROOT/_/bild/$target")
+ # hack: get the domain from the activation script. there does not seem
+ # to be a way to get it from nix-instantiate
+ where=$(rg -r '$2' -e '(domainname ")(.*)(")' "$what/activate")
+ nix copy --to ssh://root@$where $what
+ ssh root@$where $what/bin/switch-to-configuration switch
+ ssh root@$where nix-env --profile /nix/var/nix/profiles/system --set $what
+}
+
+# TODO: convert to haskell
+function ship() {
+ set -ex
+ $BIZ_ROOT/Biz/lint.py
+ stuff=(${1})
+ if [[ ${#stuff[@]} -eq 0 ]]
+ then
+ stuff=(
+ Biz.Cloud
+ Biz.Dev
+ Que.Prod
+ Hero.Prod
+ )
+ fi
+ for thing in ${stuff[@]}
+ do
+ bild $thing
+ done
+ for thing in ${stuff[@]}
+ do
+ push $thing
+ done
+}
+
+help
diff --git a/Biz/Bild/Sources.json b/Biz/Bild/Sources.json
new file mode 100644
index 0000000..d2565a7
--- /dev/null
+++ b/Biz/Bild/Sources.json
@@ -0,0 +1,103 @@
+{
+ "clay": {
+ "branch": "master",
+ "description": "A CSS preprocessor as embedded Haskell.",
+ "homepage": "",
+ "owner": "sebastiaanvisser",
+ "repo": "clay",
+ "rev": "dcc4fc6d8b55af4814bd3f9bbb6d32e2fa2751a8",
+ "sha256": "1dm71z1q7yaq0kl2yb0vr0lsbd8byq5qkdb2kvr26jq48nfq2xdc",
+ "type": "tarball",
+ "url": "https://github.com/sebastiaanvisser/clay/archive/dcc4fc6d8b55af4814bd3f9bbb6d32e2fa2751a8.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
+ "version": "cc7729b1b42a79e261091ff7835f7fc2a7ae3cee"
+ },
+ "jsaddle": {
+ "branch": "master",
+ "description": "JavaScript interface that works with GHCJS or GHC",
+ "homepage": "",
+ "owner": "ghcjs",
+ "repo": "jsaddle",
+ "rev": "d569be43f92b9b8c01dc3ee4c41401ab406a2076",
+ "sha256": "1m1xxy4l9ii91k1k504qkxh9k1ybprm1m66mkb9dqlwcpyhcccmv",
+ "type": "tarball",
+ "url": "https://github.com/ghcjs/jsaddle/archive/d569be43f92b9b8c01dc3ee4c41401ab406a2076.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
+ "version": "1e39844"
+ },
+ "miso": {
+ "branch": "master",
+ "description": ":ramen: A tasty Haskell front-end framework",
+ "homepage": "https://haskell-miso.org",
+ "owner": "dmjio",
+ "repo": "miso",
+ "rev": "41234e419d6177fe05913a1bd885f811afe5cc9f",
+ "sha256": "1nby1y8yixv0a47h1bzdfjcwzah3km7bfd0phdb520ci4dgs30w1",
+ "type": "tarball",
+ "url": "https://github.com/dmjio/miso/archive/41234e419d6177fe05913a1bd885f811afe5cc9f.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
+ "version": "1.5"
+ },
+ "niv": {
+ "branch": "master",
+ "description": "Easy dependency management for Nix projects",
+ "homepage": "https://github.com/nmattia/niv",
+ "owner": "nmattia",
+ "repo": "niv",
+ "rev": "f73bf8d584148677b01859677a63191c31911eae",
+ "sha256": "0jlmrx633jvqrqlyhlzpvdrnim128gc81q5psz2lpp2af8p8q9qs",
+ "type": "tarball",
+ "url": "https://github.com/nmattia/niv/archive/f73bf8d584148677b01859677a63191c31911eae.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "nixpkgs": {
+ "branch": "nixos-19.09",
+ "description": "Nix Packages collection",
+ "homepage": "https://github.com/NixOS/nixpkgs",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "b0c285807d6a9f1b7562ec417c24fa1a30ecc31a",
+ "sha256": "0waapr7aqz0h1fy1fqlx981ygllh91qx9sz1l2j2h59s46cdircl",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/b0c285807d6a9f1b7562ec417c24fa1a30ecc31a.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "regex-applicative": {
+ "branch": "master",
+ "description": "Regex-based parsing with applicative interface",
+ "homepage": "",
+ "owner": "feuerbach",
+ "repo": "regex-applicative",
+ "rev": "449519c38e65753345e9a008362c011cb7a0a4d9",
+ "revision": "449519c38e65753345e9a008362c011cb7a0a4d9",
+ "sha256": "1vdrhsjzij5dm7rn10sic5dv9574yb0lyhzfv9psh7b08dsj8g1k",
+ "type": "tarball",
+ "url": "https://github.com/feuerbach/regex-applicative/archive/449519c38e65753345e9a008362c011cb7a0a4d9.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
+ "version": "0.3.4"
+ },
+ "servant-auth": {
+ "branch": "master",
+ "description": null,
+ "homepage": null,
+ "owner": "haskell-servant",
+ "repo": "servant-auth",
+ "rev": "696fab268e21f3d757b231f0987201b539c52621",
+ "sha256": "1had0xyh511q7ggw2mlfhhk7pfbc30gqm2c9gj1y7pbflmsjgjda",
+ "type": "tarball",
+ "url": "https://github.com/haskell-servant/servant-auth/archive/696fab268e21f3d757b231f0987201b539c52621.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "wemux": {
+ "branch": "master",
+ "description": "Multi-User Tmux Made Easy",
+ "homepage": "",
+ "owner": "zolrath",
+ "repo": "wemux",
+ "rev": "01c6541f8deceff372711241db2a13f21c4b210c",
+ "sha256": "1y962nzvs7sf720pl3wa582l6irxc8vavd0gp4ag4243b2gs4qvm",
+ "type": "tarball",
+ "url": "https://github.com/zolrath/wemux/archive/01c6541f8deceff372711241db2a13f21c4b210c.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ }
+}
diff --git a/Biz/Bild/Sources.nix b/Biz/Bild/Sources.nix
new file mode 100644
index 0000000..8da4974
--- /dev/null
+++ b/Biz/Bild/Sources.nix
@@ -0,0 +1,138 @@
+# This file has been generated by Niv.
+
+let
+
+ #
+ # The fetchers. fetch_<type> fetches specs of type <type>.
+ #
+
+ fetch_file = pkgs: spec:
+ if spec.builtin or true then
+ builtins_fetchurl { inherit (spec) url sha256; }
+ else
+ pkgs.fetchurl { 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_local = spec: spec.path;
+
+ 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'';
+
+ 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
+ #
+
+ # The set of packages used when specs are fetched using non-builtins.
+ mkPkgs = sources:
+ let
+ sourcesNixpkgs =
+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
+ hasThisAsNixpkgsPath = <nixpkgs> == ./.;
+ in
+ if builtins.hasAttr "nixpkgs" sources
+ then sourcesNixpkgs
+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
+ import <nixpkgs> {}
+ else
+ abort
+ ''
+ Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
+ add a package called "nixpkgs" to your sources.json.
+ '';
+
+ # The actual fetching function.
+ fetch = pkgs: name: spec:
+
+ 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 name spec
+ else if spec.type == "git" then fetch_git 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}";
+
+ # Ports of functions for older nix versions
+
+ # a Nix version of mapAttrs if the built-in doesn't exist
+ mapAttrs = builtins.mapAttrs or (
+ f: set: with builtins;
+ 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, name, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchTarball;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchTarball { inherit name url; }
+ else
+ fetchTarball attrs;
+
+ # fetchurl version that is compatible between all the versions of Nix
+ builtins_fetchurl = { url, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchurl;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchurl { inherit url; }
+ else
+ fetchurl attrs;
+
+ # Create the final "sources" from the config
+ mkSources = config:
+ mapAttrs (
+ name: spec:
+ if builtins.hasAttr "outPath" spec
+ then abort
+ "The values in sources.json should not have an 'outPath' attribute"
+ else
+ spec // { outPath = fetch config.pkgs name spec; }
+ ) config.sources;
+
+ # The "config" used by the fetchers
+ mkConfig =
+ { sourcesFile ? ./Sources.json
+ , sources ? builtins.fromJSON (builtins.readFile sourcesFile)
+ , pkgs ? mkPkgs sources
+ }: rec {
+ # The sources, i.e. the attribute set of spec name to spec
+ inherit sources;
+
+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
+ inherit pkgs;
+ };
+in
+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
diff --git a/Biz/Bild/Wemux.nix b/Biz/Bild/Wemux.nix
new file mode 100644
index 0000000..365853f
--- /dev/null
+++ b/Biz/Bild/Wemux.nix
@@ -0,0 +1,12 @@
+{ sources, stdenv }:
+
+stdenv.mkDerivation rec {
+ name = "wemux-${version}";
+ version = "2020.04.03";
+ src = sources.wemux;
+ installPhase = ''
+ mkdir -p $out/bin
+ cp ${src}/wemux $out/bin
+ chmod +x $out/bin/wemux
+ '';
+}