aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/pkgs/xinclude2nix/default.nix60
-rw-r--r--modules/pkgs/xinclude2nix/xinclude2nix.hs46
2 files changed, 106 insertions, 0 deletions
diff --git a/modules/pkgs/xinclude2nix/default.nix b/modules/pkgs/xinclude2nix/default.nix
new file mode 100644
index 0000000..09a9ab3
--- /dev/null
+++ b/modules/pkgs/xinclude2nix/default.nix
@@ -0,0 +1,60 @@
+{ runCommand, haskellPackages }:
+
+/*
+ Given a list of XML files, produces a Nix file with a list of files included
+ with the XInclude mechanism. The file produced can be imported into other
+ Nix files. This requires read-write mode of evaluation.
+
+ Use case: XML config files with portions of sensitive data (secrets, keys),
+ merged in runtime. With this package, deployment tools like NixOps can be
+ taught to extract keys and deploy them automatically.
+
+
+ Example of input file (for Jenkins):
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <hudson xmlns:xi="http://www.w3.org/2001/XInclude">
+ <useSecurity>true</useSecurity>
+ <authorizationStrategy class="hudson.security.ProjectMatrixAuthorizationStrategy">
+ <permission>hudson.model.Hudson.Read:ip1981</permission>
+ <permission>hudson.model.Item.Build:ip1981</permission>
+ <permission>hudson.model.Item.Cancel:ip1981</permission>
+ <permission>hudson.model.Item.Read:ip1981</permission>
+ <permission>hudson.model.Hudson.Administer:ip1981</permission>
+ </authorizationStrategy>
+ <securityRealm class="org.jenkinsci.plugins.GithubSecurityRealm">
+ <clientID>XXXXXXXXXXXXXXXXXXX</clientID>
+ <xi:include href="/run/keys/github-oauth-XXXXXXXXXXXXXXXXXXX.xml"/>
+ <oauthScopes>read:org,user:email</oauthScopes>
+ </securityRealm>
+ </hudson>
+
+
+ Corresponding output file (/nix/store/abc...xyz-xinclude.nix):
+
+ ["/run/keys/github-oauth-XXXXXXXXXXXXXXXXXXX.xml"]
+
+*/
+
+# XXX: either string or list of strings
+xmlFiles:
+
+let
+
+ inherit (builtins) toString;
+
+ xinclude2nix =
+ let
+ deps = hpkgs: with hpkgs; [ hxt ];
+ ghc = "${haskellPackages.ghcWithPackages deps}/bin/ghc -Wall -static";
+ in runCommand "xinclude2nix" {} ''
+ ${ghc} -o $out ${./xinclude2nix.hs}
+ '';
+
+in runCommand "xinclude.nix" {} ''
+ echo ${xinclude2nix} ${toString xmlFiles} >&2
+ ${xinclude2nix} ${toString xmlFiles} > $out
+ echo -n "$out: " >&2
+ cat "$out" >&2
+''
+
diff --git a/modules/pkgs/xinclude2nix/xinclude2nix.hs b/modules/pkgs/xinclude2nix/xinclude2nix.hs
new file mode 100644
index 0000000..49d34ca
--- /dev/null
+++ b/modules/pkgs/xinclude2nix/xinclude2nix.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE Arrows #-}
+
+{-
+ Takes a list of XML files
+ Parses them for xi:xinclude elements
+ Extract included files
+ Prints list of included files
+-}
+
+module Main where
+
+import Data.List (intercalate, isPrefixOf, stripPrefix)
+import Data.Maybe (fromMaybe)
+import System.Environment (getArgs)
+import Text.XML.HXT.Core ( (>>>), deep, getAttrValue, hasAttr, hasName,
+ isElem, readDocument, returnA, runX)
+
+getXIncludes :: String -> IO [String]
+getXIncludes xmlFileName = runX $ readDocument [] xmlFileName
+ >>> deep (isElem >>> hasName "xi:include" >>> hasAttr "href") >>>
+ proc d -> do
+ href <- getAttrValue "href" -< d
+ returnA -< href
+
+getFiles :: [String] -> [String]
+getFiles = map stripScheme . filter isFile
+ where
+ fileScheme = "file://"
+ isFile s = "/" `isPrefixOf` s || (fileScheme `isPrefixOf` s)
+ stripScheme u = fromMaybe u (stripPrefix fileScheme u)
+
+unique :: [String] -> [String]
+unique [] = []
+unique (x:xs)
+ | x `elem` xs = unique xs
+ | otherwise = x:unique xs
+
+toNix :: [String] -> String
+toNix ss = "[" ++ intercalate " " (map show ss) ++ "]"
+
+main :: IO ()
+main = do
+ paths <- getArgs
+ includedFiles <- unique . getFiles . concat <$> mapM getXIncludes paths
+ putStrLn $ toNix includedFiles
+