diff options
author | tv <tv@shackspace.de> | 2015-07-11 19:44:49 +0200 |
---|---|---|
committer | tv <tv@shackspace.de> | 2015-07-11 19:44:49 +0200 |
commit | bd65d2be622369d4f4b55a1d5e64aedf58506189 (patch) | |
tree | 22ddca93839a9cb9efb03fcc807dc12b1b9ea8a8 /4lib/tv | |
parent | 2bc5c58d85990e483af8fde57ed5f2442351b69c (diff) | |
parent | d213df5c00d3073d2f3bc09471fce466153df881 (diff) |
Merge branch 'next'
Diffstat (limited to '4lib/tv')
-rw-r--r-- | 4lib/tv/default.nix | 62 | ||||
-rw-r--r-- | 4lib/tv/git.nix | 181 | ||||
-rw-r--r-- | 4lib/tv/modules.nix | 21 |
3 files changed, 264 insertions, 0 deletions
diff --git a/4lib/tv/default.nix b/4lib/tv/default.nix new file mode 100644 index 000000000..164a6a1aa --- /dev/null +++ b/4lib/tv/default.nix @@ -0,0 +1,62 @@ +{ lib, pkgs, ... }: + +with builtins; + +let + inherit (lib) mapAttrs stringAsChars; +in + +rec { + git = import ./git.nix { + lib = lib // { + inherit addNames; + }; + inherit pkgs; + }; + + addName = name: set: + set // { inherit name; }; + + addNames = mapAttrs addName; + + + # "7.4.335" -> "74" + majmin = with lib; x : concatStrings (take 2 (splitString "." x)); + + + concat = xs : + if xs == [] + then "" + else head xs + concat (tail xs) + ; + + flip = f : x : y : f y x; + + # isSuffixOf :: String -> String -> Bool + isSuffixOf = + s : xs : + let + sn = stringLength s; + xsn = stringLength xs; + in + xsn >= sn && substring (xsn - sn) sn xs == s ; + + removeSuffix = + s : xs : substring 0 (stringLength xs - stringLength s) xs; + + # setMap :: (String -> a -> b) -> Set String a -> [b] + #setMap = f: xs: map (k : f k (getAttr k xs)) (attrNames xs); + + # setToList :: Set k a -> [a] + #setToList = setMap (_: v: v); + + shell-escape = + let + isSafeChar = c: match "[-./0-9_a-zA-Z]" c != null; + in + stringAsChars (c: + if isSafeChar c then c + else if c == "\n" then "'\n'" + else "\\${c}"); + +} diff --git a/4lib/tv/git.nix b/4lib/tv/git.nix new file mode 100644 index 000000000..8dc176114 --- /dev/null +++ b/4lib/tv/git.nix @@ -0,0 +1,181 @@ +{ lib, pkgs, ... }: + +let + inherit (lib) addNames escapeShellArg makeSearchPath; + + commands = addNames { + git-receive-pack = {}; + git-upload-pack = {}; + }; + + receive-modes = addNames { + fast-forward = {}; + non-fast-forward = {}; + create = {}; + delete = {}; + merge = {}; # TODO implement in git.nix + }; + + permissions = { + fetch = { + allow-commands = [ + commands.git-upload-pack + ]; + }; + + push = ref: extra-modes: { + allow-commands = [ + commands.git-receive-pack + commands.git-upload-pack + ]; + allow-receive-ref = ref; + allow-receive-modes = [ receive-modes.fast-forward ] ++ extra-modes; + }; + }; + + refs = { + master = "refs/heads/master"; + all-heads = "refs/heads/*"; + }; + + irc-announce-script = pkgs.writeScript "irc-announce-script" '' + #! /bin/sh + set -euf + + export PATH=${makeSearchPath "bin" (with pkgs; [ + coreutils + gawk + gnused + netcat + nettools + ])} + + IRC_SERVER=$1 + IRC_PORT=$2 + IRC_NICK=$3$$ + IRC_CHANNEL=$4 + message=$5 + + export IRC_CHANNEL # for privmsg_cat + + # echo2 and cat2 are used output to both, stdout and stderr + # This is used to see what we send to the irc server. (debug output) + echo2() { echo "$*"; echo "$*" >&2; } + cat2() { tee /dev/stderr; } + + # privmsg_cat transforms stdin to a privmsg + privmsg_cat() { awk '{ print "PRIVMSG "ENVIRON["IRC_CHANNEL"]" :"$0 }'; } + + # ircin is used to feed the output of netcat back to the "irc client" + # so we can implement expect-like behavior with sed^_^ + # XXX mkselfdestructingtmpfifo would be nice instead of this cruft + tmpdir="$(mktemp -d irc-announce_XXXXXXXX)" + cd "$tmpdir" + mkfifo ircin + trap " + rm ircin + cd '$OLDPWD' + rmdir '$tmpdir' + trap - EXIT INT QUIT + " EXIT INT QUIT + + { + echo2 "USER $LOGNAME 0 * :$LOGNAME@$(hostname)" + echo2 "NICK $IRC_NICK" + + # wait for MODE message + sed -n '/^:[^ ]* MODE /q' + + echo2 "JOIN $IRC_CHANNEL" + + printf '%s' "$message" \ + | privmsg_cat \ + | cat2 + + echo2 "PART $IRC_CHANNEL" + + # wait for PART confirmation + sed -n '/:'"$IRC_NICK"'![^ ]* PART /q' + + echo2 'QUIT :Gone to have lunch' + } < ircin \ + | nc "$IRC_SERVER" "$IRC_PORT" | tee -a ircin + ''; + + hooks = { + # TODO make this a package? + irc-announce = { nick, channel, server, port ? 6667 }: '' + #! /bin/sh + set -euf + + export PATH=${makeSearchPath "bin" (with pkgs; [ + coreutils + git + gnused + ])} + + nick=${escapeShellArg nick} + channel=${escapeShellArg channel} + server=${escapeShellArg server} + port=${toString port} + + host=$nick + + empty=0000000000000000000000000000000000000000 + + unset message + while read oldrev newrev ref; do + + if [ $oldrev = $empty ]; then + receive_mode=create + elif [ $newrev = $empty ]; then + receive_mode=delete + elif [ "$(git merge-base $oldrev $newrev)" = $oldrev ]; then + receive_mode=fast-forward + else + receive_mode=non-fast-forward + fi + + h=$(echo $ref | sed 's:^refs/heads/::') + + # empty_tree=$(git hash-object -t tree /dev/null + empty_tree=4b825dc6 + + id=$(echo $newrev | cut -b-7) + id2=$(echo $oldrev | cut -b-7) + if [ $newrev = $empty ]; then id=$empty_tree; fi + if [ $oldrev = $empty ]; then id2=$empty_tree; fi + + case $receive_mode in + create) + #git log --oneline $id2 + link="http://$host/cgit/$GIT_SSH_REPO/?h=$h" + ;; + delete) + #git log --oneline $id2 + link="http://$host/cgit/$GIT_SSH_REPO/ ($h)" + ;; + fast-forward|non-fast-forward) + #git diff --stat $id..$id2 + link="http://$host/cgit/$GIT_SSH_REPO/diff/?h=$h&id=$id&id2=$id2" + ;; + esac + + #$host $GIT_SSH_REPO $ref $link + message="''${message+$message + }$GIT_SSH_USER $receive_mode $link" + done + + if test -n "''${message-}"; then + exec ${irc-announce-script} \ + "$server" \ + "$port" \ + "$nick" \ + "$channel" \ + "$message" + fi + ''; + }; + +in +commands // receive-modes // permissions // refs // hooks diff --git a/4lib/tv/modules.nix b/4lib/tv/modules.nix new file mode 100644 index 000000000..248e638ea --- /dev/null +++ b/4lib/tv/modules.nix @@ -0,0 +1,21 @@ +let + pkgs = import <nixpkgs> {}; + inherit (pkgs.lib) concatMap hasAttr; +in rec { + + no-touch-args = { + config = throw "no-touch-args: can't touch config!"; + lib = throw "no-touch-args: can't touch lib!"; + pkgs = throw "no-touch-args: can't touch pkgs!"; + }; + + # list-imports : path -> [path] + # Return a module's transitive list of imports. + # XXX duplicates won't get eliminated from the result. + list-imports = path: + let module = import path no-touch-args; + imports = if hasAttr "imports" module + then concatMap list-imports module.imports + else []; + in [path] ++ imports; +} |