diff --git a/bin/Snack.hs b/bin/Snack.hs index 622fade..8266aef 100644 --- a/bin/Snack.hs +++ b/bin/Snack.hs @@ -46,24 +46,32 @@ type family Config (c :: ConfigStage) ty1 ty2 where --- --- 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 - = Standalone (Config c FilePath PackageNix) -- Reads a package.nix file - | HPack (Config c FilePath PackageYaml) -- Reads a package.yaml - -prepareMode :: ModeRaw -> IO Mode -prepareMode = \case - Standalone fp -> Standalone <$> mkPackageNix fp - HPack fp -> HPack <$> mkPackageYaml fp - --- | Like a FilePath, but Nix friendly -newtype PackageNix = PackageNix { unPackageNix :: FilePath } - -mkPackageNix :: FilePath -> IO PackageNix -mkPackageNix = fmap PackageNix . mkFilePath +discoverPackage :: IO PackageFile +discoverPackage = do + eYaml <- mkPackageFileEither "package.yaml" + eNix <- mkPackageFileEither "package.nix" + case (eYaml, eNix) of + (Right (PackageFile yaml), Right (PackageFile nix)) -> + throwIO $ userError $ unlines + [ "Please specify which package file to use: " + , yaml, nix + ] + (Right yaml, Left{}) -> pure yaml + (Left{}, Right nix) -> pure nix + (Left e1, Left e2) -> throwIO $ userError $ unlines + [ "Could not discover package file:" + , e1, e2 + ] -- | Like a FilePath, but Nix friendly newtype SnackNix = SnackNix FilePath @@ -78,10 +86,13 @@ mkSnackLib :: FilePath -> IO SnackLib mkSnackLib = fmap SnackLib . mkDirPath -- | Like a FilePath, but Nix friendly -newtype PackageYaml = PackageYaml { unPackageYaml :: FilePath } +newtype PackageFile = PackageFile { unPackageFile :: FilePath } -mkPackageYaml :: FilePath -> IO PackageYaml -mkPackageYaml = fmap PackageYaml . mkFilePath +mkPackageFileEither :: FilePath -> IO (Either String PackageFile) +mkPackageFileEither = fmap (fmap PackageFile) . mkFilePathEither + +mkPackageFile :: FilePath -> IO PackageFile +mkPackageFile = fmap PackageFile . mkFilePath mkDirPath :: FilePath -> IO FilePath mkDirPath fp = doesPathExist fp >>= \case @@ -90,12 +101,16 @@ mkDirPath fp = doesPathExist fp >>= \case False -> canonicalizePath fp False -> throwIO $ userError $ fp <> " does not exist" -mkFilePath :: FilePath -> IO FilePath -mkFilePath fp = doesFileExist fp >>= \case - True -> canonicalizePath fp +mkFilePathEither :: FilePath -> IO (Either String FilePath) +mkFilePathEither fp = doesFileExist fp >>= \case + True -> Right <$> canonicalizePath fp False -> doesPathExist fp >>= \case - True -> throwIO $ userError $ fp <> " is a directory" - False -> throwIO $ userError $ fp <> " does not exist" + True -> pure (Left (fp <> " is a directory")) + False -> pure (Left (fp <> " does not exist")) + +mkFilePath :: FilePath -> IO FilePath +mkFilePath fp = + mkFilePathEither fp >>= either (throwIO . userError) pure -- | How to call @nix-build@ newtype NixConfig = NixConfig @@ -129,7 +144,7 @@ type Options = Options_ 'ConfigReady data Options_ c = Options { snackConfig :: SnackConfig_ c - , mode :: Mode_ c + , mode :: Config c PackageConfig PackageFile , command :: Command } @@ -137,7 +152,7 @@ prepareOptions :: OptionsRaw -> IO Options prepareOptions raw = Options <$> prepareSnackConfig (snackConfig raw) <*> - prepareMode (mode raw) <*> + preparePackage (mode raw) <*> pure (command raw) prepareSnackConfig :: SnackConfigRaw -> IO SnackConfig @@ -180,29 +195,21 @@ parseSnackConfig = SnackConfig <$> Opts.optional ) <*> parseNixConfig -parseMode :: Opts.Parser ModeRaw -parseMode = - (Standalone <$> +parsePackageConfig :: Opts.Parser PackageConfig +parsePackageConfig = + (PackageSpecific <$> Opts.strOption - (Opts.long "package-nix" - <> Opts.short 's' - <> Opts.value "./package.nix" - <> Opts.metavar "PATH") - ) - <|> - (HPack <$> - Opts.strOption - (Opts.long "package-yaml" - <> Opts.value "./package.yaml" + (Opts.long "package-file" <> Opts.short 'p' + -- TODO: description <> Opts.metavar "PATH") - ) + ) <|> pure PackageDiscovery parseOptions :: Opts.Parser OptionsRaw parseOptions = Options <$> parseSnackConfig <*> - parseMode <*> + parsePackageConfig <*> parseCommand newtype ModuleName = ModuleName T.Text @@ -351,71 +358,38 @@ nixBuild snackCfg extraNixArgs nixExpr = : [ argName narg , argValue narg ] nixCfg = snackNixCfg snackCfg -snackBuild :: SnackConfig -> PackageNix -> Sh BuildResult -snackBuild snackCfg packageNix = do +snackBuild :: SnackConfig -> PackageFile -> Sh BuildResult +snackBuild snackCfg packageFile = do NixPath out <- nixBuild snackCfg [ NixArg - { argName = "packageNix" - , argValue = T.pack $ unPackageNix packageNix + { argName = "packageFile" + , argValue = T.pack $ unPackageFile packageFile , argType = Arg } ] - $ NixExpr "snack.inferSnackBuild packageNix" + $ NixExpr "snack.inferBuild packageFile" decodeOrFail =<< liftIO (BS.readFile $ T.unpack out) -snackGhci :: SnackConfig -> PackageNix -> Sh GhciBuild -snackGhci snackCfg packageNix = do +snackGhci :: SnackConfig -> PackageFile -> Sh GhciBuild +snackGhci snackCfg packageFile = do NixPath out <- nixBuild snackCfg [ NixArg - { argName = "packageNix" - , argValue = T.pack $ unPackageNix packageNix + { argName = "packageFile" + , argValue = T.pack $ unPackageFile packageFile , argType = Arg } ] - $ NixExpr "snack.inferSnackGhci packageNix" + $ NixExpr "snack.inferGhci packageFile" liftIO (BS.readFile (T.unpack out)) >>= decodeOrFail >>= \case BuiltGhci g -> pure g b -> throwIO $ userError $ "Expected GHCi build, got " <> show b -snackBuildHPack :: SnackConfig -> PackageYaml -> Sh BuildResult -snackBuildHPack snackCfg packageYaml = do - NixPath out <- nixBuild snackCfg - [ NixArg - { 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 +runCommand :: SnackConfig -> PackageFile -> Command -> IO () +runCommand snackCfg packageFile = \case + Build -> S.shelly $ void $ snackBuild snackCfg packageFile + Run args -> quiet (snackBuild snackCfg packageFile) >>= runBuildResult args Ghci -> flip runExe [] =<< - ghciExePath <$> (quiet (snackGhci snackCfg packageNix)) - 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) + ghciExePath <$> (quiet (snackGhci snackCfg packageFile)) Test -> noTest noTest :: IO a diff --git a/script/test b/script/test index aa46f97..d7b22a7 100755 --- a/script/test +++ b/script/test @@ -68,7 +68,7 @@ for t in $SNACK_TESTS; do done for t in $SNACK_TESTS; do - banner "Test $name" + banner "Test $t" pushd "tests/$t" ./test popd diff --git a/snack-lib/default.nix b/snack-lib/default.nix index fc20899..b3a670b 100644 --- a/snack-lib/default.nix +++ b/snack-lib/default.nix @@ -1,6 +1,7 @@ # This is the entry point of the library, and badly needs documentation. # TODO: currently single out derivations prepend the PWD to the path # TODO: make sure that filters for "base" are airtight +# TODO: document the sh*t out of these functions { pkgs , ghc-version ? "ghc822" , ghcWithPackages ? pkgs.haskell.packages.${ghc-version}.ghcWithPackages @@ -67,6 +68,37 @@ let 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); inferSnackGhci = packageNix: writeText "snack-ghci-json" @@ -152,6 +184,8 @@ let in { inherit + inferBuild + inferGhci inferSnackBuild inferSnackGhci inferHPackBuild @@ -160,7 +194,7 @@ in buildAsExecutable buildAsLibrary snackSpec - hpackSpec + hpackSpecs mkPackage ; } diff --git a/tests/any-paths/test b/tests/any-paths/test index a2e5fcd..54977ce 100755 --- a/tests/any-paths/test +++ b/tests/any-paths/test @@ -8,7 +8,6 @@ test() { $SNACK run } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/extended-config/test b/tests/extended-config/test index 8fc298d..08a5859 100755 --- a/tests/extended-config/test +++ b/tests/extended-config/test @@ -16,6 +16,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4 --snack-nix snack.nix --package-nix package.nix" test -SNACK="snack -j4 --snack-nix snack.nix" test -SNACK="snack -j4 --snack-nix snack.nix --package-yaml package.yaml" test +SNACK="snack -j4 --snack-nix snack.nix --package-file package.nix" test +SNACK="snack -j4 --snack-nix snack.nix --package-file package.yaml" test diff --git a/tests/extensions/test b/tests/extensions/test index 62b4e14..5de06e0 100755 --- a/tests/extensions/test +++ b/tests/extensions/test @@ -15,7 +15,6 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/hpack/test b/tests/hpack/test index fbb5104..dfec0cb 100755 --- a/tests/hpack/test +++ b/tests/hpack/test @@ -8,6 +8,8 @@ TMP_DIR=$(mktemp -d) git clone http://github.com/nmattia/pboy.git $TMP_DIR 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 diff --git a/tests/library-2/test b/tests/library-2/test index 66914ad..a7b780c 100755 --- a/tests/library-2/test +++ b/tests/library-2/test @@ -16,6 +16,6 @@ test() { } SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test # Note: no HPack test, because HPack doesn't support multi library diff --git a/tests/library-3/test b/tests/library-3/test index 2d4bfe9..6299fbc 100755 --- a/tests/library-3/test +++ b/tests/library-3/test @@ -16,6 +16,6 @@ test() { } SNACK="snack" test -SNACK="snack -s ./package.nix" test -SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test +SNACK="snack --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test # Note: no HPack test, because HPack doesn't support multi library diff --git a/tests/library/test b/tests/library/test index ebfd06d..beb0d26 100755 --- a/tests/library/test +++ b/tests/library/test @@ -15,6 +15,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/magichash/test b/tests/magichash/test index ebfd06d..beb0d26 100755 --- a/tests/magichash/test +++ b/tests/magichash/test @@ -15,6 +15,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/nested/test b/tests/nested/test index 0f7c742..47de800 100755 --- a/tests/nested/test +++ b/tests/nested/test @@ -16,6 +16,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/packages/test b/tests/packages/test index 0f7c742..47de800 100755 --- a/tests/packages/test +++ b/tests/packages/test @@ -16,6 +16,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/readme/test b/tests/readme/test index a2e5fcd..54977ce 100755 --- a/tests/readme/test +++ b/tests/readme/test @@ -8,7 +8,6 @@ test() { $SNACK run } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 -s ./package.nix -l ../../snack-lib" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.nix -l ../../snack-lib" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/single-main/test b/tests/single-main/test index ca59f96..7eb46a1 100755 --- a/tests/single-main/test +++ b/tests/single-main/test @@ -8,4 +8,4 @@ test() { $SNACK run } -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4" test diff --git a/tests/source-dirs/test b/tests/source-dirs/test index fbf7191..5adea03 100755 --- a/tests/source-dirs/test +++ b/tests/source-dirs/test @@ -16,10 +16,5 @@ test() { } -SNACK="snack -j4" 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 +SNACK="snack -j4 -p ./package.nix" test +SNACK="snack -j4 -p ./package.yaml" test diff --git a/tests/strips-versions/test b/tests/strips-versions/test index ebfd06d..beb0d26 100755 --- a/tests/strips-versions/test +++ b/tests/strips-versions/test @@ -15,6 +15,5 @@ test() { rm $TMP_FILE } -SNACK="snack -j4" test -SNACK="snack -j4 -s ./package.nix" test -SNACK="snack -j4 --package-yaml ./package.yaml" test +SNACK="snack -j4 --package-file ./package.nix" test +SNACK="snack -j4 --package-file ./package.yaml" test diff --git a/tests/template-haskell-2/test b/tests/template-haskell-2/test index cbebe94..a12eaea 100755 --- a/tests/template-haskell-2/test +++ b/tests/template-haskell-2/test @@ -3,12 +3,12 @@ set -euo pipefail -snack -j4 build -s code/package.nix -snack -j4 run -s code/package.nix | diff golden - +snack -j4 build --package-file code/package.nix +snack -j4 run --package-file code/package.nix | diff golden - 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 rm $TMP_FILE diff --git a/tests/trans-imp/test b/tests/trans-imp/test index ca79687..0a2b95d 100755 --- a/tests/trans-imp/test +++ b/tests/trans-imp/test @@ -16,5 +16,5 @@ 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 diff --git a/tests/utf-8-BOM/test b/tests/utf-8-BOM/test index a301102..140aa53 100755 --- a/tests/utf-8-BOM/test +++ b/tests/utf-8-BOM/test @@ -15,6 +15,5 @@ test() { rm $TMP_FILE } -SNACK="snack" test -SNACK="snack -s ./package.nix" test -SNACK="snack --package-yaml ./package.yaml" test +SNACK="snack --package-file ./package.nix" test +SNACK="snack --package-file ./package.yaml" test diff --git a/tests/utf-8/test b/tests/utf-8/test index a301102..140aa53 100755 --- a/tests/utf-8/test +++ b/tests/utf-8/test @@ -15,6 +15,5 @@ test() { rm $TMP_FILE } -SNACK="snack" test -SNACK="snack -s ./package.nix" test -SNACK="snack --package-yaml ./package.yaml" test +SNACK="snack --package-file ./package.nix" test +SNACK="snack --package-file ./package.yaml" test