hix 0.1.1.0 → 0.2.0.0
raw patch · 10 files changed
+152/−48 lines, 10 filesdep ~aesondep ~hedgehogdep ~lensPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, hedgehog, lens, tasty-hedgehog
API changes (from Hackage documentation)
- Hix.Options: instance GHC.Classes.Eq Hix.Options.PreprocOptions
+ Hix.Data.GhciConfig: PreludeConfig :: PreludePackage -> ModuleName -> PreludeConfig
+ Hix.Data.GhciConfig: PreludePackageName :: Text -> PreludePackage
+ Hix.Data.GhciConfig: PreludePackageSpec :: Text -> PreludePackage
+ Hix.Data.GhciConfig: PreprocConfig :: PackagesConfig -> PreprocConfig
+ Hix.Data.GhciConfig: [$sel:extensions:ComponentConfig] :: ComponentConfig -> [String]
+ Hix.Data.GhciConfig: [$sel:ghcOptions:ComponentConfig] :: ComponentConfig -> [String]
+ Hix.Data.GhciConfig: [$sel:language:ComponentConfig] :: ComponentConfig -> String
+ Hix.Data.GhciConfig: [$sel:module_:PreludeConfig] :: PreludeConfig -> ModuleName
+ Hix.Data.GhciConfig: [$sel:name:PreludePackageName] :: PreludePackage -> Text
+ Hix.Data.GhciConfig: [$sel:package:PreludeConfig] :: PreludeConfig -> PreludePackage
+ Hix.Data.GhciConfig: [$sel:packages:PreprocConfig] :: PreprocConfig -> PackagesConfig
+ Hix.Data.GhciConfig: [$sel:prelude:ComponentConfig] :: ComponentConfig -> Maybe PreludeConfig
+ Hix.Data.GhciConfig: data PreludeConfig
+ Hix.Data.GhciConfig: data PreludePackage
+ Hix.Data.GhciConfig: data PreprocConfig
+ Hix.Data.GhciConfig: instance Data.Aeson.Types.FromJSON.FromJSON Hix.Data.GhciConfig.PreludeConfig
+ Hix.Data.GhciConfig: instance Data.Aeson.Types.FromJSON.FromJSON Hix.Data.GhciConfig.PreludePackage
+ Hix.Data.GhciConfig: instance Data.Aeson.Types.FromJSON.FromJSON Hix.Data.GhciConfig.PreprocConfig
+ Hix.Data.GhciConfig: instance GHC.Classes.Eq Hix.Data.GhciConfig.PreludeConfig
+ Hix.Data.GhciConfig: instance GHC.Classes.Eq Hix.Data.GhciConfig.PreludePackage
+ Hix.Data.GhciConfig: instance GHC.Classes.Eq Hix.Data.GhciConfig.PreprocConfig
+ Hix.Data.GhciConfig: instance GHC.Generics.Generic Hix.Data.GhciConfig.PreludeConfig
+ Hix.Data.GhciConfig: instance GHC.Generics.Generic Hix.Data.GhciConfig.PreludePackage
+ Hix.Data.GhciConfig: instance GHC.Generics.Generic Hix.Data.GhciConfig.PreprocConfig
+ Hix.Data.GhciConfig: instance GHC.Show.Show Hix.Data.GhciConfig.PreludeConfig
+ Hix.Data.GhciConfig: instance GHC.Show.Show Hix.Data.GhciConfig.PreludePackage
+ Hix.Data.GhciConfig: instance GHC.Show.Show Hix.Data.GhciConfig.PreprocConfig
+ Hix.Options: [$sel:config:PreprocOptions] :: PreprocOptions -> Maybe (Either PreprocConfig JsonConfig)
+ Hix.Preproc: CabalConfig :: [Builder] -> [Builder] -> Maybe Prelude -> CabalConfig
+ Hix.Preproc: [$sel:extensions:CabalConfig] :: CabalConfig -> [Builder]
+ Hix.Preproc: [$sel:ghcOptions:CabalConfig] :: CabalConfig -> [Builder]
+ Hix.Preproc: [$sel:prelude:CabalConfig] :: CabalConfig -> Maybe Prelude
+ Hix.Preproc: data CabalConfig
+ Hix.Preproc: fromCabal :: BuildInfo -> CabalConfig
+ Hix.Preproc: fromCabalFile :: Path Abs File -> M CabalConfig
+ Hix.Preproc: fromConfig :: Path Abs File -> Either PreprocConfig JsonConfig -> M CabalConfig
+ Hix.Preproc: fromPreludeConfig :: PreludeConfig -> Prelude
+ Hix.Preproc: instance GHC.Generics.Generic Hix.Preproc.CabalConfig
+ Hix.Preproc: instance GHC.Show.Show Hix.Preproc.CabalConfig
+ Hix.Preproc: preprocessWith :: PreprocOptions -> CabalConfig -> M ()
- Hix.Data.GhciConfig: ComponentConfig :: ComponentName -> SourceDirs -> Maybe EnvRunner -> ComponentConfig
+ Hix.Data.GhciConfig: ComponentConfig :: ComponentName -> SourceDirs -> Maybe EnvRunner -> [String] -> String -> [String] -> Maybe PreludeConfig -> ComponentConfig
- Hix.Options: PreprocOptions :: Path Abs File -> Path Abs File -> Path Abs File -> PreprocOptions
+ Hix.Options: PreprocOptions :: Maybe (Either PreprocConfig JsonConfig) -> Path Abs File -> Path Abs File -> Path Abs File -> PreprocOptions
- Hix.Preproc: extensionsPragma :: BuildInfo -> Maybe Builder
+ Hix.Preproc: extensionsPragma :: CabalConfig -> Maybe Builder
- Hix.Preproc: preprocess :: PreprocOptions -> ExceptT Error IO ()
+ Hix.Preproc: preprocess :: PreprocOptions -> M ()
- Hix.Preproc: preprocessModule :: Path Abs File -> BuildInfo -> DummyExportName -> ByteString -> Builder
+ Hix.Preproc: preprocessModule :: Path Abs File -> CabalConfig -> DummyExportName -> ByteString -> Builder
Files
- hix.cabal +5/−5
- lib/Hix.hs +2/−3
- lib/Hix/Cabal.hs +6/−0
- lib/Hix/Data/GhciConfig.hs +40/−2
- lib/Hix/Monad.hs +2/−2
- lib/Hix/Options.hs +10/−6
- lib/Hix/Preproc.hs +71/−24
- test/Hix/Test/CabalFile.hs +6/−0
- test/Hix/Test/GhciTest.hs +5/−1
- test/Hix/Test/PreprocTest.hs +5/−5
hix.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hix-version: 0.1.1.0+version: 0.2.0.0 synopsis: Haskell/Nix development build tools description: See https://hackage.haskell.org/package/hix/docs/Hix.html category: Build@@ -77,14 +77,14 @@ ghc-options: -Wall -Widentities -Wincomplete-uni-patterns -Wmissing-deriving-strategies -Wredundant-constraints -Wunused-type-patterns -Wunused-packages build-depends: Cabal- , aeson ==2.0.*+ , aeson >=2.0 && <2.2 , base ==4.* , exon ==1.4.* , extra ==1.7.* , filepattern ==0.1.* , generic-lens ==2.2.* , incipit-base ==0.5.*- , lens ==5.1.*+ , lens >=5.1 && <5.3 , lens-regex-pcre ==1.1.* , optparse-applicative ==0.17.* , path ==0.9.*@@ -198,13 +198,13 @@ Cabal , base ==4.* , exon ==1.4.*- , hedgehog ==1.1.*+ , hedgehog >=1.1 && <1.3 , hix , incipit-base ==0.5.* , path ==0.9.* , path-io ==1.7.* , tasty ==1.4.*- , tasty-hedgehog ==1.3.*+ , tasty-hedgehog >=1.3 && <1.5 , transformers mixins: base hiding (Prelude)
lib/Hix.hs view
@@ -1,9 +1,8 @@ module Hix where -import Control.Monad.Trans.Class (lift) import Path.IO (getCurrentDir) -import Hix.Data.Error (Error (..), printEnvError, printGhciError, printPreprocError, printFatalError)+import Hix.Data.Error (Error (..), printEnvError, printFatalError, printGhciError, printPreprocError) import Hix.Env (printEnvRunner) import Hix.Ghci (printGhciCmdline, printGhcidCmdline) import Hix.Monad (M, runM)@@ -31,7 +30,7 @@ runCommand :: Command -> M () runCommand = \case- Preproc opts -> lift (preprocess opts)+ Preproc opts -> preprocess opts EnvRunner opts -> printEnvRunner opts.options GhcidCmd opts -> printGhcidCmdline opts GhciCmd opts -> printGhciCmdline opts
lib/Hix/Cabal.hs view
@@ -1,8 +1,14 @@+{-# language CPP #-}+ module Hix.Cabal where import Control.Monad.Trans.Except (ExceptT (ExceptT), throwE) import Distribution.PackageDescription (BuildInfo (..), GenericPackageDescription (..))+#if MIN_VERSION_Cabal(3,8,0)+import Distribution.Simple.PackageDescription (readGenericPackageDescription)+#else import Distribution.PackageDescription.Parsec (readGenericPackageDescription)+#endif import Distribution.Types.Benchmark (benchmarkBuildInfo) import Distribution.Types.CondTree (CondTree (..)) import qualified Distribution.Types.Executable as Executable
lib/Hix/Data/GhciConfig.hs view
@@ -1,6 +1,6 @@ module Hix.Data.GhciConfig where -import Data.Aeson (FromJSON (parseJSON), FromJSONKey)+import Data.Aeson (FromJSON (parseJSON), FromJSONKey, withObject, (.:)) import GHC.Exts (IsList) import Path (Abs, Dir, File, Path, Rel) @@ -49,11 +49,42 @@ deriving stock (Eq, Show, Generic) deriving newtype (FromJSON) +data PreludePackage =+ PreludePackageName Text+ |+ PreludePackageSpec { name :: Text }+ deriving stock (Eq, Show, Generic)++instance FromJSON PreludePackage where+ parseJSON v =+ hpackStruct v <|> plainName+ where+ hpackStruct = withObject "PreludePackageSpec" \ o -> o .: "name"+ plainName = PreludePackageName <$> parseJSON v++data PreludeConfig =+ PreludeConfig {+ package :: PreludePackage,+ module_ :: ModuleName+ }+ deriving stock (Eq, Show, Generic)++instance FromJSON PreludeConfig where+ parseJSON =+ withObject "PreludeConfig" \ o -> do+ package <- o .: "package"+ module_ <- o .: "module"+ pure PreludeConfig {..}+ data ComponentConfig = ComponentConfig { name :: ComponentName, sourceDirs :: SourceDirs,- runner :: Maybe EnvRunner+ runner :: Maybe EnvRunner,+ extensions :: [String],+ language :: String,+ ghcOptions :: [String],+ prelude :: Maybe PreludeConfig } deriving stock (Eq, Show, Generic) deriving anyclass (FromJSON)@@ -111,6 +142,13 @@ setup :: Map RunnerName GhciSetupCode, run :: Map RunnerName GhciRunExpr, args :: GhciArgs+ }+ deriving stock (Eq, Show, Generic)+ deriving anyclass (FromJSON)++data PreprocConfig =+ PreprocConfig {+ packages :: PackagesConfig } deriving stock (Eq, Show, Generic) deriving anyclass (FromJSON)
lib/Hix/Monad.hs view
@@ -5,7 +5,7 @@ import Control.Monad.Trans.Reader (ReaderT (runReaderT)) import Path (Abs, Dir, Path) -import Hix.Data.Error (Error (GhciError), tryIO)+import Hix.Data.Error (Error (EnvError, GhciError), tryIO) data Env = Env {@@ -17,7 +17,7 @@ noteEnv :: Text -> Maybe a -> M a noteEnv err =- maybe (lift (throwE (GhciError err))) pure+ maybe (lift (throwE (EnvError err))) pure noteGhci :: Text -> Maybe a -> M a noteGhci err =
lib/Hix/Options.hs view
@@ -35,6 +35,7 @@ GhciConfig, ModuleName, PackageName (PackageName),+ PreprocConfig, RunnerName, SourceDir (SourceDir), )@@ -42,11 +43,12 @@ data PreprocOptions = PreprocOptions {+ config :: Maybe (Either PreprocConfig JsonConfig), source :: Path Abs File, inFile :: Path Abs File, outFile :: Path Abs File }- deriving stock (Eq, Show, Generic)+ deriving stock (Show, Generic) data PackageSpec = PackageSpec {@@ -136,10 +138,17 @@ fileParser longName helpText = option absFileOption (long longName <> completer (bashCompleter "file") <> help helpText) +jsonConfigParser ::+ Parser JsonConfig+jsonConfigParser =+ option jsonOption (long "config" <> short 'c' <> help "The Hix-generated config, file or text")+ preprocParser :: Parser PreprocOptions preprocParser = PreprocOptions <$>+ (fmap Right <$> optional jsonConfigParser)+ <*> fileParser "source" "The original source file" <*> fileParser "in" "The prepared input file"@@ -199,11 +208,6 @@ moduleParser :: Parser ModuleName moduleParser = strOption (long "module" <> short 'm' <> help "The module containing the test function" <> value "Main")--jsonConfigParser ::- Parser JsonConfig-jsonConfigParser =- option jsonOption (long "config" <> short 'c' <> help "The Hix-generated config, file or text") testOptionsParser :: Parser TestOptions testOptionsParser = do
lib/Hix/Preproc.hs view
@@ -2,6 +2,7 @@ import Control.Lens (IndexedTraversal', has, index, ix, preview, (%~), (.~), (^..)) import Control.Lens.Regex.ByteString (Match, group, groups, match, regex)+import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Except (ExceptT, throwE) import qualified Data.ByteString as ByteString import Data.ByteString (elemIndex)@@ -26,8 +27,14 @@ import System.Random (randomRIO) import Hix.Cabal (buildInfoForFile)+import Hix.Component (targetComponent) import Hix.Data.Error (Error (..), sourceError, tryIO)-import Hix.Options (PreprocOptions (..))+import qualified Hix.Data.GhciConfig+import Hix.Data.GhciConfig (PreludeConfig, PreludePackage (PreludePackageName, PreludePackageSpec), PreprocConfig)+import Hix.Json (jsonConfig)+import Hix.Monad (M)+import Hix.Options (PreprocOptions (..), TargetSpec (TargetForFile))+import Hix.Optparse (JsonConfig) type Regex = IndexedTraversal' Int ByteString Match @@ -38,6 +45,22 @@ } deriving stock (Show) +fromPreludeConfig :: PreludeConfig -> Prelude+fromPreludeConfig conf =+ Prelude (encodeUtf8 (name conf.package)) (encodeUtf8 conf.module_.unModuleName)+ where+ name = \case+ PreludePackageName n -> n+ PreludePackageSpec n -> n++data CabalConfig =+ CabalConfig {+ extensions :: [Builder],+ ghcOptions :: [Builder],+ prelude :: Maybe Prelude+ }+ deriving stock (Show, Generic)+ newtype DummyExportName = DummyExportName { unDummyExportName :: ByteString } deriving stock (Eq, Show, Generic)@@ -86,15 +109,10 @@ languagePragma exts = [exon|{-# language #{Exon.intercalate ", " exts} #-}|] -extensionsPragma :: BuildInfo -> Maybe Builder-extensionsPragma info- | null exts = Nothing- | otherwise = Just (languagePragma exts)- where- exts = maybeToList (dlExtension =<< info.defaultLanguage) ++ mapMaybe extension info.defaultExtensions- dlExtension = \case- UnknownLanguage _ -> Nothing- lang -> Just (stringUtf8 (show lang))+extensionsPragma :: CabalConfig -> Maybe Builder+extensionsPragma conf+ | null conf.extensions = Nothing+ | otherwise = Just (languagePragma conf.extensions) optionsPragma :: Builder -> Builder optionsPragma opts =@@ -440,24 +458,53 @@ preprocessModule :: Path Abs File ->- BuildInfo ->+ CabalConfig -> DummyExportName -> ByteString -> Builder-preprocessModule source info dummyExportName inLines =- assemble source header (extensionsPragma info) options dummyExportName+preprocessModule source conf dummyExportName inLines =+ assemble source header (extensionsPragma conf) options dummyExportName where- options = Exon.intercalate " " <$> nonEmpty (stringUtf8 <$> ghcOptions)- PerCompilerFlavor ghcOptions _ = info.options- customPrelude = findPrelude info.mixins- header = scanHeader customPrelude inLines+ options = Exon.intercalate " " <$> nonEmpty conf.ghcOptions+ header = scanHeader conf.prelude inLines --- TODO add common stanzas-preprocess :: PreprocOptions -> ExceptT Error IO ()-preprocess PreprocOptions {..} = do- info <- buildInfoForFile source- inLines <- tryIO (ByteString.readFile (toFilePath inFile))+preprocessWith :: PreprocOptions -> CabalConfig -> M ()+preprocessWith opt conf = do+ inLines <- lift (tryIO (ByteString.readFile (toFilePath opt.inFile))) dummyNumber :: Int <- randomRIO (10000, 10000000) let dummyExportName = DummyExportName [exon|Hix_Dummy_#{show dummyNumber}|]- let result = preprocessModule source info dummyExportName inLines- tryIO (ByteStringBuilder.writeFile (toFilePath outFile) result)+ let result = preprocessModule opt.source conf dummyExportName inLines+ lift (tryIO (ByteStringBuilder.writeFile (toFilePath opt.outFile) result))++fromConfig :: Path Abs File -> Either PreprocConfig JsonConfig -> M CabalConfig+fromConfig source pconf = do+ conf <- either pure jsonConfig pconf+ target <- targetComponent conf.packages (TargetForFile source)+ pure CabalConfig {+ extensions = stringUtf8 <$> target.component.language : target.component.extensions,+ ghcOptions = stringUtf8 <$> target.component.ghcOptions,+ prelude = fromPreludeConfig <$> target.component.prelude+ }++fromCabal :: BuildInfo -> CabalConfig+fromCabal info =+ CabalConfig {+ extensions = maybeToList (dlExtension =<< info.defaultLanguage) <> mapMaybe extension info.defaultExtensions,+ ghcOptions = stringUtf8 <$> ghcOptions,+ prelude = findPrelude info.mixins+ }+ where+ PerCompilerFlavor ghcOptions _ = info.options+ dlExtension = \case+ UnknownLanguage _ -> Nothing+ lang -> Just (stringUtf8 (show lang))++fromCabalFile :: Path Abs File -> M CabalConfig+fromCabalFile source =+ fromCabal <$> lift (buildInfoForFile source)++-- TODO add common stanzas+preprocess :: PreprocOptions -> M ()+preprocess opt = do+ conf <- maybe (fromCabalFile opt.source) (fromConfig opt.source) opt.config+ preprocessWith opt conf
test/Hix/Test/CabalFile.hs view
@@ -1,6 +1,12 @@+{-# language CPP #-}+ module Hix.Test.CabalFile where +#if MIN_VERSION_Cabal(3,8,0)+import Distribution.Simple.PackageDescription (parseString)+#else import Distribution.Fields.ParseResult (parseString)+#endif import Distribution.PackageDescription (GenericPackageDescription) import Distribution.PackageDescription.Parsec (parseGenericPackageDescription) import Distribution.Verbosity (silent)
test/Hix/Test/GhciTest.hs view
@@ -54,7 +54,11 @@ ComponentConfig { name, sourceDirs = SourceDirs [SourceDir dir],- runner = Just runner+ runner = Just runner,+ extensions = [],+ language = "GHC2021",+ ghcOptions = [],+ prelude = Nothing } packages :: PackagesConfig
test/Hix/Test/PreprocTest.hs view
@@ -11,7 +11,7 @@ import Hedgehog (TestT, evalMaybe, (===)) import Path (absfile) -import Hix.Preproc (preprocessModule)+import Hix.Preproc (fromCabal, preprocessModule) import Hix.Test.CabalFile (testPackage, testPackageNoPrelude) pragmas :: Text@@ -27,8 +27,8 @@ preprocTestNoPrelude module_ target = withFrozenCallStack do pkg <- liftIO testPackageNoPrelude- info <- evalMaybe (pkg.condLibrary <&> \ l -> l.condTreeData.libBuildInfo)- let result = toLazyByteString (preprocessModule [absfile|/foo/bar/Foo.hs|] info "Hix_Dummy" module_)+ conf <- evalMaybe (pkg.condLibrary <&> \ l -> fromCabal l.condTreeData.libBuildInfo)+ let result = toLazyByteString (preprocessModule [absfile|/foo/bar/Foo.hs|] conf "Hix_Dummy" module_) Text.lines target === Text.lines (decodeUtf8 result) preprocTest ::@@ -39,8 +39,8 @@ preprocTest module_ target = withFrozenCallStack do pkg <- liftIO testPackage- info <- evalMaybe (pkg.condLibrary <&> \ l -> l.condTreeData.libBuildInfo)- let result = toLazyByteString (preprocessModule [absfile|/foo/bar/Foo.hs|] info "Hix_Dummy" module_)+ conf <- evalMaybe (pkg.condLibrary <&> \ l -> fromCabal l.condTreeData.libBuildInfo)+ let result = toLazyByteString (preprocessModule [absfile|/foo/bar/Foo.hs|] conf "Hix_Dummy" module_) Text.lines target === Text.lines (decodeUtf8 result) moduleInsert :: ByteString