A stable replacement for nix run in haskell
nix cli
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add proper support for -E and instantiate args

WeetHet d1674722 34674d26

+136 -82
+134 -76
app/Main.hs
··· 1 1 module Main (main) where 2 2 3 + import Data.Text (strip) 3 4 import Options.Applicative 4 5 import Options.Applicative qualified as OA 5 6 import System.Environment (withArgs) ··· 12 13 buildPackage :: Maybe Text, 13 14 buildArgs :: [(Text, Text)], 14 15 buildArgStrs :: [(Text, Text)], 15 - buildAttrs :: [Text], 16 - buildExprs :: [Text], 17 - buildDryRun :: Bool, 18 - buildIncludePaths :: [String], 16 + buildAttrs :: Maybe Text, 17 + buildExpr :: Maybe Text, 18 + buildIncludePaths :: [Text], 19 19 buildOptions :: [(Text, Text)], 20 20 buildRepair :: Bool, 21 21 buildNoBuildOutput :: Bool, ··· 29 29 buildReadonlyMode :: Bool, 30 30 buildVerbose :: Int, 31 31 buildQuiet :: Int, 32 - buildLogFormat :: Maybe String, 32 + buildLogFormat :: Maybe Text, 33 33 buildCheck :: Bool 34 34 } 35 35 deriving (Show) ··· 47 47 ) 48 48 ) 49 49 <*> many 50 - ( (,) 51 - <$> strOption (long "arg" <> metavar "name" <> help "Pass a value for argument 'name'") 52 - <*> strOption (metavar "value" <> help "Value for argument") 50 + ( biOption 51 + str 52 + str 53 + (long "arg" <> metavar "name" <> metavar2 "value" <> help "Pass a Nix value for argument 'name'") 53 54 ) 54 55 <*> many 55 - ( (,) 56 - <$> strOption (long "argstr" <> metavar "name" <> help "Pass a string value for argument 'name'") 57 - <*> strOption (metavar "value" <> help "String value for argument") 56 + ( biOption 57 + str 58 + str 59 + (long "argstr" <> metavar "name" <> metavar2 "value" <> help "Pass a string value for argument 'name'") 58 60 ) 59 - <*> many 61 + <*> optional 60 62 ( strOption 61 63 ( long "attr" 62 64 <> short 'A' ··· 64 66 <> help "Select attribute to build" 65 67 ) 66 68 ) 67 - <*> many 69 + <*> optional 68 70 ( strOption 69 71 ( long "expr" 70 72 <> short 'E' ··· 72 74 <> help "Interpret argument as a Nix expression" 73 75 ) 74 76 ) 75 - <*> switch (long "dry-run" <> help "Show what would be built, without building") 76 77 <*> many 77 78 ( strOption 78 79 ( long "include" ··· 82 83 ) 83 84 ) 84 85 <*> many 85 - ( (,) 86 - <$> strOption (long "option" <> metavar "name" <> help "Set Lix configuration option") 87 - <*> strOption (metavar "value" <> help "Value for option") 86 + ( biOption 87 + str 88 + str 89 + (long "option" <> metavar "name" <> metavar2 "value" <> help "Set Lix configuration option") 88 90 ) 89 91 <*> switch (long "repair" <> help "Fix corrupted or missing store paths by redownloading or rebuilding them") 90 92 <*> switch (long "no-build-output" <> short 'Q' <> help "Suppress output from builders to stderr") ··· 137 139 138 140 verifyNoConflicts :: BuildOptions -> IO BuildOptions 139 141 verifyNoConflicts opts = 140 - case (buildFileish opts, buildPackage opts) of 141 - (Just _, Just _) -> do 142 + case (buildExpr opts, buildFileish opts, buildPackage opts) of 143 + (Just _, Just _, _) -> do 144 + hPutStrLn stderr "Error: --expr/-E cannot be used with fileish argument." 145 + exitFailure 146 + (Just _, _, Just _) -> do 147 + hPutStrLn stderr "Error: --expr/-E cannot be used with --package/-p." 148 + exitFailure 149 + (Nothing, Just _, Just _) -> do 142 150 hPutStrLn stderr "Error: --package/-p and fileish argument cannot be used together." 143 151 exitFailure 144 - (Nothing, Nothing) -> do 145 - hPutStrLn stderr "Error: You must specify either a fileish argument or --package/-p." 152 + (Nothing, Nothing, Nothing) -> do 153 + hPutStrLn stderr "Error: You must specify either a fileish argument or --package/-p or --expr/-E." 146 154 exitFailure 147 155 _ -> pure opts 148 156 149 - nixBuildArgs :: BuildOptions -> [String] 150 - nixBuildArgs BuildOptions {..} = 157 + nixCommonArgs :: BuildOptions -> [Text] 158 + nixCommonArgs BuildOptions {..} = 151 159 concat 152 - [ maybe [] (\f -> [toString f]) buildFileish, 153 - maybe [] (\p -> ["-A", toString p]) buildPackage, 154 - concatMap (\(n, v) -> ["--arg", toString n, toString v]) buildArgs, 155 - concatMap (\(n, v) -> ["--argstr", toString n, toString v]) buildArgStrs, 156 - concatMap (\a -> ["-A", toString a]) buildAttrs, 157 - concatMap (\e -> ["-E", toString e]) buildExprs, 158 - ["--dry-run" | buildDryRun], 159 - concatMap (\i -> ["-I", i]) buildIncludePaths, 160 - concatMap (\(n, v) -> ["--option", toString n, toString v]) buildOptions, 161 - ["--repair" | buildRepair], 162 - ["--no-build-output" | buildNoBuildOutput], 163 - maybe [] (\j -> ["-j", toString j]) buildMaxJobs, 164 - maybe [] (\c -> ["--cores", show c]) buildCores, 165 - maybe [] (\s -> ["--max-silent-time", show s]) buildMaxSilentTime, 166 - maybe [] (\t -> ["--timeout", show t]) buildTimeout, 167 - ["--keep-going" | buildKeepGoing], 168 - ["--keep-failed" | buildKeepFailed], 169 - ["--fallback" | buildFallback], 170 - ["--readonly-mode" | buildReadonlyMode], 160 + [ concatMap (\i -> ["-I", i]) buildIncludePaths, 161 + concatMap (\(n, v) -> ["--option", n, v]) buildOptions, 171 162 replicate buildVerbose "--verbose", 172 163 replicate buildQuiet "--quiet", 173 - maybe [] (\fmt -> ["--log-format", fmt]) buildLogFormat, 174 - ["--check" | buildCheck] 164 + maybe [] (\fmt -> ["--log-format", fmt]) buildLogFormat 175 165 ] 176 166 167 + nixBuildArgs :: BuildOptions -> [Text] 168 + nixBuildArgs opts@(BuildOptions {..}) = 169 + nixCommonArgs opts 170 + ++ concat 171 + [ concatMap (\(n, v) -> ["--arg", n, v]) buildArgs, 172 + concatMap (\(n, v) -> ["--argstr", n, v]) buildArgStrs, 173 + ["--repair" | buildRepair], 174 + ["--no-build-output" | buildNoBuildOutput], 175 + maybe [] (\j -> ["-j", j]) buildMaxJobs, 176 + maybe [] (\c -> ["--cores", show c]) buildCores, 177 + maybe [] (\s -> ["--max-silent-time", show s]) buildMaxSilentTime, 178 + maybe [] (\t -> ["--timeout", show t]) buildTimeout, 179 + ["--keep-going" | buildKeepGoing], 180 + ["--keep-failed" | buildKeepFailed], 181 + ["--fallback" | buildFallback], 182 + ["--readonly-mode" | buildReadonlyMode], 183 + ["--check" | buildCheck] 184 + ] 185 + 186 + getFile :: BuildOptions -> Text 187 + getFile opts = 188 + case buildPackage opts of 189 + Just _ -> "<nixpkgs>" 190 + Nothing -> fromMaybe "./." $ buildFileish opts 191 + 192 + getAttr :: BuildOptions -> Maybe Text 193 + getAttr opts = 194 + case (buildAttrs opts, buildPackage opts) of 195 + (Just a, _) -> Just a 196 + (_, Just p) -> Just p 197 + (Nothing, Nothing) -> Nothing 198 + 199 + getExeExprFromFile :: Text -> Maybe Text -> [(Text, Text)] -> [(Text, Text)] -> Text 200 + getExeExprFromFile file attr args argstrs = 201 + unlines 202 + [ "let", 203 + " lib = import <nixpkgs/lib>;", 204 + " drv = import (" <> file <> ");", 205 + " drvResolved = if builtins.isFunction drv then drv " <> argsBlock <> " else drv;", 206 + "in lib.getExe drvResolved" <> attrSub 207 + ] 208 + where 209 + attrSub = maybe "" ("." <>) attr 210 + argNix = unwords . fmap (\(n, v) -> n <> " = " <> v <> ";") $ args 211 + argstrNix = unwords . fmap (\(n, v) -> n <> " = " <> "\"" <> v <> "\"" <> ";") $ argstrs 212 + argsBlock = "{" <> (unwords [argNix, argstrNix]) <> " }" 213 + 214 + getExeExprFromExpr :: Text -> Text 215 + getExeExprFromExpr expr = 216 + unlines 217 + [ "let", 218 + " lib = import <nixpkgs/lib>;", 219 + " drv = (" <> expr <> ");", 220 + "in lib.getExe drv" 221 + ] 222 + 223 + readProcessText :: FilePath -> [Text] -> Text -> IO Text 224 + readProcessText cmd args input = toText <$> readProcess cmd (map toString args) (toString input) 225 + 226 + executeFileText :: Text -> Bool -> [Text] -> Maybe [(String, String)] -> IO a 227 + executeFileText binPath search args env = 228 + executeFile (toString binPath) search (map toString args) env 229 + 177 230 main :: IO () 178 231 main = do 179 232 args <- getArgs 180 233 let (ours, rest) = break (== "--") args 181 - let passthrough = maybe [] tail (nonEmpty rest) 234 + let passthrough = map toText $ maybe [] tail (nonEmpty rest) 182 235 183 236 withArgs ours $ do 184 237 opts_ <- ··· 188 241 (fullDesc <> progDesc "nix-run - run a Nix application" <> OA.header "nix-run - run a Nix application") 189 242 opts <- verifyNoConflicts opts_ 190 243 191 - let file = case buildPackage opts of 192 - Just _ -> "<nixpkgs>" 193 - Nothing -> fromMaybe "./." (buildFileish opts) 194 - 195 - let attr = case (buildAttrs opts, buildPackage opts) of 196 - (a : _, _) -> Just a 197 - ([], Just p) -> Just p 198 - ([], Nothing) -> Nothing 199 - 200 - let attrSub = maybe "" ("." <>) attr 201 - let expr = 202 - unlines 203 - [ "let", 204 - " pkgs = import <nixpkgs> {};", 205 - " drv = import (" <> file <> ");", 206 - " drvResolved = if builtins.isFunction drv then drv {} else drv;", 207 - "in pkgs.lib.getExe drvResolved" <> attrSub 208 - ] 209 - binPath <- 210 - readProcess 211 - "nix-instantiate" 212 - ["--eval", "--raw", "--read-write-mode", "-E", toString expr] 213 - "" 214 - let attrArgs = maybe [] (("-A" :) . one) attr 215 - _ <- 216 - readProcess 217 - "nix-build" 218 - ((++ nixBuildArgs opts) . map toString $ ["--no-out-link", file] ++ attrArgs) 219 - "" 220 - 221 - executeFile binPath False passthrough Nothing 244 + case buildExpr opts of 245 + Just exprText -> do 246 + let expr = getExeExprFromExpr exprText 247 + binPath <- 248 + readProcessText 249 + "nix-instantiate" 250 + ( ["--eval", "--raw", "-E", expr] 251 + ++ nixCommonArgs opts 252 + ++ if (buildReadonlyMode opts) then ["--readonly-mode"] else ["--read-write-mode"] 253 + ) 254 + "" 255 + void $ 256 + readProcessText 257 + "nix-build" 258 + (["--no-out-link", "-E", expr] <> nixBuildArgs opts) 259 + "" 260 + executeFileText (strip binPath) False passthrough Nothing 261 + Nothing -> do 262 + let file = getFile opts 263 + let attr = getAttr opts 264 + let expr = getExeExprFromFile file attr (buildArgs opts) (buildArgStrs opts) 265 + binPath <- 266 + readProcessText 267 + "nix-instantiate" 268 + ( ["--eval", "--raw", "-E", expr] 269 + ++ nixCommonArgs opts 270 + ++ if (buildReadonlyMode opts) then ["--readonly-mode"] else ["--read-write-mode"] 271 + ) 272 + "" 273 + let attrArgs = maybe [] (("-A" :) . one) attr 274 + void $ 275 + readProcessText 276 + "nix-build" 277 + (["--no-out-link", file] ++ attrArgs ++ nixBuildArgs opts) 278 + "" 279 + executeFileText (strip binPath) False passthrough Nothing
+1 -1
package.yaml
··· 24 24 mixin: 25 25 - (Relude as Prelude) 26 26 - "" 27 - - optparse-applicative ^>= 0.18.1.0 27 + - hercules-ci-optparse-applicative ^>= 0.19.0.0 28 28 - process 29 29 - unix 30 30 language: GHC2024
+1 -5
shell.nix
··· 5 5 pkgs.haskellPackages.shellFor { 6 6 packages = hpkgs: [ 7 7 ((hpkgs.callCabal2nix "nix-run" ./. { }).overrideAttrs (old: { 8 - preConfigure = '' 9 - if [ -f package.yaml ] && [ ! -f nix-run-hs.cabal ]; then 10 - ${pkgs.haskellPackages.hpack}/bin/hpack 11 - fi 12 - ''; 8 + preConfigure = "hpack"; 13 9 14 10 nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.haskellPackages.hpack ]; 15 11 }))