summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2018-02-28 21:02:21 +0100
committertv <tv@krebsco.de>2018-02-28 21:02:21 +0100
commite89cf20d4310070a877c2e24a287659546b561c9 (patch)
tree18e19a41b65d03782a955235b2a67407157eaa9f /lib
import stockholm's deployment tools
https://cgit.krebsco.de/stockholm 877b4104370c1ea9698a449e376e2842d7c372fd
Diffstat (limited to 'lib')
-rw-r--r--lib/default.nix56
-rw-r--r--lib/types/default.nix8
-rw-r--r--lib/types/populate.nix93
-rw-r--r--lib/types/posix.nix54
4 files changed, 211 insertions, 0 deletions
diff --git a/lib/default.nix b/lib/default.nix
new file mode 100644
index 0000000..7197fe9
--- /dev/null
+++ b/lib/default.nix
@@ -0,0 +1,56 @@
+let {
+
+ body = lib;
+
+ lib = nixpkgs.lib // builtins // {
+
+ evalSource = let
+ eval = source: lib.evalModules {
+ modules = lib.singleton {
+ _file = toString ./.;
+ imports = map (source: { inherit source; }) (lib.toList source);
+ options.source = lib.mkOption {
+ default = {};
+ type = lib.types.attrsOf lib.types.source;
+ };
+ };
+ };
+ sanitize = x: lib.getAttr (lib.typeOf x) {
+ set = lib.mapAttrs
+ (lib.const sanitize)
+ (lib.filterAttrs
+ (name: value: name != "_module" && value != null) x);
+ string = x;
+ };
+ in
+ # This function's return value can be used as pkgs.populate input.
+ source: sanitize (eval source).config.source;
+
+ getHostName = let
+ # We're parsing /etc/hostname here because reading
+ # /proc/sys/kernel/hostname yields ""
+ y = lib.filter lib.types.label.check (lib.splitString "\n" (lib.readFile /etc/hostname));
+ in
+ if lib.length y != 1 then throw "malformed /etc/hostname" else
+ lib.elemAt y 0;
+
+ mkTarget = s: let
+ default = defVal: val: if val != null then val else defVal;
+ parse = lib.match "(([^@]+)@)?(([^:/]+))?(:([^/]+))?(/.*)?" s;
+ elemAt' = xs: i: if lib.length xs > i then lib.elemAt xs i else null;
+ in {
+ user = default (lib.getEnv "LOGNAME") (elemAt' parse 1);
+ host = default (lib.maybeEnv "HOSTNAME" lib.getHostName) (elemAt' parse 3);
+ port = default "22" /* "ssh"? */ (elemAt' parse 5);
+ path = default "/var/src" /* no default? */ (elemAt' parse 6);
+ };
+
+ test = re: x: lib.isString x && lib.testString re x;
+ testString = re: x: lib.match re x != null;
+
+ types = nixpkgs.lib.types // import ./types { lib = body; };
+ };
+
+ nixpkgs.lib = import <nixpkgs/lib>;
+
+}
diff --git a/lib/types/default.nix b/lib/types/default.nix
new file mode 100644
index 0000000..c4bf517
--- /dev/null
+++ b/lib/types/default.nix
@@ -0,0 +1,8 @@
+{ lib }@args: let {
+
+ body = lib.foldl' (res: path: res // import path args) {} [
+ ./populate.nix
+ ./posix.nix
+ ];
+
+}
diff --git a/lib/types/populate.nix b/lib/types/populate.nix
new file mode 100644
index 0000000..3b13df0
--- /dev/null
+++ b/lib/types/populate.nix
@@ -0,0 +1,93 @@
+{ lib }: rec {
+
+ source = lib.types.submodule ({ config, ... }: {
+ options = {
+ type = let
+ known-types = lib.attrNames source-types;
+ type-candidates = lib.filter (k: config.${k} != null) known-types;
+ in lib.mkOption {
+ default = if lib.length type-candidates == 1
+ then lib.head type-candidates
+ else throw "cannot determine type";
+ type = lib.types.enum known-types;
+ };
+ file = lib.mkOption {
+ apply = x:
+ if lib.types.absolute-pathname.check x
+ then { path = x; }
+ else x;
+ default = null;
+ type = lib.types.nullOr (lib.types.either lib.types.absolute-pathname source-types.file);
+ };
+ git = lib.mkOption {
+ default = null;
+ type = lib.types.nullOr source-types.git;
+ };
+ pass = lib.mkOption {
+ default = null;
+ type = lib.types.nullOr source-types.pass;
+ };
+ pipe = lib.mkOption {
+ apply = x:
+ if lib.types.absolute-pathname.check x
+ then { command = x; }
+ else x;
+ default = null;
+ type = lib.types.nullOr (lib.types.either lib.types.absolute-pathname source-types.pipe);
+ };
+ symlink = lib.mkOption {
+ apply = x:
+ if lib.types.pathname.check x
+ then { target = x; }
+ else x;
+ default = null;
+ type = lib.types.nullOr (lib.types.either lib.types.pathname source-types.symlink);
+ };
+ };
+ });
+
+ source-types = {
+ file = lib.types.submodule {
+ options = {
+ path = lib.mkOption {
+ type = lib.types.absolute-pathname;
+ };
+ };
+ };
+ git = lib.types.submodule {
+ options = {
+ ref = lib.mkOption {
+ type = lib.types.str; # TODO lib.types.git.ref
+ };
+ url = lib.mkOption {
+ type = lib.types.str; # TODO lib.types.git.url
+ };
+ };
+ };
+ pass = lib.types.submodule {
+ options = {
+ dir = lib.mkOption {
+ type = lib.types.absolute-pathname;
+ };
+ name = lib.mkOption {
+ type = lib.types.pathname; # TODO relative-pathname
+ };
+ };
+ };
+ pipe = lib.types.submodule {
+ options = {
+ command = lib.mkOption {
+ type = lib.types.absolute-pathname;
+ };
+ };
+ };
+ symlink = lib.types.submodule {
+ options = {
+ target = lib.mkOption {
+ type = lib.types.pathname; # TODO relative-pathname
+ };
+ };
+ };
+ };
+
+}
diff --git a/lib/types/posix.nix b/lib/types/posix.nix
new file mode 100644
index 0000000..e8f464e
--- /dev/null
+++ b/lib/types/posix.nix
@@ -0,0 +1,54 @@
+{ lib }: rec {
+
+ # RFC952, B. Lexical grammar, <hname>
+ hostname = lib.mkOptionType {
+ name = "hostname";
+ check = x: lib.isString x && lib.all label.check (lib.splitString "." x);
+ merge = lib.mergeOneOption;
+ };
+
+ # RFC952, B. Lexical grammar, <name>
+ # RFC1123, 2.1 Host Names and Numbers
+ label = lib.mkOptionType {
+ name = "label";
+ # TODO case-insensitive labels
+ check = lib.test "[0-9A-Za-z]([0-9A-Za-z-]*[0-9A-Za-z])?";
+ merge = lib.mergeOneOption;
+ };
+
+ # POSIX.1‐2013, 3.278 Portable Filename Character Set
+ filename = lib.mkOptionType {
+ name = "POSIX filename";
+ check = lib.test "([0-9A-Za-z._])[0-9A-Za-z._-]*";
+ merge = lib.mergeOneOption;
+ };
+
+ # POSIX.1‐2013, 3.2 Absolute Pathname
+ absolute-pathname = lib.mkOptionType {
+ name = "POSIX absolute pathname";
+ check = x: lib.isString x && lib.substring 0 1 x == "/" && pathname.check x;
+ merge = lib.mergeOneOption;
+ };
+
+ # POSIX.1‐2013, 3.267 Pathname
+ pathname = lib.mkOptionType {
+ name = "POSIX pathname";
+ check = x:
+ let
+ # The filter is used to normalize paths, i.e. to remove duplicated and
+ # trailing slashes. It also removes leading slashes, thus we have to
+ # check for "/" explicitly below.
+ xs = lib.filter (s: lib.stringLength s > 0) (lib.splitString "/" x);
+ in
+ lib.isString x && (x == "/" || (lib.length xs > 0 && lib.all filename.check xs));
+ merge = lib.mergeOneOption;
+ };
+
+ # POSIX.1-2013, 3.431 User Name
+ username = lib.mkOptionType {
+ name = "POSIX username";
+ check = filename.check;
+ merge = lib.mergeOneOption;
+ };
+
+}