diff --git a/Changelog.org b/Changelog.org index d41a1fd..b0c48d7 100644 --- a/Changelog.org +++ b/Changelog.org @@ -1,6 +1,10 @@ * Unreleased + +* Version 0.5.0.0 +- Split modules so that implementing new languages becomes easier - More tests - Language data type +- Toolchain downgrade to GHC 9.8 (dropped into Nixpkgs, and so is easier to use) * Version 0.4.0.1 - Update and improve GitHub workflows (use Nix and Cachix) diff --git a/Readme.org b/Readme.org index 503431f..94fe36f 100644 --- a/Readme.org +++ b/Readme.org @@ -95,6 +95,12 @@ Available options: SCRIPT_ARGS Arguments passed on to the script #+end_example +* New languages +We have designed Magix so that implementing new languages is straightforward. In +particular: +- Change and add modules only within the =src/Magix/Languages/*= namespace. +- Add language-specific tests to =test/Magix/Languages/*=. + * Next steps - Property-based testing (e.g., generate arbitrary directives or even scripts). When creating arbitrary directives, one could test if the resulting diff --git a/app/Main.hs b/app/Main.hs index 8253ed9..3e9aab9 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -18,12 +18,22 @@ import Control.Exception (onException, throwIO) import Data.ByteString (readFile) import Data.Text (unpack) import Data.Text.Encoding (decodeUtf8') -import Magix.Build (BuildStatus (..), build, getBuildStatus, withBuildLock) -import Magix.Config (Config, getConfig) -import Magix.Directives (Directives, getDirectives) -import Magix.Expression (getNixExpression) -import Magix.Options (Options (..), Rebuild (..), Verbosity (..), getOptions) -import Magix.Run (run) +import Magix + ( BuildStatus (..), + Config, + Directives, + Options (..), + Rebuild (..), + Verbosity (..), + build, + getBuildStatus, + getConfig, + getDirectives, + getNixExpression, + getOptions, + run, + withBuildLock, + ) import System.Console.ANSI ( Color (Green, Red, White), ColorIntensity (Dull), diff --git a/flake.lock b/flake.lock index 3725da4..81cdc1f 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1744932701, - "narHash": "sha256-fusHbZCyv126cyArUwwKrLdCkgVAIaa/fQJYFlCEqiU=", + "lastModified": 1756125398, + "narHash": "sha256-XexyKZpf46cMiO5Vbj+dWSAXOnr285GHsMch8FBoHbc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b024ced1aac25639f8ca8fdfc2f8c4fbd66c48ef", + "rev": "3b9f00d7a7bf68acd4c4abb9d43695afb04e03a5", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 157ce51..fb34aba 100644 --- a/flake.nix +++ b/flake.nix @@ -15,8 +15,7 @@ theseHpkgNames = [ "magix" ]; - # NOTE: When updating GHC, do not forget to also update the CICD script. - thisGhcVersion = "ghc910"; + thisGhcVersion = "ghc98"; hOverlay = selfn: supern: { haskell = supern.haskell // { packageOverrides = diff --git a/magix.cabal b/magix.cabal index a5fc4c0..aee6585 100644 --- a/magix.cabal +++ b/magix.cabal @@ -1,6 +1,6 @@ cabal-version: 3.4 name: magix -version: 0.4.0.1 +version: 0.5.0.0 synopsis: Build, cache, and run possibly compiled scripts with dependencies using the Nix package manager @@ -61,13 +61,15 @@ library Magix.Directives Magix.Expression Magix.Hash - Magix.Language Magix.Languages.Bash.Directives Magix.Languages.Bash.Expression + Magix.Languages.Common.Directives + Magix.Languages.Common.Expression Magix.Languages.Directives Magix.Languages.Expression Magix.Languages.Haskell.Directives Magix.Languages.Haskell.Expression + Magix.Languages.Language Magix.Languages.Python.Directives Magix.Languages.Python.Expression Magix.NixpkgsPath @@ -118,11 +120,12 @@ test-suite test-magix Magix.DirectivesSpec Magix.Languages.Bash.DirectivesSpec Magix.Languages.Bash.ExpressionSpec - Magix.Languages.DirectivesSpec + Magix.Languages.Common.DirectivesSpec Magix.Languages.Haskell.DirectivesSpec Magix.Languages.Haskell.ExpressionSpec Magix.Languages.Python.DirectivesSpec Magix.Languages.Python.ExpressionSpec + Magix.Languages.Tools Magix.NixpkgsPathSpec Magix.Tools diff --git a/src/Magix.hs b/src/Magix.hs index 549994c..dc75022 100644 --- a/src/Magix.hs +++ b/src/Magix.hs @@ -12,8 +12,11 @@ module Magix ( -- Options. Options (..), + Rebuild (..), + Verbosity (..), getOptions, -- Configuration. + Config, getConfig, -- Directives. getDirectives, @@ -23,11 +26,18 @@ module Magix BuildStatus (..), getBuildStatus, build, + withBuildLock, + -- Run. + run, + -- Languages. + Directives, ) where -import Magix.Build (BuildStatus (..), build, getBuildStatus) -import Magix.Config (getConfig) +import Magix.Build (BuildStatus (..), build, getBuildStatus, withBuildLock) +import Magix.Config (Config, getConfig) import Magix.Directives (getDirectives) import Magix.Expression (getNixExpression) -import Magix.Options (Options (..), getOptions) +import Magix.Languages.Directives (Directives) +import Magix.Options (Options (..), Rebuild (..), Verbosity (..), getOptions) +import Magix.Run (run) diff --git a/src/Magix/Directives.hs b/src/Magix/Directives.hs index f4be112..7ffc905 100644 --- a/src/Magix/Directives.hs +++ b/src/Magix/Directives.hs @@ -10,9 +10,7 @@ -- -- Creation date: Fri Oct 18 09:17:40 2024. module Magix.Directives - ( Directives (..), - getLanguage, - pShebang, + ( pShebang, pMagixDirective, pLanguageDirectives, pDirectives, @@ -20,41 +18,30 @@ module Magix.Directives ) where -import Control.Applicative (Alternative (..)) import Control.Exception (Exception) import Data.Bifunctor (Bifunctor (..)) import Data.Text (Text) -import Magix.Language (Language (..), pLanguage) -import Magix.Languages.Bash.Directives (BashDirectives, pBashDirectives) -import Magix.Languages.Directives (Parser, pDirectiveWithValue) -import Magix.Languages.Haskell.Directives (HaskellDirectives, pHaskellDirectives) -import Magix.Languages.Python.Directives (PythonDirectives, pPythonDirectives) -import Text.Megaparsec (MonadParsec (notFollowedBy, try), chunk, errorBundlePretty, parse) -import Text.Megaparsec.Char (hspace, newline, space) +import Magix.Languages.Common.Directives (Parser, pDirectiveWithValue) +import Magix.Languages.Directives (Directives, getDirectivesParser) +import Magix.Languages.Language (Language (..), getLanguageNameLowercase) +import Text.Megaparsec + ( MonadParsec (notFollowedBy), + choice, + chunk, + errorBundlePretty, + parse, + ) +import Text.Megaparsec.Char (hspace, newline, space, string) import Prelude hiding (readFile) -data Directives - = BashD !BashDirectives - | HaskellD !HaskellDirectives - | PythonD !PythonDirectives - deriving (Eq, Show) - -getDirectivesParser :: Language -> Parser Directives -getDirectivesParser l = case l of - Bash -> BashD <$> withNewline pBashDirectives - Haskell -> HaskellD <$> withNewline pHaskellDirectives - Python -> PythonD <$> withNewline pPythonDirectives - where - withNewline p = try (newline *> p) <|> mempty - -getLanguage :: Directives -> Language -getLanguage (BashD _) = Bash -getLanguage (HaskellD _) = Haskell -getLanguage (PythonD _) = Python - pShebang :: Parser Text pShebang = pDirectiveWithValue "/usr/bin/env" (chunk "magix") +pLanguage :: Parser Language +pLanguage = choice $ map pAnyLanguage [minBound .. maxBound :: Language] + where + pAnyLanguage language = language <$ string (getLanguageNameLowercase language) + pMagixDirective :: Parser Language pMagixDirective = pDirectiveWithValue "magix" pLanguage <* hspace diff --git a/src/Magix/Expression.hs b/src/Magix/Expression.hs index 0b05a68..8cc807a 100644 --- a/src/Magix/Expression.hs +++ b/src/Magix/Expression.hs @@ -16,15 +16,14 @@ module Magix.Expression ) where +import Data.Foldable qualified as Foldable import Data.Text (Text, replace) import Data.Text.IO (readFile) import Magix.Config (Config (..)) -import Magix.Directives (Directives (..), getLanguage) -import Magix.Language (Language (..)) -import Magix.Languages.Bash.Expression (getBashReplacements) -import Magix.Languages.Expression (Replacement, getCommonReplacements) -import Magix.Languages.Haskell.Expression (getHaskellReplacements) -import Magix.Languages.Python.Expression (getPythonReplacements) +import Magix.Languages.Common.Expression (Replacement, getCommonReplacements) +import Magix.Languages.Directives (Directives (..), getLanguage) +import Magix.Languages.Expression (getLanguageReplacements) +import Magix.Languages.Language (Language (..)) import Paths_magix (getDataFileName) import Prelude hiding (readFile) @@ -34,17 +33,12 @@ getTemplatePath language = "src/Magix/Languages/" <> show language <> "/Template getTemplate :: Language -> IO Text getTemplate language = getDataFileName (getTemplatePath language) >>= readFile -getLanguageReplacements :: Directives -> [Replacement] -getLanguageReplacements (BashD ds) = getBashReplacements ds -getLanguageReplacements (HaskellD ds) = getHaskellReplacements ds -getLanguageReplacements (PythonD ds) = getPythonReplacements ds - getReplacements :: Config -> Directives -> [Replacement] getReplacements c ds = getCommonReplacements c ++ getLanguageReplacements ds getNixExpression :: Config -> Directives -> IO Text getNixExpression c ds = do t <- getTemplate $ getLanguage ds - pure $ foldl' replace' t (getReplacements c ds) + pure $ Foldable.foldl' replace' t (getReplacements c ds) where replace' t (x, y) = replace x y t diff --git a/src/Magix/Hash.hs b/src/Magix/Hash.hs index dbc32dc..eaa65b7 100644 --- a/src/Magix/Hash.hs +++ b/src/Magix/Hash.hs @@ -17,6 +17,7 @@ where import Crypto.Hash.SHA256 (finalize, init, update) import Data.ByteString (ByteString, toStrict) import Data.ByteString.Builder (Builder, charUtf8, intDec, toLazyByteString) +import Data.Foldable qualified as Foldable import Data.Version (Version (versionBranch)) import Paths_magix (version) import Prelude hiding (init) @@ -27,7 +28,7 @@ toByteStringWith f = toStrict . toLazyByteString . mconcat . map f getMagixHash :: FilePath -> ByteString -> ByteString getMagixHash nixpkgsPath scriptContents = finalize $ - foldl' + Foldable.foldl' update init [ toByteStringWith charUtf8 nixpkgsPath, diff --git a/src/Magix/Languages/Bash/Directives.hs b/src/Magix/Languages/Bash/Directives.hs index e436bae..63f663f 100644 --- a/src/Magix/Languages/Bash/Directives.hs +++ b/src/Magix/Languages/Bash/Directives.hs @@ -16,7 +16,7 @@ module Magix.Languages.Bash.Directives where import Data.Text (Text) -import Magix.Languages.Directives +import Magix.Languages.Common.Directives ( Parser, pDirectiveWithValues, pManyDirectives, diff --git a/src/Magix/Languages/Bash/Expression.hs b/src/Magix/Languages/Bash/Expression.hs index 0cd4c83..c800a62 100644 --- a/src/Magix/Languages/Bash/Expression.hs +++ b/src/Magix/Languages/Bash/Expression.hs @@ -16,7 +16,7 @@ where import Data.Text (unwords) import Magix.Languages.Bash.Directives (BashDirectives (..)) -import Magix.Languages.Expression (Replacement) +import Magix.Languages.Common.Expression (Replacement) import Prelude hiding (unwords) getBashReplacements :: BashDirectives -> [Replacement] diff --git a/src/Magix/Languages/Common/Directives.hs b/src/Magix/Languages/Common/Directives.hs new file mode 100644 index 0000000..a8f1c2e --- /dev/null +++ b/src/Magix/Languages/Common/Directives.hs @@ -0,0 +1,52 @@ +-- | +-- Module : Magix.Languages.Common.Directives +-- Description : Common tools for parsing directives +-- Copyright : 2024 Dominik Schrempf +-- License : GPL-3.0-or-later +-- +-- Maintainer : dominik.schrempf@gmail.com +-- Stability : experimental +-- Portability : portable +-- +-- Creation date: Fri Oct 18 09:17:40 2024. +module Magix.Languages.Common.Directives + ( Parser, + pDirectiveWithValue, + pDirectiveWithValues, + pManyDirectives, + ) +where + +import Control.Applicative (Alternative (..)) +import Data.Text (Text, pack) +import Data.Void (Void) +import Text.Megaparsec + ( Parsec, + chunk, + sepEndBy, + sepEndBy1, + ) +import Text.Megaparsec.Char + ( alphaNumChar, + hspace, + newline, + punctuationChar, + symbolChar, + ) + +type Parser = Parsec Void Text + +pDirective :: Text -> Parser Text +pDirective d = chunk "#!" *> chunk d + +pValue :: Parser Text +pValue = pack <$> some (alphaNumChar <|> punctuationChar <|> symbolChar) + +pDirectiveWithValue :: Text -> Parser a -> Parser a +pDirectiveWithValue d p = pDirective d *> hspace *> p + +pDirectiveWithValues :: Text -> Parser [Text] +pDirectiveWithValues d = pDirectiveWithValue d (sepEndBy1 pValue hspace) + +pManyDirectives :: (Monoid b) => Parser b -> Parser b +pManyDirectives p = mconcat <$> sepEndBy p (hspace <* newline) diff --git a/src/Magix/Languages/Common/Expression.hs b/src/Magix/Languages/Common/Expression.hs new file mode 100644 index 0000000..22522b6 --- /dev/null +++ b/src/Magix/Languages/Common/Expression.hs @@ -0,0 +1,27 @@ +-- | +-- Module : Magix.Languages.Common.Expression +-- Description : Common definitions related to handling Nix expressions +-- Copyright : 2025 Dominik Schrempf +-- License : GPL-3.0-or-later +-- +-- Maintainer : dominik.schrempf@gmail.com +-- Stability : experimental +-- Portability : portable +-- +-- Creation date: Fri Apr 11 06:36:34 2025. +module Magix.Languages.Common.Expression + ( Replacement, + getCommonReplacements, + ) +where + +import Data.Text (Text, pack) +import Magix.Config (Config (..)) + +type Replacement = (Text, Text) + +getCommonReplacements :: Config -> [Replacement] +getCommonReplacements c = + [ ("__SCRIPT_NAME__", pack $ scriptName c), + ("__SCRIPT_SOURCE__", pack $ scriptLinkPath c) + ] diff --git a/src/Magix/Languages/Directives.hs b/src/Magix/Languages/Directives.hs index 2b56b96..5d887f4 100644 --- a/src/Magix/Languages/Directives.hs +++ b/src/Magix/Languages/Directives.hs @@ -1,52 +1,47 @@ -- | -- Module : Magix.Languages.Directives --- Description : Common tools for parsing directives --- Copyright : 2024 Dominik Schrempf +-- Description : Pooled language directives +-- Copyright : 2025 Dominik Schrempf -- License : GPL-3.0-or-later -- -- Maintainer : dominik.schrempf@gmail.com -- Stability : experimental -- Portability : portable -- --- Creation date: Fri Oct 18 09:17:40 2024. +-- Creation date: Mon Apr 22 14:10:46 2025. +-- +-- Bijective map between `Language` and `Directives`. module Magix.Languages.Directives - ( Parser, - pDirectiveWithValue, - pDirectiveWithValues, - pManyDirectives, + ( Directives (..), + getDirectivesParser, + getLanguage, ) where import Control.Applicative (Alternative (..)) -import Data.Text (Text, pack) -import Data.Void (Void) -import Text.Megaparsec - ( Parsec, - chunk, - sepEndBy, - sepEndBy1, - ) -import Text.Megaparsec.Char - ( alphaNumChar, - hspace, - newline, - punctuationChar, - symbolChar, - ) - -type Parser = Parsec Void Text - -pDirective :: Text -> Parser Text -pDirective d = chunk "#!" *> chunk d - -pValue :: Parser Text -pValue = pack <$> some (alphaNumChar <|> punctuationChar <|> symbolChar) +import Magix.Languages.Bash.Directives (BashDirectives, pBashDirectives) +import Magix.Languages.Common.Directives (Parser) +import Magix.Languages.Haskell.Directives (HaskellDirectives, pHaskellDirectives) +import Magix.Languages.Language (Language (..)) +import Magix.Languages.Python.Directives (PythonDirectives, pPythonDirectives) +import Text.Megaparsec (try) +import Text.Megaparsec.Char (newline) -pDirectiveWithValue :: Text -> Parser a -> Parser a -pDirectiveWithValue d p = pDirective d *> hspace *> p +data Directives + = BashD !BashDirectives + | HaskellD !HaskellDirectives + | PythonD !PythonDirectives + deriving (Eq, Show) -pDirectiveWithValues :: Text -> Parser [Text] -pDirectiveWithValues d = pDirectiveWithValue d (sepEndBy1 pValue hspace) +getDirectivesParser :: Language -> Parser Directives +getDirectivesParser l = case l of + Bash -> BashD <$> withNewline pBashDirectives + Haskell -> HaskellD <$> withNewline pHaskellDirectives + Python -> PythonD <$> withNewline pPythonDirectives + where + withNewline p = try (newline *> p) <|> mempty -pManyDirectives :: (Monoid b) => Parser b -> Parser b -pManyDirectives p = mconcat <$> sepEndBy p (hspace <* newline) +getLanguage :: Directives -> Language +getLanguage (BashD _) = Bash +getLanguage (HaskellD _) = Haskell +getLanguage (PythonD _) = Python diff --git a/src/Magix/Languages/Expression.hs b/src/Magix/Languages/Expression.hs index 3dbebce..59ca2ed 100644 --- a/src/Magix/Languages/Expression.hs +++ b/src/Magix/Languages/Expression.hs @@ -1,6 +1,6 @@ -- | -- Module : Magix.Languages.Expression --- Description : Common definitions related to handling Nix expressions +-- Description : Pooled language expressions -- Copyright : 2025 Dominik Schrempf -- License : GPL-3.0-or-later -- @@ -8,20 +8,16 @@ -- Stability : experimental -- Portability : portable -- --- Creation date: Fri Apr 11 06:36:34 2025. -module Magix.Languages.Expression - ( Replacement, - getCommonReplacements, - ) -where +-- Creation date: Mon Apr 22 14:10:46 2025. +module Magix.Languages.Expression (getLanguageReplacements) where -import Data.Text (Text, pack) -import Magix.Config (Config (..)) +import Magix.Languages.Bash.Expression (getBashReplacements) +import Magix.Languages.Common.Expression (Replacement) +import Magix.Languages.Directives (Directives (BashD, HaskellD, PythonD)) +import Magix.Languages.Haskell.Expression (getHaskellReplacements) +import Magix.Languages.Python.Expression (getPythonReplacements) -type Replacement = (Text, Text) - -getCommonReplacements :: Config -> [Replacement] -getCommonReplacements c = - [ ("__SCRIPT_NAME__", pack $ scriptName c), - ("__SCRIPT_SOURCE__", pack $ scriptLinkPath c) - ] +getLanguageReplacements :: Directives -> [Replacement] +getLanguageReplacements (BashD ds) = getBashReplacements ds +getLanguageReplacements (HaskellD ds) = getHaskellReplacements ds +getLanguageReplacements (PythonD ds) = getPythonReplacements ds diff --git a/src/Magix/Languages/Haskell/Directives.hs b/src/Magix/Languages/Haskell/Directives.hs index bd35c8e..5367041 100644 --- a/src/Magix/Languages/Haskell/Directives.hs +++ b/src/Magix/Languages/Haskell/Directives.hs @@ -17,7 +17,7 @@ where import Control.Applicative (Alternative (..)) import Data.Text (Text) -import Magix.Languages.Directives +import Magix.Languages.Common.Directives ( Parser, pDirectiveWithValues, pManyDirectives, diff --git a/src/Magix/Languages/Haskell/Expression.hs b/src/Magix/Languages/Haskell/Expression.hs index 2b5644e..819a16f 100644 --- a/src/Magix/Languages/Haskell/Expression.hs +++ b/src/Magix/Languages/Haskell/Expression.hs @@ -15,7 +15,7 @@ module Magix.Languages.Haskell.Expression where import Data.Text (unwords) -import Magix.Languages.Expression (Replacement) +import Magix.Languages.Common.Expression (Replacement) import Magix.Languages.Haskell.Directives (HaskellDirectives (..)) import Prelude hiding (readFile, unwords) diff --git a/src/Magix/Language.hs b/src/Magix/Languages/Language.hs similarity index 59% rename from src/Magix/Language.hs rename to src/Magix/Languages/Language.hs index 0b53e08..69f1243 100644 --- a/src/Magix/Language.hs +++ b/src/Magix/Languages/Language.hs @@ -1,5 +1,5 @@ -- | --- Module : Magix.Language +-- Module : Magix.Languages.Language -- Description : Languages supported by Magix -- Copyright : 2025 Dominik Schrempf -- License : GPL-3.0-or-later @@ -9,25 +9,16 @@ -- Portability : portable -- -- Creation date: Mon Apr 21 14:10:46 2025. -module Magix.Language +module Magix.Languages.Language ( Language (..), getLanguageNameLowercase, - pLanguage, ) where import Data.Text (Text, pack, toLower) -import Magix.Languages.Directives (Parser) -import Text.Megaparsec (choice) -import Text.Megaparsec.Char (string) data Language = Bash | Haskell | Python deriving (Eq, Show, Ord, Enum, Bounded) getLanguageNameLowercase :: Language -> Text getLanguageNameLowercase = toLower . pack . show - -pLanguage :: Parser Language -pLanguage = choice $ map pAnyLanguage [minBound .. maxBound :: Language] - where - pAnyLanguage language = language <$ string (getLanguageNameLowercase language) diff --git a/src/Magix/Languages/Python/Directives.hs b/src/Magix/Languages/Python/Directives.hs index 26d2e9c..ffe660a 100644 --- a/src/Magix/Languages/Python/Directives.hs +++ b/src/Magix/Languages/Python/Directives.hs @@ -16,7 +16,7 @@ module Magix.Languages.Python.Directives where import Data.Text (Text) -import Magix.Languages.Directives +import Magix.Languages.Common.Directives ( Parser, pDirectiveWithValues, pManyDirectives, diff --git a/src/Magix/Languages/Python/Expression.hs b/src/Magix/Languages/Python/Expression.hs index ad25d2e..361f861 100644 --- a/src/Magix/Languages/Python/Expression.hs +++ b/src/Magix/Languages/Python/Expression.hs @@ -15,7 +15,7 @@ module Magix.Languages.Python.Expression where import Data.Text (unwords) -import Magix.Languages.Expression (Replacement) +import Magix.Languages.Common.Expression (Replacement) import Magix.Languages.Python.Directives (PythonDirectives (..)) import Prelude hiding (unwords) diff --git a/test/Magix/DirectivesSpec.hs b/test/Magix/DirectivesSpec.hs index 83a1875..f117861 100644 --- a/test/Magix/DirectivesSpec.hs +++ b/test/Magix/DirectivesSpec.hs @@ -17,47 +17,24 @@ where import Data.Text (Text, unlines) import Data.Text.IO (readFile) import Magix.Directives - ( Directives (..), - pDirectives, + ( pDirectives, pLanguageDirectives, pMagixDirective, pShebang, ) -import Magix.Language (Language (..), getLanguageNameLowercase) import Magix.Languages.Bash.Directives (BashDirectives (..)) +import Magix.Languages.Directives (Directives (..)) import Magix.Languages.Haskell.Directives (HaskellDirectives (..)) +import Magix.Languages.Language (Language (..), getLanguageNameLowercase) import Magix.Languages.Python.Directives (PythonDirectives (..)) +import Magix.Languages.Tools (getEmptyDirectives, getMinimalTestcase) import Magix.Tools (parseF, parseS) -import Test.Hspec (Spec, SpecWith, describe, it, shouldBe) -import Text.Megaparsec (parse) +import Test.Hspec (Spec, SpecWith, describe, it) import Prelude hiding (readFile, unlines) -fnMinimalBash :: FilePath -fnMinimalBash = "test-scripts/bash/minimal" - -readMinimalBash :: IO Text -readMinimalBash = readFile fnMinimalBash - -fnMinimalHaskell :: FilePath -fnMinimalHaskell = "test-scripts/haskell/minimal" - -readMinimalHaskell :: IO Text -readMinimalHaskell = readFile fnMinimalHaskell - -fnMinimalPython :: FilePath -fnMinimalPython = "test-scripts/python/minimal" - -readMinimalPython :: IO Text -readMinimalPython = readFile fnMinimalPython - languages :: [Language] languages = [minBound .. maxBound] -getEmptyDirectives :: Language -> Directives -getEmptyDirectives Bash = BashD mempty -getEmptyDirectives Haskell = HaskellD mempty -getEmptyDirectives Python = PythonD mempty - pEmptyLanguageDirectivesFor :: Language -> SpecWith () pEmptyLanguageDirectivesFor language = it description $ @@ -74,6 +51,13 @@ pEmptyLanguageDirectivesFor language = emptyDirectives = getEmptyDirectives language testWith directives = parseS pLanguageDirectives directives emptyDirectives +pMinimalFor :: Language -> SpecWith () +pMinimalFor language = + it "parses minimal sample scripts" $ do + let (fn, res) = getMinimalTestcase language + fo <- readFile fn + parseS pDirectives fo res + spec :: Spec spec = do describe "pShebang" $ do @@ -95,9 +79,11 @@ spec = do sequence_ [testLanguage lang | lang <- languages] it "fails on wrong Magix directives" $ do - parseF pMagixDirective "#!magic haskell" + parseF pMagixDirective "#!magic foo" parseF pMagixDirective "#!magic" + -- TODO: Forcce testing of all languages. If `bash` or any other language is + -- used somewhere, instead test for all languages. describe "pLanguageDirectives" $ do it "fails on wrong language directives" $ do parseF pLanguageDirectives "#! bar" @@ -111,7 +97,7 @@ spec = do mapM_ pEmptyLanguageDirectivesFor languages - -- Force testing of all languages. + -- TODO: Force testing of all languages. it "parses Bash language directives" $ do parseS pLanguageDirectives "#!magix bash\n#!packages bar" $ BashD (BashDirectives ["bar"]) @@ -127,17 +113,7 @@ spec = do PythonD (PythonDirectives ["requests"]) describe "pDirectives" $ do - -- Force testing of all languages. - it "parses minimal sample scripts" $ do - minimalBash <- readMinimalBash - parse pDirectives fnMinimalBash minimalBash - `shouldBe` Right (BashD (BashDirectives ["jq"])) - minimalHaskell <- readMinimalHaskell - parse pDirectives fnMinimalHaskell minimalHaskell - `shouldBe` Right (HaskellD (HaskellDirectives ["bytestring"] ["-threaded"])) - minimalPython <- readMinimalPython - parse pDirectives fnMinimalPython minimalPython - `shouldBe` Right (PythonD (PythonDirectives ["numpy"])) + mapM_ pMinimalFor languages it "parses some edge cases" $ do let spaceTest :: Text = diff --git a/test/Magix/Languages/Bash/ExpressionSpec.hs b/test/Magix/Languages/Bash/ExpressionSpec.hs index de4caa2..12f43db 100644 --- a/test/Magix/Languages/Bash/ExpressionSpec.hs +++ b/test/Magix/Languages/Bash/ExpressionSpec.hs @@ -15,8 +15,8 @@ module Magix.Languages.Bash.ExpressionSpec where import Data.Text (Text) -import Magix.Directives (Directives (..)) import Magix.Languages.Bash.Directives (BashDirectives (..)) +import Magix.Languages.Directives (Directives (..)) import Magix.Tools (testExpression) import Test.Hspec (Spec) diff --git a/test/Magix/Languages/DirectivesSpec.hs b/test/Magix/Languages/Common/DirectivesSpec.hs similarity index 94% rename from test/Magix/Languages/DirectivesSpec.hs rename to test/Magix/Languages/Common/DirectivesSpec.hs index 8417fc3..0740a2c 100644 --- a/test/Magix/Languages/DirectivesSpec.hs +++ b/test/Magix/Languages/Common/DirectivesSpec.hs @@ -1,5 +1,5 @@ -- | --- Module : Magix.Languages.DirectivesSpec +-- Module : Magix.Languages.Common.DirectivesSpec -- Description : Tests for parsing common directives -- Copyright : 2024 Dominik Schrempf -- License : GPL-3.0-or-later @@ -9,12 +9,12 @@ -- Portability : portable -- -- Creation date: Fri Oct 18 09:34:01 2024. -module Magix.Languages.DirectivesSpec +module Magix.Languages.Common.DirectivesSpec ( spec, ) where -import Magix.Languages.Directives +import Magix.Languages.Common.Directives ( pDirectiveWithValue, pDirectiveWithValues, pManyDirectives, diff --git a/test/Magix/Languages/Haskell/ExpressionSpec.hs b/test/Magix/Languages/Haskell/ExpressionSpec.hs index 2813f08..d6caff5 100644 --- a/test/Magix/Languages/Haskell/ExpressionSpec.hs +++ b/test/Magix/Languages/Haskell/ExpressionSpec.hs @@ -15,7 +15,7 @@ module Magix.Languages.Haskell.ExpressionSpec where import Data.Text (Text) -import Magix.Directives (Directives (..)) +import Magix.Languages.Directives (Directives (..)) import Magix.Languages.Haskell.Directives (HaskellDirectives (..)) import Magix.Tools (testExpression) import Test.Hspec (Spec) diff --git a/test/Magix/Languages/Python/ExpressionSpec.hs b/test/Magix/Languages/Python/ExpressionSpec.hs index 66f74dd..b8852cf 100644 --- a/test/Magix/Languages/Python/ExpressionSpec.hs +++ b/test/Magix/Languages/Python/ExpressionSpec.hs @@ -15,7 +15,7 @@ module Magix.Languages.Python.ExpressionSpec where import Data.Text (Text) -import Magix.Directives (Directives (..)) +import Magix.Languages.Directives (Directives (..)) import Magix.Languages.Python.Directives (PythonDirectives (..)) import Magix.Tools (testExpression) import Test.Hspec (Spec) diff --git a/test/Magix/Languages/Tools.hs b/test/Magix/Languages/Tools.hs new file mode 100644 index 0000000..35071c7 --- /dev/null +++ b/test/Magix/Languages/Tools.hs @@ -0,0 +1,42 @@ +-- | +-- Module : Magix.Languages.Tools +-- Description : Language-specific test tools +-- Copyright : 2025 Dominik Schrempf +-- License : GPL-3.0-or-later +-- +-- Maintainer : dominik.schrempf@gmail.com +-- Stability : experimental +-- Portability : portable +-- +-- Creation date: Tue Apr 22 15:19:11 2025. +module Magix.Languages.Tools + ( getEmptyDirectives, + getMinimalTestcase, + ) +where + +import Magix.Languages.Bash.Directives (BashDirectives (BashDirectives)) +import Magix.Languages.Directives (Directives (..)) +import Magix.Languages.Haskell.Directives (HaskellDirectives (HaskellDirectives)) +import Magix.Languages.Language (Language (..)) +import Magix.Languages.Python.Directives (PythonDirectives (PythonDirectives)) +import Prelude hiding (readFile) + +getEmptyDirectives :: Language -> Directives +getEmptyDirectives Bash = BashD mempty +getEmptyDirectives Haskell = HaskellD mempty +getEmptyDirectives Python = PythonD mempty + +getMinimalTestcase :: Language -> (FilePath, Directives) +getMinimalTestcase Bash = + ( "test-scripts/bash/minimal", + BashD (BashDirectives ["jq"]) + ) +getMinimalTestcase Haskell = + ( "test-scripts/haskell/minimal", + HaskellD (HaskellDirectives ["bytestring"] ["-threaded"]) + ) +getMinimalTestcase Python = + ( "test-scripts/python/minimal", + PythonD (PythonDirectives ["numpy"]) + ) diff --git a/test/Magix/Tools.hs b/test/Magix/Tools.hs index ea38ad3..da5cb02 100644 --- a/test/Magix/Tools.hs +++ b/test/Magix/Tools.hs @@ -23,8 +23,8 @@ import Data.ByteString (ByteString, pack) import Data.Either (isLeft) import Data.Text (Text, isInfixOf, unwords) import Magix.Config (Config (..)) -import Magix.Directives (Directives, getLanguage) import Magix.Expression (getNixExpression, getReplacements, getTemplate) +import Magix.Languages.Directives (Directives, getLanguage) import System.Directory (createDirectory, getTemporaryDirectory) import System.FilePath (()) import System.Random.Stateful (randomIO, randomRIO)