1
1
mirror of https://github.com/nmattia/snack.git synced 2024-12-01 03:03:55 +03:00

Merge pull request #99 from nmattia/nm-discovery

Implement discovery mode for package and snack.nix files
This commit is contained in:
Nicolas Mattia 2019-01-19 18:30:30 +01:00 committed by GitHub
commit 51c56ad3a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 330 additions and 259 deletions

View File

@ -19,6 +19,11 @@ Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
- The `snack.nix` now describes the build environment and packages are
described through `package.nix` (i.e. to migrate: rename `snack.nix` to
`package.nix`).
- The same flag (`-p`) is used for specifying both a YAML or Nix file. When
none is provided snack tries to use either `./package.yaml` or
`./package.nix`.
- The flag `-s` is used to specify a `snack.nix`. By default `./snack.nix` is
used.
### Fixed
- The module import parsing when the CPP extension is enabled.

View File

@ -81,14 +81,24 @@ The _snack_ executable is now in your `PATH`:
``` shell
$ snack --help
Usage: snack [-l|--lib DIR] [-b|--snack-nix PATH] [-j|--cores INT]
([-s|--package-nix PATH] | [-p|--package-yaml PATH]) COMMAND
Usage: <interactive> [-l|--lib DIR] ([-s|--snack-nix PATH] | [--no-snack-nix])
[-j|--cores INT] [-p|--package-file PATH] (COMMAND |
COMMAND)
Available options:
-l,--lib DIR Path to the directory to use as the Nix library
instead of the default one bundled with the snack
executable.
-s,--snack-nix PATH Use the specified environment (snack.nix) file. When
none is provided ./snack.nix is used (if it exists).
(Use --no-snack-nix to disable this behavior)
--no-snack-nix Don't use ./snack.nix as the environment (snack.nix)
file.
-j,--cores INT How many cores to use during the build
-p,--package-file PATH Specifies a YAML or Nix file to use as package
description. If not provided, snack looks for either
'package.yaml' or 'package.nix' in the current
directory.
-h,--help Show this help text
Available commands:
@ -106,13 +116,10 @@ suite its own package description.
## Usage
There are two ways to tell snack about a package;
* Use [`--package-nix`](#nix) if you need more control over your build.
* Use [`--package-yaml`](#hpack) for simple builds or if you already have
There are two ways to describe a package:
* Use [`package.yaml` file](#hpack) for simple builds or if you already have
a `package.yaml` file.
If a package option is not supplied then snack will run as if
`--package-nix=package.nix` was given as the package option.
* Use a [`package.nix` file](#nix) if you need more control over your build.
The next two sections show an example config for each option. They use the
following example project which displays the title of the top-rated post on the
@ -190,19 +197,19 @@ default-extensions:
This command will build the project and display the top-rated post's title:
``` shell
$ snack run --package-yaml ./package.yaml
$ snack run
```
You can also build without executing:
``` shell
$ snack build --package-yaml ./package.yaml
$ snack build
```
Alternatively you can load up the project in `ghci`:
``` shell
$ snack ghci --package-yaml ./package.yaml
$ snack ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling Lib ( /home/nicolas/projects/nmattia/snack/tests/readme/src/Lib.hs, interpreted )
[2 of 2] Compiling Main ( /home/nicolas/projects/nmattia/snack/tests/readme/app/Main.hs, interpreted )
@ -233,7 +240,7 @@ in
Building and running the project is as simple as
``` shell
$ snack run # looks for a file called package.nix by default
$ snack run
```
Alternatively, use `$ snack build` or `$ snack ghci` if you only want to build,
@ -310,7 +317,7 @@ If you are hacking on the _snack_ executable, just start _snack_ in a GHCi
session:
``` shell
$ snack ghci -s ./bin/package.nix
$ snack ghci -p ./bin/package.nix
Temporarily symlinking /nix/store/j1x5vkxjr2ibabddfkdih4sm4kwinfda-spec-json/spec.json to spec.json...
done.
Temporarily symlinking /nix/store/w42y6dzgfmli9r8kmgh8akqk6kyda31x-lib64/lib.tar.gz.b64 to lib.tar.gz.b64...
@ -325,7 +332,7 @@ If you are hacking on the library, specify `-l/--lib` when running snack (this
works in GHCi too):
``` shell
*Main> :main ghci -l ./snack-lib/ -s ./tests/readme/package.nix
*Main> :main ghci -l ./snack-lib/ -p ./tests/readme/package.nix
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling Lib ( /home/nicolas/projects/nmattia/snack/tests/readme/src/Lib.hs, interpreted )
[2 of 2] Compiling Main ( /home/nicolas/projects/nmattia/snack/tests/readme/app/Main.hs, interpreted )

View File

@ -15,13 +15,13 @@ module Main (main) where
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Data.Aeson (FromJSON, (.:), (.:?))
import Data.Aeson (FromJSON, (.:))
import Data.FileEmbed (embedStringFile)
import Data.List (intercalate)
import Data.Semigroup ((<>))
import Data.String.Interpolate
import Shelly (Sh)
import System.Directory (canonicalizePath)
import System.Directory (doesFileExist, doesPathExist, canonicalizePath)
import System.Posix.Process (executeFile)
import UnliftIO.Exception
import qualified Data.Aeson as Aeson
@ -32,7 +32,17 @@ import qualified Data.Text as T
import qualified Options.Applicative as Opts
import qualified Shelly as S
---
main :: IO ()
main = do
opts <-
prepareOptions =<<
Opts.execParser (Opts.info (parseOptions <**> Opts.helper) mempty)
runCommand (snackConfig opts) (package opts) (command opts)
-------------------------------------------------------------------------------
-- Configuration
-------------------------------------------------------------------------------
--- Some config helpers
data ConfigStage
@ -43,99 +53,126 @@ type family Config (c :: ConfigStage) ty1 ty2 where
Config 'ConfigRaw ty1 _ = ty1
Config 'ConfigReady _ ty2 = ty2
---
--- Configuration proper
type Mode = Mode_ 'ConfigReady
type ModeRaw = Mode_ 'ConfigRaw
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 . canonicalizePath
-- | Like a FilePath, but Nix friendly
newtype SnackNix = SnackNix FilePath
data SnackNixConfig
= SnackNixSpecific FilePath
| SnackNixDiscovery
| SnackNixNone
parseSnackNixConfig :: Opts.Parser SnackNixConfig
parseSnackNixConfig =
SnackNixSpecific <$> Opts.strOption
(Opts.long "snack-nix"
<> Opts.short 's'
<> Opts.metavar "PATH"
<> Opts.help (unlines
[ "Use the specified environment (snack.nix) file."
, "When none is provided ./snack.nix is used (if it exists)."
, "(Use --no-snack-nix to disable this behavior)"
])
) <|>
Opts.flag'
SnackNixNone
(Opts.long "no-snack-nix"
<> Opts.help "Don't use ./snack.nix as the environment (snack.nix) file."
) <|>
pure SnackNixDiscovery
prepareSnackNix :: SnackNixConfig -> IO (Maybe SnackNix)
prepareSnackNix = \case
SnackNixNone -> pure Nothing
SnackNixSpecific fp -> Just <$> mkSnackNix fp
SnackNixDiscovery -> discoverSnackNix
discoverSnackNix :: IO (Maybe SnackNix)
discoverSnackNix = do
eSNix <- mkSnackNixEither "snack.nix"
case eSNix of
Left{} -> pure Nothing
Right sn -> pure (Just sn)
mkSnackNix :: FilePath -> IO SnackNix
mkSnackNix = fmap SnackNix . canonicalizePath
mkSnackNix = fmap SnackNix . mkFilePath
mkSnackNixEither :: FilePath -> IO (Either String SnackNix)
mkSnackNixEither fp = fmap SnackNix <$> mkFilePathEither fp
-- | Like a FilePath, but Nix friendly
newtype SnackLib = SnackLib FilePath
mkSnackLib :: FilePath -> IO SnackLib
mkSnackLib = fmap SnackLib . canonicalizePath
mkSnackLib = fmap SnackLib . mkDirPath
--- Package description (@package.yaml@, @package.nix@)
-- | Like a FilePath, but Nix friendly
newtype PackageYaml = PackageYaml { unPackageYaml :: FilePath }
newtype PackageFile = PackageFile { unPackageFile :: FilePath }
mkPackageYaml :: FilePath -> IO PackageYaml
mkPackageYaml = fmap PackageYaml . canonicalizePath
-- | What package description (@package.yaml@, @package.nix@) to use
data PackageFileConfig
= PackageFileSpecific FilePath
-- ^ Use the specified file as package description
| PackageFileDiscovery
-- ^ Find a suitable package description
parsePackageFileConfig :: Opts.Parser PackageFileConfig
parsePackageFileConfig =
(PackageFileSpecific <$>
Opts.strOption
(Opts.long "package-file"
<> Opts.short 'p'
<> Opts.help (unlines
[ "Specifies a YAML or Nix file to use as package description."
, "If not provided, snack looks for either 'package.yaml' or 'package.nix' in the current directory."
]
)
<> Opts.metavar "PATH")
) <|> pure PackageFileDiscovery
-- Finding the package descriptions
mkPackageFileEither :: FilePath -> IO (Either String PackageFile)
mkPackageFileEither = fmap (fmap PackageFile) . mkFilePathEither
mkPackageFile :: FilePath -> IO PackageFile
mkPackageFile = fmap PackageFile . mkFilePath
preparePackage :: PackageFileConfig -> IO PackageFile
preparePackage = \case
PackageFileSpecific fp -> mkPackageFile fp
PackageFileDiscovery -> discoverPackageFile
-- | Tries to find a package description.
discoverPackageFile :: IO PackageFile
discoverPackageFile = 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, e.g.: "
, " snack -p " <> yaml, "or"
, " snack -p " <> 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
, "Please specify one with e.g.:"
, " snack -p <path-to-yaml-or-nix>"
]
--- Nix configuration
-- | How to call @nix-build@
newtype NixConfig = NixConfig
{ nixNCores :: Int }
type SnackConfig = SnackConfig_ 'ConfigReady
type SnackConfigRaw = SnackConfig_ 'ConfigRaw
-- | Extra configuration for snack
data SnackConfig_ c = SnackConfig
{ snackLib :: Config c (Maybe FilePath) (Maybe SnackLib)
, snackNix :: Maybe (Config c FilePath SnackNix)
, snackNixCfg :: NixConfig
}
data Command
= Build
| Run [String] -- Run with extra args
| Ghci
| Test
main :: IO ()
main = do
opts <-
prepareOptions =<<
Opts.execParser (Opts.info (parseOptions <**> Opts.helper) mempty)
runCommand (snackConfig opts) (mode opts) (command opts)
type OptionsRaw = Options_ 'ConfigRaw
type Options = Options_ 'ConfigReady
data Options_ c = Options
{ snackConfig :: SnackConfig_ c
, mode :: Mode_ c
, command :: Command
}
prepareOptions :: OptionsRaw -> IO Options
prepareOptions raw =
Options <$>
prepareSnackConfig (snackConfig raw) <*>
prepareMode (mode raw) <*>
pure (command raw)
prepareSnackConfig :: SnackConfigRaw -> IO SnackConfig
prepareSnackConfig raw =
SnackConfig <$>
(case snackLib raw of
Nothing -> pure Nothing
Just fp -> Just <$> mkSnackLib fp
) <*>
forM (snackNix raw) mkSnackNix <*>
pure (snackNixCfg raw)
parseNixConfig :: Opts.Parser NixConfig
parseNixConfig =
(NixConfig <$>
@ -147,6 +184,25 @@ parseNixConfig =
<> Opts.help "How many cores to use during the build")
)
--- Snack configuration (unrelated to packages)
type SnackConfig = SnackConfig_ 'ConfigReady
type SnackConfigRaw = SnackConfig_ 'ConfigRaw
-- | Extra configuration for snack
data SnackConfig_ c = SnackConfig
{ snackLib :: Maybe (Config c FilePath SnackLib)
, snackNix :: Config c SnackNixConfig (Maybe SnackNix)
, snackNixCfg :: NixConfig
}
prepareSnackConfig :: SnackConfigRaw -> IO SnackConfig
prepareSnackConfig raw =
SnackConfig <$>
forM (snackLib raw) mkSnackLib <*>
prepareSnackNix (snackNix raw) <*>
pure (snackNixCfg raw)
parseSnackConfig :: Opts.Parser SnackConfigRaw
parseSnackConfig = SnackConfig <$> Opts.optional
(Opts.strOption
@ -160,40 +216,56 @@ parseSnackConfig = SnackConfig <$> Opts.optional
]
)
)
) <*>
Opts.optional (
Opts.strOption
(Opts.long "snack-nix"
<> Opts.short 'b'
<> Opts.metavar "PATH")
) <*>
) <*> parseSnackNixConfig <*>
parseNixConfig
parseMode :: Opts.Parser ModeRaw
parseMode =
(Standalone <$>
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.short 'p'
<> Opts.metavar "PATH")
)
-- | What command to execute
data Command
= Build
| Run [String] -- Run with extra args
| Ghci
| Test
parseCommand :: Opts.Parser Command
parseCommand =
Opts.hsubparser
( Opts.command "build" (Opts.info (pure Build) mempty)
<> Opts.command "run" (Opts.info
( Run <$> Opts.many (Opts.argument Opts.str (Opts.metavar "ARG"))
) mempty)
<> Opts.command "ghci" (Opts.info (pure Ghci) mempty)
)
<|> Opts.hsubparser
( Opts.command "test" (Opts.info (pure Test) (Opts.progDesc "Use build, run or ghci commands with test suites."))
<> Opts.commandGroup "Unavailable commands:"
)
type OptionsRaw = Options_ 'ConfigRaw
type Options = Options_ 'ConfigReady
-- | The whole set of CLI options
data Options_ c = Options
{ snackConfig :: SnackConfig_ c
, package :: Config c PackageFileConfig PackageFile
, command :: Command
}
prepareOptions :: OptionsRaw -> IO Options
prepareOptions raw =
Options <$>
prepareSnackConfig (snackConfig raw) <*>
preparePackage (package raw) <*>
pure (command raw)
parseOptions :: Opts.Parser OptionsRaw
parseOptions =
Options <$>
parseSnackConfig <*>
parseMode <*>
parsePackageFileConfig <*>
parseCommand
--- Build related types used when interfacing with Nix
newtype ModuleName = ModuleName T.Text
deriving newtype (Ord, Eq, Aeson.FromJSONKey)
deriving stock Show
@ -240,17 +312,16 @@ instance FromJSON ExecutableBuild where
parseJSON = Aeson.withObject "executable build" $ \o ->
ExecutableBuild <$> o .: "exe_path"
data MultiBuild = MultiBuild
{ _librayBuild :: Maybe LibraryBuild
, executableBuilds :: Map.Map T.Text ExecutableBuild
newtype MultiBuild = MultiBuild
{ executableBuilds :: Map.Map T.Text ExecutableBuild
}
deriving stock Show
instance Aeson.FromJSON MultiBuild where
parseJSON = Aeson.withObject "multi build" $ \o ->
MultiBuild
<$> o .:? "library"
<*> o .: "executables"
MultiBuild <$> o .: "executables"
--- Type-helpers for passing arguments to Nix
data NixArg = NixArg
{ argType :: NixArgType
@ -268,12 +339,6 @@ newtype NixPath = NixPath T.Text
deriving newtype FromJSON
deriving stock Show
decodeOrFail :: FromJSON a => BS.ByteString -> Sh a
decodeOrFail bs = case Aeson.decodeStrict' bs of
Just foo -> pure foo
Nothing -> throwIO $ userError $ unlines
[ "could not decode " <> show bs ]
nixBuild :: SnackConfig -> [NixArg] -> NixExpr -> Sh NixPath
nixBuild snackCfg extraNixArgs nixExpr =
NixPath <$> runStdin1
@ -343,71 +408,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
@ -421,29 +453,46 @@ runBuildResult args = \case
runExe exe args
b -> fail $ "Unexpected build type: " <> show b
quiet :: Sh a -> IO a
quiet = S.shelly . S.print_stdout False
runExe :: NixPath -> [String] -> IO ()
runExe (NixPath fp) args = executeFile (T.unpack fp) True args Nothing
parseCommand :: Opts.Parser Command
parseCommand =
Opts.hsubparser
( Opts.command "build" (Opts.info (pure Build) mempty)
<> Opts.command "run" (Opts.info
( Run <$> Opts.many (Opts.argument Opts.str (Opts.metavar "ARG"))
) mempty)
<> Opts.command "ghci" (Opts.info (pure Ghci) mempty)
)
<|> Opts.hsubparser
( Opts.command "test" (Opts.info (pure Test) (Opts.progDesc "Use build, run or ghci commands with test suites."))
<> Opts.commandGroup "Unavailable commands:"
)
specJson :: T.Text
specJson = $(embedStringFile "spec.json")
libb64 :: T.Text
libb64 = $(embedStringFile "lib.tar.gz.b64")
--- Auxiliary
mkDirPath :: FilePath -> IO FilePath
mkDirPath fp = doesPathExist fp >>= \case
True -> doesFileExist fp >>= \case
True -> throwIO $ userError $ fp <> " is a file"
False -> canonicalizePath fp
False -> throwIO $ userError $ fp <> " does not exist"
mkFilePath :: FilePath -> IO FilePath
mkFilePath fp =
mkFilePathEither fp >>= either (throwIO . userError) pure
mkFilePathEither :: FilePath -> IO (Either String FilePath)
mkFilePathEither fp = doesFileExist fp >>= \case
True -> Right <$> canonicalizePath fp
False -> doesPathExist fp >>= \case
True -> pure (Left (fp <> " is a directory"))
False -> pure (Left (fp <> " does not exist"))
decodeOrFail :: FromJSON a => BS.ByteString -> Sh a
decodeOrFail bs = case Aeson.decodeStrict' bs of
Just foo -> pure foo
Nothing -> throwIO $ userError $ unlines
[ "could not decode " <> show bs ]
-- | Run the executable with given arguments
run :: S.FilePath -> [T.Text] -> Sh [T.Text]
run p args = T.lines <$> S.run p args
-- | Run the executable with given arguments, assuming a single line of output
runStdin1 :: T.Text -> S.FilePath -> [T.Text] -> Sh T.Text
runStdin1 stin p args = do
S.setStdin stin
@ -451,8 +500,5 @@ runStdin1 stin p args = do
[out] -> pure out
xs -> throwIO $ userError $ "unexpected output: " <> show xs
specJson :: T.Text
specJson = $(embedStringFile "spec.json")
libb64 :: T.Text
libb64 = $(embedStringFile "lib.tar.gz.b64")
quiet :: Sh a -> IO a
quiet = S.shelly . S.print_stdout False

View File

@ -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

View File

@ -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
;
}

View File

@ -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

View File

@ -1,7 +0,0 @@
{ main = "Foo";
src = ./src;
dependencies = [
"conduit"
"something-that-doesnt-exist"
];
}

View File

@ -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.yaml" test
SNACK="snack -j4" test

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -8,4 +8,4 @@ test() {
$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
# 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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