From ff48133d0f31f6607a8c35eac27514f299bba3c7 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Thu, 10 Sep 2015 19:50:14 +0200 Subject: [PATCH 01/12] Fix deps in passthrough mode --- nix-script.hs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/nix-script.hs b/nix-script.hs index 3bf3afd..79d567a 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -23,7 +23,8 @@ import Data.Monoid import qualified Data.Text as Text --- | Information about a languages + +-- | Information about a language data LangDef = LangDef { name :: String -- ^ Name of this language , deps :: [Text] -> [Text] -- ^ Convert langunage-specific dependencies to nix packages @@ -31,44 +32,56 @@ data LangDef = LangDef , repl :: FilePath -> (String, [String]) -- ^ Command to load the given file in an interpreter } + +basePackages :: [Text] +basePackages = ["coreutils", "utillinux"] + + languages :: [LangDef] languages = [haskell, python, javascript, perl, shell] haskell :: LangDef haskell = LangDef "haskell" d r i where - d pkgs = return $ + d pkgs = pure $ "haskellPackages.ghcWithPackages (hs: with hs; [" <> Text.unwords pkgs <> "])" r script = ("runhaskell" , [script]) i script = ("ghci" , [script]) python :: LangDef python = LangDef "python" d r i where - d pkgs = "python" : map ("pythonPackages." <>) pkgs + d pkgs = "python" : map ("pythonPackages." <>) pkgs r script = ("python" , [script]) i script = ("python" , ["-i", script]) javascript :: LangDef javascript = LangDef "javascript" d r i where - d pkgs = "node" : map ("nodePackages." <>) pkgs + d pkgs = "node" : map ("nodePackages." <>) pkgs r script = ("node" , [script]) i script = ("node" , []) perl :: LangDef perl = LangDef "perl" d r i where - d pkgs = "perl" : map ("perlPackages." <>) pkgs + d pkgs = "perl" : map ("perlPackages." <>) pkgs r script = ("perl" , [script]) i script = ("perl" , ["-d", script]) shell :: LangDef -shell = LangDef "shell" (extraPackages ++) r i where +shell = LangDef "shell" d r i where + d = mappend ("bash" : basePackages) r script = ("bash", [script]) i _ = ("bash", []) - extraPackages = ["bash", "coreutils", "utillinux", "gitAndTools.hub", "git"] + +passthrough :: String -> LangDef +passthrough name = LangDef name d r i where + d = mappend basePackages + r script = (name, [script]) + i _ = (name, []) + lookupLangDef :: String -> IO LangDef lookupLangDef n | Just def <- find ((n ==) . name) languages = return def - | otherwise = fail $ "Unknown language: " ++ n + | otherwise = return (passthrough n) makeDeps :: String -> [String] -> IO [String] makeDeps lang ds = lookupLangDef lang <&> \def -> From f65181ae3479a5480f47982d9d4350c796101cf0 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 05:08:34 +0200 Subject: [PATCH 02/12] Completely rewrite --- nix-script.hs | 202 +++++++++++++++++++++++++------------------------- 1 file changed, 102 insertions(+), 100 deletions(-) diff --git a/nix-script.hs b/nix-script.hs index 79d567a..be3075d 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -1,131 +1,133 @@ -#!/usr/bin/env nix-script -#!> haskell -#! haskell | text lens -#! shell | nix -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TupleSections #-} +-- | A shebang for running scripts inside nix-shell with defined dependencies +module NixScript where -import Control.Monad -import Control.Applicative -import System.Environment -import Data.List -import Data.Text (Text) -import Data.Text.Lens (_Text) -import Control.Lens -import Control.Exception.Lens -import System.IO.Error.Lens -import System.Exit -import System.Posix.Process -import System.Posix.IO -import System.IO -import Data.Char -import Data.Monoid - -import qualified Data.Text as Text +import Control.Monad (when) +import Data.Maybe (fromMaybe) +import Data.List (isSuffixOf, isPrefixOf, find) +import System.Environment (lookupEnv, getProgName, getArgs) +import System.Process (callProcess) +import System.Posix.IO (createPipe, fdToHandle) +import System.IO (hPutStrLn, hClose, hFlush) -- | Information about a language -data LangDef = LangDef - { name :: String -- ^ Name of this language - , deps :: [Text] -> [Text] -- ^ Convert langunage-specific dependencies to nix packages - , run :: FilePath -> (String, [String]) -- ^ Command to run the given file as script - , repl :: FilePath -> (String, [String]) -- ^ Command to load the given file in an interpreter +data Language = Language + { name :: String + -- ^ Name of the language + , depsTrans :: [String] -> [String] + -- ^ Transform language-specific dependencies to nix packages + , run :: FilePath -> (String, [String]) + -- ^ Command to run the given file as script + , repl :: FilePath -> (String, [String]) + -- ^ Command to load the given file in an interpreter } -basePackages :: [Text] +-- | Basic packages always present +basePackages :: [String] basePackages = ["coreutils", "utillinux"] +-- | Preserved environment variables +baseEnv :: [String] +baseEnv = ["LOCALE_ARCHIVE", "LANG", "TERMINFO", "TERM"] -languages :: [LangDef] + +-- | List of supported language definitions +languages :: [Language] languages = [haskell, python, javascript, perl, shell] + where + haskell = Language "haskell" d r i where + d pkgs = pure ("haskellPackages.ghcWithPackages (hs: with hs; [" ++ + unwords pkgs ++ "])") + r script = ("runghc" , [script]) + i script = ("ghci" , [script]) -haskell :: LangDef -haskell = LangDef "haskell" d r i where - d pkgs = pure $ - "haskellPackages.ghcWithPackages (hs: with hs; [" <> Text.unwords pkgs <> "])" - r script = ("runhaskell" , [script]) - i script = ("ghci" , [script]) + python = Language "python" d r i where + d pkgs = "python" : map ("pythonPackages." ++) pkgs + r script = ("python" , [script]) + i script = ("python" , ["-i", script]) -python :: LangDef -python = LangDef "python" d r i where - d pkgs = "python" : map ("pythonPackages." <>) pkgs - r script = ("python" , [script]) - i script = ("python" , ["-i", script]) + javascript = Language "javascript" d r i where + d pkgs = "node" : map ("nodePackages." ++) pkgs + r script = ("node" , [script]) + i script = ("node" , []) -javascript :: LangDef -javascript = LangDef "javascript" d r i where - d pkgs = "node" : map ("nodePackages." <>) pkgs - r script = ("node" , [script]) - i script = ("node" , []) + perl = Language "perl" d r i where + d pkgs = "perl" : map ("perlPackages." ++) pkgs + r script = ("perl" , [script]) + i script = ("perl" , ["-d", script]) -perl :: LangDef -perl = LangDef "perl" d r i where - d pkgs = "perl" : map ("perlPackages." <>) pkgs - r script = ("perl" , [script]) - i script = ("perl" , ["-d", script]) + shell = Language "shell" d r i where + d = mappend ("bash" : basePackages) + r script = ("bash", [script]) + i _ = ("bash", []) -shell :: LangDef -shell = LangDef "shell" d r i where - d = mappend ("bash" : basePackages) - r script = ("bash", [script]) - i _ = ("bash", []) -passthrough :: String -> LangDef -passthrough name = LangDef name d r i where +-- | Create ad-hoc definitions for unknown languages +passthrough :: String -> Language +passthrough name = Language name d r i where d = mappend basePackages r script = (name, [script]) i _ = (name, []) -lookupLangDef :: String -> IO LangDef -lookupLangDef n - | Just def <- find ((n ==) . name) languages = return def - | otherwise = return (passthrough n) +-- | Find the appropriate language definition +lookupLang :: String -> Language +lookupLang n = + fromMaybe (passthrough n) (find ((n ==) . name) languages) -makeDeps :: String -> [String] -> IO [String] -makeDeps lang ds = lookupLangDef lang <&> \def -> - map (view _Text) $ deps def (map (review _Text) ds) +-- | Parse dependencies declaration line +parseHeader :: String -> [String] +parseHeader = uncurry trans . split . words + where + trans lang = depsTrans (lookupLang lang) + split (lang : "|" : deps) = (lang, deps) + split line = error ("Invalid dependency declaration: " ++ unwords line) -parseDepLine :: [String] -> IO (String, [String]) -parseDepLine (lang:"|":deps) = return (lang, deps) -parseDepLine x = fail $ "Invalid dependency specification: " ++ unwords x -makeCommand :: String -> Bool -> String -> IO (String, [String]) -makeCommand lang interactive file = lookupLangDef lang <&> \def -> - (if interactive then repl else run) def file +-- | Find command to run/load the script +interpreter :: String -> Bool -> String -> (String, [String]) +interpreter lang interactive = + (if interactive then repl else run) (lookupLang lang) -makeEnvArg :: String -> IO String -makeEnvArg env = f $ getEnv env <&> \val -> env ++ "=" ++ val where - f = handling_ (_IOException.errorType._NoSuchThing) $ return "" -makeXargsCommand :: String -> Int -> IO String -makeXargsCommand cmd fd = do - let xargsFile = "/proc/self/fd/" ++ show fd - envStr <- unwords <$> traverse makeEnvArg - ["LOCALE_ARCHIVE", "LANG", "TERMINFO", "TERM"] - return $ "env " ++ envStr ++ " xargs -a " ++ xargsFile ++ " -d '\\n' " ++ cmd ++ "" +-- | Create command to add the shell environment +makeCommand :: String -> [String] -> IO String +makeCommand program args = do + (readFd, writeFd) <- createPipe + writeH <- fdToHandle writeFd + hPutStrLn writeH (unlines args) + hFlush writeH >> hClose writeH + definitions <- mapM format baseEnv + return (env definitions ++ xargs readFd ++ program) + where + env defs = "env " ++ unwords defs ++ " " + xargs fd = "xargs -a /proc/self/fd/" ++ show fd ++ " -d '\\n' " + format var = maybe "" (\x -> var ++ "=" ++ x) <$> lookupEnv var + + +-- | run a script or load it in an interactive interpreter main :: IO () main = do progName <- getProgName - args <- getArgs - let interactive = "i" `isSuffixOf` progName - case args ^? _Cons of - Nothing -> fail $ "usage: " ++ progName ++ " " ++ " [missing file name]" - Just (file, args') -> do - header <- drop 1 . map (drop 2) . takeWhile ("#!" `isPrefixOf`) . lines <$> readFile file - case header ^? _Cons of - Just ('>':lang, depHeader) -> do - deps <- concat <$> traverse (uncurry makeDeps <=< parseDepLine . words) depHeader - let deps' = "findutils" : deps - let depArgs = concatMap (\x -> ["-p", x]) deps' - (cmd,cmdArgs) <- makeCommand (under _Text Text.strip lang) interactive file - (readFd, writeFd) <- createPipe - writeH <- fdToHandle writeFd - hPutStrLn writeH (unlines cmdArgs) >> hFlush writeH - hClose writeH - xargsCmd <- makeXargsCommand cmd (fromIntegral readFd) - let finalArgs = "--pure" : "--command" : xargsCmd : depArgs - executeFile "nix-shell" True finalArgs Nothing - _ -> fail "missing language to run as" + progArgs <- getArgs + + when (null progArgs) (fail $ "usage: " ++ progName ++ " ") + + let file = head progArgs + shebang = takeWhile (isPrefixOf "#!") . lines + header = drop 1 . map (drop 2) . shebang + + script <- readFile file + case header script of + (('>' : identifier) : lines) -> do + let pkgs = concatMap parseHeader lines + language = dropWhile (==' ') identifier + interactive = isSuffixOf "i" progName + (program, args) = interpreter language interactive file + + cmd <- makeCommand program args + callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs) + + _ -> fail "missing or invalid header" \ No newline at end of file From d8852783eaffa692da01db1e683b8264e78ff8a0 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 05:12:40 +0200 Subject: [PATCH 03/12] Add test for arguments handling --- example.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 example.sh diff --git a/example.sh b/example.sh new file mode 100755 index 0000000..8caa463 --- /dev/null +++ b/example.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env nix-script +#!>zsh +#! nix | zsh + +function a { echo "this is zsh!" } +a +echo "your args: $@" \ No newline at end of file From fd3b126eb2b829254d75f7fd14a3a0950f431047 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 05:12:57 +0200 Subject: [PATCH 04/12] Add test for dependencies handling --- example.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example.hs b/example.hs index a2a06bd..f046046 100755 --- a/example.hs +++ b/example.hs @@ -3,6 +3,8 @@ #! haskell | text lens optparse-applicative #! shell | nix nix-prefetch-scripts +import Control.Lens + main :: IO () main = do putStrLn "It works!" From a3a56c2dbbfd5799ecdc7b619365a6e250ec8866 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 05:13:15 +0200 Subject: [PATCH 05/12] Drop dependencies --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 1b10b31..e76e4dc 100644 --- a/default.nix +++ b/default.nix @@ -6,7 +6,7 @@ pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" "fixupPhase" ]; buildPhase = ''mkdir -p $out/bin; ghc -O2 $src -o $out/bin/nix-script -odir $TMP''; installPhase = ''ln -s $out/bin/nix-script $out/bin/nix-scripti''; - buildInputs = [ (pkgs.haskellPackages.ghcWithPackages (hs: with hs; [lens text])) ]; + buildInputs = [ pkgs.haskellPackages.ghc ]; meta = { homepage = https://github.com/bennofs/nix-script; description = "A shebang for running inside nix-shell."; From 332c94e05a0dd0364c32a5e31cbfea8dcb54b315 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 05:16:24 +0200 Subject: [PATCH 06/12] Rename module (must be called Main) --- nix-script.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix-script.hs b/nix-script.hs index be3075d..8795a69 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -1,5 +1,5 @@ -- | A shebang for running scripts inside nix-shell with defined dependencies -module NixScript where +module Main where import Control.Monad (when) import Data.Maybe (fromMaybe) @@ -128,6 +128,7 @@ main = do (program, args) = interpreter language interactive file cmd <- makeCommand program args + putStrLn $ unwords ("--pure" : "--command" : cmd : "-p" : pkgs) callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs) _ -> fail "missing or invalid header" \ No newline at end of file From 8bab98e655bef27b1b07409c80ba7c94b32d2ccc Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 06:19:03 +0200 Subject: [PATCH 07/12] Properly handle arguments --- example.sh | 1 + nix-script.hs | 67 +++++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/example.sh b/example.sh index 8caa463..f3d2084 100755 --- a/example.sh +++ b/example.sh @@ -4,4 +4,5 @@ function a { echo "this is zsh!" } a +echo $# echo "your args: $@" \ No newline at end of file diff --git a/nix-script.hs b/nix-script.hs index 8795a69..eeec84d 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -1,13 +1,17 @@ -- | A shebang for running scripts inside nix-shell with defined dependencies module Main where -import Control.Monad (when) -import Data.Maybe (fromMaybe) -import Data.List (isSuffixOf, isPrefixOf, find) -import System.Environment (lookupEnv, getProgName, getArgs) -import System.Process (callProcess) -import System.Posix.IO (createPipe, fdToHandle) -import System.IO (hPutStrLn, hClose, hFlush) +import Control.Monad (when) +import Data.Maybe (fromMaybe) +import Data.List (isPrefixOf, find) +import System.Environment (lookupEnv, getProgName, getArgs) +import System.Process (callProcess) +import System.Posix.Escape.Unicode (escapeMany) + + +type Env = [String] +type Args = [String] +type Inter = (String, Args) -- | Information about a language @@ -16,9 +20,9 @@ data Language = Language -- ^ Name of the language , depsTrans :: [String] -> [String] -- ^ Transform language-specific dependencies to nix packages - , run :: FilePath -> (String, [String]) + , run :: FilePath -> Inter -- ^ Command to run the given file as script - , repl :: FilePath -> (String, [String]) + , repl :: FilePath -> Inter -- ^ Command to load the given file in an interpreter } @@ -76,6 +80,7 @@ lookupLang :: String -> Language lookupLang n = fromMaybe (passthrough n) (find ((n ==) . name) languages) + -- | Parse dependencies declaration line parseHeader :: String -> [String] parseHeader = uncurry trans . split . words @@ -86,25 +91,24 @@ parseHeader = uncurry trans . split . words -- | Find command to run/load the script -interpreter :: String -> Bool -> String -> (String, [String]) -interpreter lang interactive = +makeInter :: String -> Bool -> String -> Inter +makeInter lang interactive = (if interactive then repl else run) (lookupLang lang) -- | Create command to add the shell environment -makeCommand :: String -> [String] -> IO String -makeCommand program args = do - (readFd, writeFd) <- createPipe - writeH <- fdToHandle writeFd - hPutStrLn writeH (unlines args) - hFlush writeH >> hClose writeH - - definitions <- mapM format baseEnv - return (env definitions ++ xargs readFd ++ program) +makeCmd :: Inter -> Args -> Env -> String +makeCmd (program, args) args' defs = + env defs ++ interpreter ++ escapeMany args' where + interpreter = program ++ " " ++ unwords args ++ " " env defs = "env " ++ unwords defs ++ " " - xargs fd = "xargs -a /proc/self/fd/" ++ show fd ++ " -d '\\n' " - format var = maybe "" (\x -> var ++ "=" ++ x) <$> lookupEnv var + + +-- | Create environment variable to run the script with +makeEnv :: IO Env +makeEnv = mapM format baseEnv where + format var = maybe "" (\x -> var ++ "=" ++ x) <$> lookupEnv var -- | run a script or load it in an interactive interpreter @@ -115,20 +119,19 @@ main = do when (null progArgs) (fail $ "usage: " ++ progName ++ " ") - let file = head progArgs - shebang = takeWhile (isPrefixOf "#!") . lines - header = drop 1 . map (drop 2) . shebang + let shebang = takeWhile (isPrefixOf "#!") . lines + header = drop 1 . map (drop 2) . shebang + (file:args) = progArgs script <- readFile file case header script of - (('>' : identifier) : lines) -> do - let pkgs = concatMap parseHeader lines - language = dropWhile (==' ') identifier - interactive = isSuffixOf "i" progName - (program, args) = interpreter language interactive file + (('>':identifier) : lines) -> do + let pkgs = concatMap parseHeader lines + language = dropWhile (==' ') identifier + interactive = last progName == 'i' + interpreter = makeInter language interactive file - cmd <- makeCommand program args - putStrLn $ unwords ("--pure" : "--command" : cmd : "-p" : pkgs) + cmd <- makeCmd interpreter args <$> makeEnv callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs) _ -> fail "missing or invalid header" \ No newline at end of file From 569d336c7f3540fad6f38f8a3248f443717a8226 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 06:19:17 +0200 Subject: [PATCH 08/12] Add new dependency --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index e76e4dc..6af4803 100644 --- a/default.nix +++ b/default.nix @@ -6,7 +6,7 @@ pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" "fixupPhase" ]; buildPhase = ''mkdir -p $out/bin; ghc -O2 $src -o $out/bin/nix-script -odir $TMP''; installPhase = ''ln -s $out/bin/nix-script $out/bin/nix-scripti''; - buildInputs = [ pkgs.haskellPackages.ghc ]; + buildInputs = [ (pkgs.haskellPackages.ghcWithPackages (hs: with hs; [posix-escape])) ]; meta = { homepage = https://github.com/bennofs/nix-script; description = "A shebang for running inside nix-shell."; From 8f107c011a6c5c322f7ba1034d9d0f41b21eed70 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 16:49:40 +0200 Subject: [PATCH 09/12] Add ssl cacert path variable --- nix-script.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-script.hs b/nix-script.hs index eeec84d..3d82a83 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -33,7 +33,7 @@ basePackages = ["coreutils", "utillinux"] -- | Preserved environment variables baseEnv :: [String] -baseEnv = ["LOCALE_ARCHIVE", "LANG", "TERMINFO", "TERM"] +baseEnv = ["LOCALE_ARCHIVE", "SSL_CERT_FILE" ,"LANG", "TERMINFO", "TERM"] -- | List of supported language definitions From 5cff3ec2c58553d297df16f91cb61e61d00c00f8 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 11 Sep 2015 16:54:29 +0200 Subject: [PATCH 10/12] Document type aliases --- nix-script.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nix-script.hs b/nix-script.hs index 3d82a83..cc7fb03 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -8,9 +8,13 @@ import System.Environment (lookupEnv, getProgName, getArgs) import System.Process (callProcess) import System.Posix.Escape.Unicode (escapeMany) - +-- | Enviroment variables type Env = [String] + +-- | Program arguments type Args = [String] + +-- | interpreter name and arguments type Inter = (String, Args) From 5af095e97c209e2319cb4fc787f57664bf27d291 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Mon, 21 Sep 2015 05:19:16 +0200 Subject: [PATCH 11/12] Allow users to extend the environment --- nix-script.hs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/nix-script.hs b/nix-script.hs index cc7fb03..74afe45 100755 --- a/nix-script.hs +++ b/nix-script.hs @@ -3,7 +3,8 @@ module Main where import Control.Monad (when) import Data.Maybe (fromMaybe) -import Data.List (isPrefixOf, find) +import Data.Char (isSpace) +import Data.List (isPrefixOf, find, (\\)) import System.Environment (lookupEnv, getProgName, getArgs) import System.Process (callProcess) import System.Posix.Escape.Unicode (escapeMany) @@ -85,6 +86,14 @@ lookupLang n = fromMaybe (passthrough n) (find ((n ==) . name) languages) +-- | Extract environment declaration from the header +filterEnv :: [String] -> (Env, [String]) +filterEnv header = (vars env, header \\ env) + where + vars = concatMap (drop 2 . words) + env = filter (isPrefixOf "env" . dropWhile isSpace) header + + -- | Parse dependencies declaration line parseHeader :: String -> [String] parseHeader = uncurry trans . split . words @@ -110,8 +119,8 @@ makeCmd (program, args) args' defs = -- | Create environment variable to run the script with -makeEnv :: IO Env -makeEnv = mapM format baseEnv where +makeEnv :: Env -> IO Env +makeEnv extra = mapM format (baseEnv ++ extra) where format var = maybe "" (\x -> var ++ "=" ++ x) <$> lookupEnv var @@ -130,12 +139,13 @@ main = do script <- readFile file case header script of (('>':identifier) : lines) -> do - let pkgs = concatMap parseHeader lines - language = dropWhile (==' ') identifier + let (env, deps) = filterEnv lines + pkgs = concatMap parseHeader deps + language = dropWhile isSpace identifier interactive = last progName == 'i' interpreter = makeInter language interactive file - cmd <- makeCmd interpreter args <$> makeEnv + cmd <- makeCmd interpreter args <$> makeEnv env callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs) _ -> fail "missing or invalid header" \ No newline at end of file From 9814f6462e7f1703c1a6464cad9db5b624d918d5 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Mon, 21 Sep 2015 05:32:01 +0200 Subject: [PATCH 12/12] Update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2c1b3eb..93fe3b1 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ To use `nix-script`, you need to add a header to your file. Here is an example f ```haskell #!/usr/bin/env nix-script #!> haskell +#! env | EDITOR #! haskell | text lens optparse-applicative #! shell | nix nix-prefetch-scripts @@ -40,6 +41,8 @@ The first line just tells the shell to use `nix-script` when executing the scrip The next lines the specify dependencies of the script. The first entry on each line is the language of the following dependencies. This is required so that language-specific names can be converted to the correct nix attribute names. You should have one line per language. In our case, we say that we want to use the `text`, `lens` and `optparse-applicative` haskell packages. We also want that `nix` and `nix-prefetch-scripts` are available in $PATH (the `shell` language doesn't apply any renaming to their dependencies and just passes them through unmodified). +The lines starting with `env` specify additional environment variables to be kept in the environment where the script will run. In this case the variable`EDITOR` editor. + We can now mark the script executable and run it: ```