1
1
mirror of https://github.com/nmattia/snack.git synced 2024-09-11 11:55:36 +03:00
This commit is contained in:
Nicolas Mattia 2018-10-21 13:10:35 +02:00
parent a96356a361
commit d206d019fd
21 changed files with 138 additions and 144 deletions

View File

@ -46,24 +46,32 @@ type family Config (c :: ConfigStage) ty1 ty2 where
--- ---
--- Configuration proper --- Configuration proper
type Mode = Mode_ 'ConfigReady data PackageConfig
= PackageSpecific FilePath
| PackageDiscovery
-- ^ Reads a 'package.nix' or 'package.yaml'
type ModeRaw = Mode_ 'ConfigRaw preparePackage :: PackageConfig -> IO PackageFile
preparePackage = \case
PackageSpecific fp -> mkPackageFile fp
PackageDiscovery -> discoverPackage
data Mode_ c discoverPackage :: IO PackageFile
= Standalone (Config c FilePath PackageNix) -- Reads a package.nix file discoverPackage = do
| HPack (Config c FilePath PackageYaml) -- Reads a package.yaml eYaml <- mkPackageFileEither "package.yaml"
eNix <- mkPackageFileEither "package.nix"
prepareMode :: ModeRaw -> IO Mode case (eYaml, eNix) of
prepareMode = \case (Right (PackageFile yaml), Right (PackageFile nix)) ->
Standalone fp -> Standalone <$> mkPackageNix fp throwIO $ userError $ unlines
HPack fp -> HPack <$> mkPackageYaml fp [ "Please specify which package file to use: "
, yaml, nix
-- | Like a FilePath, but Nix friendly ]
newtype PackageNix = PackageNix { unPackageNix :: FilePath } (Right yaml, Left{}) -> pure yaml
(Left{}, Right nix) -> pure nix
mkPackageNix :: FilePath -> IO PackageNix (Left e1, Left e2) -> throwIO $ userError $ unlines
mkPackageNix = fmap PackageNix . mkFilePath [ "Could not discover package file:"
, e1, e2
]
-- | Like a FilePath, but Nix friendly -- | Like a FilePath, but Nix friendly
newtype SnackNix = SnackNix FilePath newtype SnackNix = SnackNix FilePath
@ -78,10 +86,13 @@ mkSnackLib :: FilePath -> IO SnackLib
mkSnackLib = fmap SnackLib . mkDirPath mkSnackLib = fmap SnackLib . mkDirPath
-- | Like a FilePath, but Nix friendly -- | Like a FilePath, but Nix friendly
newtype PackageYaml = PackageYaml { unPackageYaml :: FilePath } newtype PackageFile = PackageFile { unPackageFile :: FilePath }
mkPackageYaml :: FilePath -> IO PackageYaml mkPackageFileEither :: FilePath -> IO (Either String PackageFile)
mkPackageYaml = fmap PackageYaml . mkFilePath mkPackageFileEither = fmap (fmap PackageFile) . mkFilePathEither
mkPackageFile :: FilePath -> IO PackageFile
mkPackageFile = fmap PackageFile . mkFilePath
mkDirPath :: FilePath -> IO FilePath mkDirPath :: FilePath -> IO FilePath
mkDirPath fp = doesPathExist fp >>= \case mkDirPath fp = doesPathExist fp >>= \case
@ -90,12 +101,16 @@ mkDirPath fp = doesPathExist fp >>= \case
False -> canonicalizePath fp False -> canonicalizePath fp
False -> throwIO $ userError $ fp <> " does not exist" False -> throwIO $ userError $ fp <> " does not exist"
mkFilePath :: FilePath -> IO FilePath mkFilePathEither :: FilePath -> IO (Either String FilePath)
mkFilePath fp = doesFileExist fp >>= \case mkFilePathEither fp = doesFileExist fp >>= \case
True -> canonicalizePath fp True -> Right <$> canonicalizePath fp
False -> doesPathExist fp >>= \case False -> doesPathExist fp >>= \case
True -> throwIO $ userError $ fp <> " is a directory" True -> pure (Left (fp <> " is a directory"))
False -> throwIO $ userError $ fp <> " does not exist" False -> pure (Left (fp <> " does not exist"))
mkFilePath :: FilePath -> IO FilePath
mkFilePath fp =
mkFilePathEither fp >>= either (throwIO . userError) pure
-- | How to call @nix-build@ -- | How to call @nix-build@
newtype NixConfig = NixConfig newtype NixConfig = NixConfig
@ -129,7 +144,7 @@ type Options = Options_ 'ConfigReady
data Options_ c = Options data Options_ c = Options
{ snackConfig :: SnackConfig_ c { snackConfig :: SnackConfig_ c
, mode :: Mode_ c , mode :: Config c PackageConfig PackageFile
, command :: Command , command :: Command
} }
@ -137,7 +152,7 @@ prepareOptions :: OptionsRaw -> IO Options
prepareOptions raw = prepareOptions raw =
Options <$> Options <$>
prepareSnackConfig (snackConfig raw) <*> prepareSnackConfig (snackConfig raw) <*>
prepareMode (mode raw) <*> preparePackage (mode raw) <*>
pure (command raw) pure (command raw)
prepareSnackConfig :: SnackConfigRaw -> IO SnackConfig prepareSnackConfig :: SnackConfigRaw -> IO SnackConfig
@ -180,29 +195,21 @@ parseSnackConfig = SnackConfig <$> Opts.optional
) <*> ) <*>
parseNixConfig parseNixConfig
parseMode :: Opts.Parser ModeRaw parsePackageConfig :: Opts.Parser PackageConfig
parseMode = parsePackageConfig =
(Standalone <$> (PackageSpecific <$>
Opts.strOption Opts.strOption
(Opts.long "package-nix" (Opts.long "package-file"
<> Opts.short 's'
<> Opts.value "./package.nix"
<> Opts.metavar "PATH")
)
<|>
(HPack <$>
Opts.strOption
(Opts.long "package-yaml"
<> Opts.value "./package.yaml"
<> Opts.short 'p' <> Opts.short 'p'
-- TODO: description
<> Opts.metavar "PATH") <> Opts.metavar "PATH")
) ) <|> pure PackageDiscovery
parseOptions :: Opts.Parser OptionsRaw parseOptions :: Opts.Parser OptionsRaw
parseOptions = parseOptions =
Options <$> Options <$>
parseSnackConfig <*> parseSnackConfig <*>
parseMode <*> parsePackageConfig <*>
parseCommand parseCommand
newtype ModuleName = ModuleName T.Text newtype ModuleName = ModuleName T.Text
@ -351,71 +358,38 @@ nixBuild snackCfg extraNixArgs nixExpr =
: [ argName narg , argValue narg ] : [ argName narg , argValue narg ]
nixCfg = snackNixCfg snackCfg nixCfg = snackNixCfg snackCfg
snackBuild :: SnackConfig -> PackageNix -> Sh BuildResult snackBuild :: SnackConfig -> PackageFile -> Sh BuildResult
snackBuild snackCfg packageNix = do snackBuild snackCfg packageFile = do
NixPath out <- nixBuild snackCfg NixPath out <- nixBuild snackCfg
[ NixArg [ NixArg
{ argName = "packageNix" { argName = "packageFile"
, argValue = T.pack $ unPackageNix packageNix , argValue = T.pack $ unPackageFile packageFile
, argType = Arg , argType = Arg
} }
] ]
$ NixExpr "snack.inferSnackBuild packageNix" $ NixExpr "snack.inferBuild packageFile"
decodeOrFail =<< liftIO (BS.readFile $ T.unpack out) decodeOrFail =<< liftIO (BS.readFile $ T.unpack out)
snackGhci :: SnackConfig -> PackageNix -> Sh GhciBuild snackGhci :: SnackConfig -> PackageFile -> Sh GhciBuild
snackGhci snackCfg packageNix = do snackGhci snackCfg packageFile = do
NixPath out <- nixBuild snackCfg NixPath out <- nixBuild snackCfg
[ NixArg [ NixArg
{ argName = "packageNix" { argName = "packageFile"
, argValue = T.pack $ unPackageNix packageNix , argValue = T.pack $ unPackageFile packageFile
, argType = Arg , argType = Arg
} }
] ]
$ NixExpr "snack.inferSnackGhci packageNix" $ NixExpr "snack.inferGhci packageFile"
liftIO (BS.readFile (T.unpack out)) >>= decodeOrFail >>= \case liftIO (BS.readFile (T.unpack out)) >>= decodeOrFail >>= \case
BuiltGhci g -> pure g BuiltGhci g -> pure g
b -> throwIO $ userError $ "Expected GHCi build, got " <> show b b -> throwIO $ userError $ "Expected GHCi build, got " <> show b
snackBuildHPack :: SnackConfig -> PackageYaml -> Sh BuildResult runCommand :: SnackConfig -> PackageFile -> Command -> IO ()
snackBuildHPack snackCfg packageYaml = do runCommand snackCfg packageFile = \case
NixPath out <- nixBuild snackCfg Build -> S.shelly $ void $ snackBuild snackCfg packageFile
[ NixArg Run args -> quiet (snackBuild snackCfg packageFile) >>= runBuildResult args
{ argName = "packageYaml"
, argValue = T.pack $ unPackageYaml packageYaml
, argType = Arg
}
]
$ NixExpr "snack.inferHPackBuild packageYaml"
decodeOrFail =<< liftIO (BS.readFile (T.unpack out))
snackGhciHPack :: SnackConfig -> PackageYaml -> Sh GhciBuild
snackGhciHPack snackCfg packageYaml = do
NixPath out <- nixBuild snackCfg
[ NixArg
{ argName = "packageYaml"
, argValue = T.pack $ unPackageYaml packageYaml
, argType = Arg
}
]
$ NixExpr "snack.inferHPackGhci packageYaml"
liftIO (BS.readFile (T.unpack out)) >>= decodeOrFail >>= \case
BuiltGhci g -> pure g
b -> throwIO $ userError $ "Expected GHCi build, got " <> show b
runCommand :: SnackConfig -> Mode -> Command -> IO ()
runCommand snackCfg (Standalone packageNix) = \case
Build -> S.shelly $ void $ snackBuild snackCfg packageNix
Run args -> quiet (snackBuild snackCfg packageNix) >>= runBuildResult args
Ghci -> flip runExe [] =<< Ghci -> flip runExe [] =<<
ghciExePath <$> (quiet (snackGhci snackCfg packageNix)) ghciExePath <$> (quiet (snackGhci snackCfg packageFile))
Test -> noTest
runCommand snackCfg (HPack packageYaml) = \case
Build -> S.shelly $ void $ snackBuildHPack snackCfg packageYaml
Run args ->
quiet (snackBuildHPack snackCfg packageYaml) >>= runBuildResult args
Ghci -> flip runExe [] =<<
ghciExePath <$> quiet (snackGhciHPack snackCfg packageYaml)
Test -> noTest Test -> noTest
noTest :: IO a noTest :: IO a

View File

@ -68,7 +68,7 @@ for t in $SNACK_TESTS; do
done done
for t in $SNACK_TESTS; do for t in $SNACK_TESTS; do
banner "Test $name" banner "Test $t"
pushd "tests/$t" pushd "tests/$t"
./test ./test
popd popd

View File

@ -1,6 +1,7 @@
# This is the entry point of the library, and badly needs documentation. # This is the entry point of the library, and badly needs documentation.
# TODO: currently single out derivations prepend the PWD to the path # TODO: currently single out derivations prepend the PWD to the path
# TODO: make sure that filters for "base" are airtight # TODO: make sure that filters for "base" are airtight
# TODO: document the sh*t out of these functions
{ pkgs { pkgs
, ghc-version ? "ghc822" , ghc-version ? "ghc822"
, ghcWithPackages ? pkgs.haskell.packages.${ghc-version}.ghcWithPackages , ghcWithPackages ? pkgs.haskell.packages.${ghc-version}.ghcWithPackages
@ -67,6 +68,37 @@ let
exe_path = "${drv.out}/${drv.relExePath}"; exe_path = "${drv.out}/${drv.relExePath}";
}; };
# TODO: deduplicate extensions + update README with --package-file
inferBuild = packageFile:
let
basename = builtins.baseNameOf packageFile;
components = pkgs.lib.strings.splitString "." basename;
ext =
if pkgs.lib.length components <= 1
then abort ("File " ++ packageFile ++ " does not have an extension")
else pkgs.lib.last components;
build =
if ext == "nix" then inferSnackBuild
else if ext == "yaml" then inferHPackBuild
else if ext == "yml" then inferHPackBuild
else abort ("Unknown extension " ++ ext ++ " of file " ++ packageFile);
in build packageFile;
inferGhci = packageFile:
let
basename = builtins.baseNameOf packageFile;
components = pkgs.lib.strings.splitString "." basename;
ext =
if pkgs.lib.length components <= 1
then abort ("File " ++ packageFile ++ " does not have an extension")
else pkgs.lib.last components;
ghci =
if ext == "nix" then inferSnackGhci
else if ext == "yaml" then inferHPackGhci
else if ext == "yml" then inferHPackGhci
else abort ("Unknown extension " ++ ext ++ " of file " ++ packageFile);
in ghci packageFile;
inferSnackBuild = packageNix: mkPackage (import packageNix); inferSnackBuild = packageNix: mkPackage (import packageNix);
inferSnackGhci = packageNix: writeText "snack-ghci-json" inferSnackGhci = packageNix: writeText "snack-ghci-json"
@ -152,6 +184,8 @@ let
in in
{ {
inherit inherit
inferBuild
inferGhci
inferSnackBuild inferSnackBuild
inferSnackGhci inferSnackGhci
inferHPackBuild inferHPackBuild
@ -160,7 +194,7 @@ in
buildAsExecutable buildAsExecutable
buildAsLibrary buildAsLibrary
snackSpec snackSpec
hpackSpec hpackSpecs
mkPackage mkPackage
; ;
} }

View File

@ -8,7 +8,6 @@ test() {
$SNACK run $SNACK run
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test
SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -16,6 +16,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4 --snack-nix snack.nix --package-nix package.nix" test SNACK="snack -j4 --snack-nix snack.nix --package-file package.nix" test
SNACK="snack -j4 --snack-nix snack.nix" test SNACK="snack -j4 --snack-nix snack.nix --package-file package.yaml" test
SNACK="snack -j4 --snack-nix snack.nix --package-yaml package.yaml" test

View File

@ -15,7 +15,6 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test
SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -8,6 +8,8 @@ TMP_DIR=$(mktemp -d)
git clone http://github.com/nmattia/pboy.git $TMP_DIR git clone http://github.com/nmattia/pboy.git $TMP_DIR
git -C $TMP_DIR reset --hard a2458d6984930a33a3b1972cb6d5c167d2511b06 git -C $TMP_DIR reset --hard a2458d6984930a33a3b1972cb6d5c167d2511b06
snack -j4 build --package-yaml $TMP_DIR/package.yaml pushd $TMP_DIR
snack -j4 build
popd
rm -rf $TMP_DIR rm -rf $TMP_DIR

View File

@ -16,6 +16,6 @@ test() {
} }
SNACK="snack -j4" test SNACK="snack -j4" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test
# Note: no HPack test, because HPack doesn't support multi library # Note: no HPack test, because HPack doesn't support multi library

View File

@ -16,6 +16,6 @@ test() {
} }
SNACK="snack" test SNACK="snack" test
SNACK="snack -s ./package.nix" test SNACK="snack --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test
# Note: no HPack test, because HPack doesn't support multi library # Note: no HPack test, because HPack doesn't support multi library

View File

@ -15,6 +15,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -15,6 +15,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -16,6 +16,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -16,6 +16,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -8,7 +8,6 @@ test() {
$SNACK run $SNACK run
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test
SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -8,4 +8,4 @@ test() {
$SNACK run $SNACK run
} }
SNACK="snack -j4 --package-yaml ./package.yaml" test SNACK="snack -j4" test

View File

@ -16,10 +16,5 @@ test() {
} }
SNACK="snack -j4" test SNACK="snack -j4 -p ./package.nix" test
SNACK="snack -j4 -p ./package.yaml" test
# TODO: Fix cannot coerce a list to a string, at /...-snack-lib/files.nix:66:12
SNACK="snack -j4 -s ./package.nix" test
# TODO: Fix cannot coerce a list to a string, at /...-snack-lib/hpack.nix:60:37
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -15,6 +15,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack -j4" test SNACK="snack -j4 --package-file ./package.nix" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.yaml" test
SNACK="snack -j4 --package-yaml ./package.yaml" test

View File

@ -3,12 +3,12 @@
set -euo pipefail set -euo pipefail
snack -j4 build -s code/package.nix snack -j4 build --package-file code/package.nix
snack -j4 run -s code/package.nix | diff golden - snack -j4 run --package-file code/package.nix | diff golden -
TMP_FILE=$(mktemp) TMP_FILE=$(mktemp)
capture_io "$TMP_FILE" main | snack -j4 -s code/package.nix ghci capture_io "$TMP_FILE" main | snack -j4 --package-file code/package.nix ghci
diff golden $TMP_FILE diff golden $TMP_FILE
rm $TMP_FILE rm $TMP_FILE

View File

@ -16,5 +16,5 @@ test() {
} }
SNACK="snack -j4" test SNACK="snack -j4" test
SNACK="snack -j4 -s ./package.nix" test SNACK="snack -j4 --package-file ./package.nix" test
# Note: no HPack test, because HPack doesn't support multi library # Note: no HPack test, because HPack doesn't support multi library

View File

@ -15,6 +15,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack" test SNACK="snack --package-file ./package.nix" test
SNACK="snack -s ./package.nix" test SNACK="snack --package-file ./package.yaml" test
SNACK="snack --package-yaml ./package.yaml" test

View File

@ -15,6 +15,5 @@ test() {
rm $TMP_FILE rm $TMP_FILE
} }
SNACK="snack" test SNACK="snack --package-file ./package.nix" test
SNACK="snack -s ./package.nix" test SNACK="snack --package-file ./package.yaml" test
SNACK="snack --package-yaml ./package.yaml" test