1
0
mirror of https://github.com/bennofs/nix-script synced 2025-01-09 20:34:20 +01:00

Properly handle arguments

This commit is contained in:
rnhmjoj 2015-09-11 06:19:03 +02:00
parent 332c94e05a
commit 8bab98e655
2 changed files with 36 additions and 32 deletions

View File

@ -4,4 +4,5 @@
function a { echo "this is zsh!" } function a { echo "this is zsh!" }
a a
echo $#
echo "your args: $@" echo "your args: $@"

View File

@ -1,13 +1,17 @@
-- | A shebang for running scripts inside nix-shell with defined dependencies -- | A shebang for running scripts inside nix-shell with defined dependencies
module Main where module Main where
import Control.Monad (when) import Control.Monad (when)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.List (isSuffixOf, isPrefixOf, find) import Data.List (isPrefixOf, find)
import System.Environment (lookupEnv, getProgName, getArgs) import System.Environment (lookupEnv, getProgName, getArgs)
import System.Process (callProcess) import System.Process (callProcess)
import System.Posix.IO (createPipe, fdToHandle) import System.Posix.Escape.Unicode (escapeMany)
import System.IO (hPutStrLn, hClose, hFlush)
type Env = [String]
type Args = [String]
type Inter = (String, Args)
-- | Information about a language -- | Information about a language
@ -16,9 +20,9 @@ data Language = Language
-- ^ Name of the language -- ^ Name of the language
, depsTrans :: [String] -> [String] , depsTrans :: [String] -> [String]
-- ^ Transform language-specific dependencies to nix packages -- ^ Transform language-specific dependencies to nix packages
, run :: FilePath -> (String, [String]) , run :: FilePath -> Inter
-- ^ Command to run the given file as script -- ^ Command to run the given file as script
, repl :: FilePath -> (String, [String]) , repl :: FilePath -> Inter
-- ^ Command to load the given file in an interpreter -- ^ Command to load the given file in an interpreter
} }
@ -76,6 +80,7 @@ lookupLang :: String -> Language
lookupLang n = lookupLang n =
fromMaybe (passthrough n) (find ((n ==) . name) languages) fromMaybe (passthrough n) (find ((n ==) . name) languages)
-- | Parse dependencies declaration line -- | Parse dependencies declaration line
parseHeader :: String -> [String] parseHeader :: String -> [String]
parseHeader = uncurry trans . split . words parseHeader = uncurry trans . split . words
@ -86,25 +91,24 @@ parseHeader = uncurry trans . split . words
-- | Find command to run/load the script -- | Find command to run/load the script
interpreter :: String -> Bool -> String -> (String, [String]) makeInter :: String -> Bool -> String -> Inter
interpreter lang interactive = makeInter lang interactive =
(if interactive then repl else run) (lookupLang lang) (if interactive then repl else run) (lookupLang lang)
-- | Create command to add the shell environment -- | Create command to add the shell environment
makeCommand :: String -> [String] -> IO String makeCmd :: Inter -> Args -> Env -> String
makeCommand program args = do makeCmd (program, args) args' defs =
(readFd, writeFd) <- createPipe env defs ++ interpreter ++ escapeMany args'
writeH <- fdToHandle writeFd
hPutStrLn writeH (unlines args)
hFlush writeH >> hClose writeH
definitions <- mapM format baseEnv
return (env definitions ++ xargs readFd ++ program)
where where
interpreter = program ++ " " ++ unwords args ++ " "
env defs = "env " ++ unwords defs ++ " " 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 -- | run a script or load it in an interactive interpreter
@ -115,20 +119,19 @@ main = do
when (null progArgs) (fail $ "usage: " ++ progName ++ " <file>") when (null progArgs) (fail $ "usage: " ++ progName ++ " <file>")
let file = head progArgs let shebang = takeWhile (isPrefixOf "#!") . lines
shebang = takeWhile (isPrefixOf "#!") . lines header = drop 1 . map (drop 2) . shebang
header = drop 1 . map (drop 2) . shebang (file:args) = progArgs
script <- readFile file script <- readFile file
case header script of case header script of
(('>' : identifier) : lines) -> do (('>':identifier) : lines) -> do
let pkgs = concatMap parseHeader lines let pkgs = concatMap parseHeader lines
language = dropWhile (==' ') identifier language = dropWhile (==' ') identifier
interactive = isSuffixOf "i" progName interactive = last progName == 'i'
(program, args) = interpreter language interactive file interpreter = makeInter language interactive file
cmd <- makeCommand program args cmd <- makeCmd interpreter args <$> makeEnv
putStrLn $ unwords ("--pure" : "--command" : cmd : "-p" : pkgs)
callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs) callProcess "nix-shell" ("--pure" : "--command" : cmd : "-p" : pkgs)
_ -> fail "missing or invalid header" _ -> fail "missing or invalid header"