hix 0.6.2 → 0.6.7
raw patch · 10 files changed
+174/−60 lines, 10 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Hix.Bootstrap: nonEmptyAttrs :: Text -> [ExprAttr] -> ExprAttr
+ Hix.Bootstrap: notNil :: ExprAttr -> Bool
+ Hix.Data.GhciConfig: [$sel:mainPackage:EnvConfig] :: EnvConfig -> Maybe PackageName
+ Hix.Data.GhciConfig: [$sel:mainPackage:GhciConfig] :: GhciConfig -> Maybe PackageName
+ Hix.Data.GhciTest: [$sel:cmdline:GhciRun] :: GhciRun -> Text
+ Hix.Ghci: argFrag :: Text -> Text
+ Hix.Ghci: optArg :: Maybe Text -> Text
- Hix.Bootstrap: convertComponent :: ComponentType -> BuildInfo -> HixComponent
+ Hix.Bootstrap: convertComponent :: ComponentType -> BuildInfo -> [ExprAttr] -> HixComponent
- Hix.Component: packageDefault :: PackagesConfig -> ResolvedPackage
+ Hix.Component: packageDefault :: Maybe PackageName -> PackagesConfig -> ResolvedPackage
- Hix.Component: packageForSpecOrDefault :: Path Abs Dir -> PackagesConfig -> Maybe PackageSpec -> M ResolvedPackage
+ Hix.Component: packageForSpecOrDefault :: Path Abs Dir -> Maybe PackageName -> PackagesConfig -> Maybe PackageSpec -> M ResolvedPackage
- Hix.Component: targetComponent :: Maybe (Path Abs Dir) -> PackagesConfig -> TargetSpec -> M TargetOrDefault
+ Hix.Component: targetComponent :: Maybe (Path Abs Dir) -> Maybe PackageName -> PackagesConfig -> TargetSpec -> M TargetOrDefault
- Hix.Component: targetComponentIn :: Path Abs Dir -> PackagesConfig -> TargetSpec -> M TargetOrDefault
+ Hix.Component: targetComponentIn :: Path Abs Dir -> Maybe PackageName -> PackagesConfig -> TargetSpec -> M TargetOrDefault
- Hix.Component: targetComponentOrError :: Maybe (Path Abs Dir) -> PackagesConfig -> TargetSpec -> M Target
+ Hix.Component: targetComponentOrError :: Maybe (Path Abs Dir) -> Maybe PackageName -> PackagesConfig -> TargetSpec -> M Target
- Hix.Component: targetForComponent :: Path Abs Dir -> PackagesConfig -> ComponentCoords -> M TargetOrDefault
+ Hix.Component: targetForComponent :: Path Abs Dir -> Maybe PackageName -> PackagesConfig -> ComponentCoords -> M TargetOrDefault
- Hix.Data.GhciConfig: EnvConfig :: PackagesConfig -> EnvRunner -> EnvConfig
+ Hix.Data.GhciConfig: EnvConfig :: PackagesConfig -> EnvRunner -> Maybe PackageName -> EnvConfig
- Hix.Data.GhciConfig: GhciConfig :: PackagesConfig -> Map RunnerName GhciSetupCode -> Map RunnerName GhciRunExpr -> GhciArgs -> GhciConfig
+ Hix.Data.GhciConfig: GhciConfig :: PackagesConfig -> Maybe PackageName -> Map RunnerName GhciSetupCode -> Map RunnerName GhciRunExpr -> GhciArgs -> GhciConfig
- Hix.Data.GhciTest: GhciRun :: GhciTest -> Text -> Maybe Text -> Path Abs File -> GhciRun
+ Hix.Data.GhciTest: GhciRun :: GhciTest -> Text -> Maybe Text -> Path Abs File -> Text -> GhciRun
- Hix.Env: componentRunner :: Maybe (Path Abs Dir) -> PackagesConfig -> TargetSpec -> M (Maybe EnvRunner)
+ Hix.Env: componentRunner :: Maybe (Path Abs Dir) -> Maybe PackageName -> PackagesConfig -> TargetSpec -> M (Maybe EnvRunner)
Files
- hix.cabal +1/−1
- lib/Hix/Bootstrap.hs +41/−14
- lib/Hix/Component.hs +27/−12
- lib/Hix/Data/GhciConfig.hs +4/−2
- lib/Hix/Data/GhciTest.hs +2/−1
- lib/Hix/Env.hs +11/−4
- lib/Hix/Ghci.hs +15/−6
- lib/Hix/Preproc.hs +2/−2
- test/Hix/Test/BootstrapTest.hs +29/−15
- test/Hix/Test/GhciTest.hs +42/−3
hix.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hix-version: 0.6.2+version: 0.6.7 synopsis: Haskell/Nix development build tools description: See https://hackage.haskell.org/package/hix/docs/Hix.html category: Build
lib/Hix/Bootstrap.hs view
@@ -133,11 +133,11 @@ renderExpr :: Int -> Expr -> NonEmpty Text renderExpr ind = \case- ExprString s -> indent ind [[exon|"#{s}"|]]+ ExprString s -> indent ind [[exon|"#{Text.replace "\"" "\\\"" s}"|]] ExprLit e -> [e] ExprList l -> "[" :| (indent (ind + 2) (toList . renderExpr ind =<< l)) ++ ["]"] ExprAttrs a -> case renderAttrs ind a of- [] -> ["{};"]+ [] -> ["{}"] as -> "{" :| indent (ind + 2) as ++ ["}"] ExprPrefix p (renderExpr ind -> h :| t) -> [exon|#{p} #{h}|] :| t@@ -235,6 +235,17 @@ mkAttrs a e = (fmap ($ e) a) +notNil :: ExprAttr -> Bool+notNil = \case+ ExprAttrNil -> False+ _ -> True++nonEmptyAttrs :: Text -> [ExprAttr] -> ExprAttr+nonEmptyAttrs key =+ filter notNil >>> \case+ [] -> ExprAttrNil+ as -> ExprAttr key (ExprAttrs as)+ -- TODO extract version and put it in a file knownPackageKeys :: PackageDescription -> [ExprAttr] knownPackageKeys =@@ -243,7 +254,8 @@ single "build-type" buildType, single "copyright" (.copyright), single "license" license,- singleOpt "license-file" (head . licenseFiles)+ singleOpt "license-file" (head . licenseFiles),+ single "version" (.package.pkgVersion) ] metaPackageKeys :: PackageDescription -> [ExprAttr]@@ -274,14 +286,22 @@ multi "default-extensions" (.defaultExtensions), multiOrSingle "source-dirs" (.hsSourceDirs), singleOpt "language" (.defaultLanguage),- multi "ghc-options" (filter notDefaultGhcOption . ghcFlavour . (.options))+ multi "ghc-options" (filter notDefaultGhcOption . ghcFlavour . (.options)),+ misc ] info++ misc e =+ nonEmptyAttrs "component" (mkAttrs [+ multi "other-modules" (.otherModules)+ ] e)+ (preludeWithVersion, deps) | Just p <- prelude = let (v, res) = foldl (amendPrelude p) (Nothing, []) info.targetBuildDepends in (Just (PreludeWithVersion p v), res) | otherwise =- (Nothing, filter notBase (info.targetBuildDepends))+ (Nothing, filter notBase info.targetBuildDepends)+ amendPrelude p (Nothing, ds) dep@(Dependency (Cabal.unPackageName -> dname) _ _) | dname == p.preludePackage = (Just dep, ds) amendPrelude _ (v, ds) d = (v, d : ds)@@ -291,28 +311,32 @@ Cabal.Dependency "base" _ _ -> False _ -> True -convertComponent :: ComponentType -> BuildInfo -> HixComponent-convertComponent special info =- HixComponent {..}+convertComponent :: ComponentType -> BuildInfo -> [ExprAttr] -> HixComponent+convertComponent special info extra =+ HixComponent {known = knownCommon <> extra, ..} where- (prelude, known) = knownComponentKeys preludeBasic info+ (prelude, knownCommon) = knownComponentKeys preludeBasic info preludeBasic = findPrelude info.mixins convertLibrary :: Cabal.Library -> HixComponent convertLibrary lib =- convertComponent Library lib.libBuildInfo+ convertComponent Library lib.libBuildInfo extra+ where+ extra = mkAttrs [+ multi "reexported-modules" (.reexportedModules)+ ] lib convertExecutable :: UnqualComponentName -> Cabal.Executable -> HixComponent convertExecutable name exe =- convertComponent (Executable (toText (unUnqualComponentName name))) exe.buildInfo+ convertComponent (Executable (toText (unUnqualComponentName name))) exe.buildInfo [] convertTestsuite :: UnqualComponentName -> Cabal.TestSuite -> HixComponent convertTestsuite name test =- convertComponent (Test (toText (unUnqualComponentName name))) test.testBuildInfo+ convertComponent (Test (toText (unUnqualComponentName name))) test.testBuildInfo [] convertBenchmark :: UnqualComponentName -> Cabal.Benchmark -> HixComponent convertBenchmark name bench =- convertComponent (Benchmark (toText (unUnqualComponentName name))) bench.benchmarkBuildInfo+ convertComponent (Benchmark (toText (unUnqualComponentName name))) bench.benchmarkBuildInfo [] convert :: CabalInfo -> HixPackage convert cinfo =@@ -340,7 +364,7 @@ renderComponent HixComponent {..} = ExprAttr key cabalConfig where- cabalConfig = ExprAttrs (known <> foldMap preludeAttrs prelude)+ cabalConfig = ExprAttrs (enable <> foldMap preludeAttrs prelude <> known) preludeAttrs p = [ExprAttr "prelude" (ExprAttrs [ ExprAttr "package" (preludePackageAttrs p),@@ -358,6 +382,9 @@ Executable name -> [exon|executables.#{name}|] Test name -> [exon|tests.#{name}|] Benchmark name -> [exon|benchmarks.#{name}|]+ enable = case special of+ Library -> [ExprAttr "enable" (ExprLit "true")]+ _ -> [] flakePackage :: HixPackage -> ExprAttr flakePackage pkg =
lib/Hix/Component.hs view
@@ -50,9 +50,19 @@ packageByDir config dir = noteEnv [exon|No package at this directory: #{pathText dir}|] (tryPackageByDir config dir) -packageDefault :: PackagesConfig -> ResolvedPackage-packageDefault = \case+packageDefault :: Maybe PackageName -> PackagesConfig -> ResolvedPackage+packageDefault mainPkg = \case+ [] -> NoPackage "Project has no packages." [(_, pkg)] -> ResolvedPackage False pkg+ pkgs | Just name <- mainPkg ->+ case Map.lookup name pkgs of+ Just pkg ->+ ResolvedPackage False pkg+ Nothing ->+ NoPackage (+ [exon|Project has multiple packages and the main package '##{name}' is not among them. |] <>+ "Specify -p or -f to choose one explicitly."+ ) _ -> NoPackage "Project has more than one package, specify -p or -f." packageForSpec ::@@ -75,12 +85,13 @@ packageForSpecOrDefault :: Path Abs Dir ->+ Maybe PackageName -> PackagesConfig -> Maybe PackageSpec -> M ResolvedPackage-packageForSpecOrDefault root config = \case+packageForSpecOrDefault root mainPkg config = \case Just pkg -> ResolvedPackage True <$> packageForSpec root config pkg- Nothing -> pure (packageDefault config)+ Nothing -> pure (packageDefault mainPkg config) matchComponent :: ComponentConfig -> ComponentSpec -> Bool matchComponent candidate (ComponentSpec name dir) =@@ -126,11 +137,12 @@ targetForComponent :: Path Abs Dir ->+ Maybe PackageName -> PackagesConfig -> ComponentCoords -> M TargetOrDefault-targetForComponent root config spec = do- package <- packageForSpecOrDefault root config spec.package+targetForComponent root mainPkg config spec = do+ package <- packageForSpecOrDefault root mainPkg config spec.package targetInPackage package spec.component targetForFile ::@@ -156,31 +168,34 @@ targetComponentIn :: Path Abs Dir ->+ Maybe PackageName -> PackagesConfig -> TargetSpec -> M TargetOrDefault-targetComponentIn root config = \case+targetComponentIn root mainPkg config = \case TargetForComponent spec ->- targetForComponent root config spec+ targetForComponent root mainPkg config spec TargetForFile spec -> ExplicitTarget <$> targetForFile root config spec targetComponent :: Maybe (Path Abs Dir) ->+ Maybe PackageName -> PackagesConfig -> TargetSpec -> M TargetOrDefault-targetComponent cliRoot config spec = do+targetComponent cliRoot mainPkg config spec = do root <- rootDir cliRoot- targetComponentIn root config spec+ targetComponentIn root mainPkg config spec targetComponentOrError :: Maybe (Path Abs Dir) ->+ Maybe PackageName -> PackagesConfig -> TargetSpec -> M Target-targetComponentOrError cliRoot config spec =- targetComponent cliRoot config spec >>= \case+targetComponentOrError cliRoot mainPkg config spec =+ targetComponent cliRoot mainPkg config spec >>= \case ExplicitTarget t -> pure t DefaultTarget t -> pure t NoDefaultTarget err -> throwM (EnvError err)
lib/Hix/Data/GhciConfig.hs view
@@ -3,7 +3,7 @@ import Data.Aeson (FromJSON, FromJSONKey) import GHC.Exts (IsList) -import Hix.Data.ComponentConfig (EnvRunner, PackagesConfig)+import Hix.Data.ComponentConfig (EnvRunner, PackageName, PackagesConfig) newtype RunnerName = RunnerName { unRunnerName :: Text }@@ -32,7 +32,8 @@ data EnvConfig = EnvConfig { packages :: PackagesConfig,- defaultEnv :: EnvRunner+ defaultEnv :: EnvRunner,+ mainPackage :: Maybe PackageName } deriving stock (Eq, Show, Generic) deriving anyclass (FromJSON)@@ -40,6 +41,7 @@ data GhciConfig = GhciConfig { packages :: PackagesConfig,+ mainPackage :: Maybe PackageName, setup :: Map RunnerName GhciSetupCode, run :: Map RunnerName GhciRunExpr, args :: GhciArgs
lib/Hix/Data/GhciTest.hs view
@@ -18,7 +18,8 @@ test :: GhciTest, shell :: Text, run :: Maybe Text,- scriptFile :: Path Abs File+ scriptFile :: Path Abs File,+ cmdline :: Text } deriving stock (Eq, Show, Generic)
lib/Hix/Env.hs view
@@ -5,7 +5,12 @@ import Hix.Component (targetComponent) import qualified Hix.Data.ComponentConfig-import Hix.Data.ComponentConfig (EnvRunner (EnvRunner), PackagesConfig, TargetOrDefault (DefaultTarget, ExplicitTarget))+import Hix.Data.ComponentConfig (+ EnvRunner (EnvRunner),+ PackageName,+ PackagesConfig,+ TargetOrDefault (DefaultTarget, ExplicitTarget),+ ) import Hix.Data.Error (pathText) import qualified Hix.Data.GhciConfig import Hix.Json (jsonConfig)@@ -17,11 +22,12 @@ -- Nothing when the config requests it componentRunner :: Maybe (Path Abs Dir) ->+ Maybe PackageName -> PackagesConfig -> TargetSpec -> M (Maybe EnvRunner)-componentRunner cliRoot config spec =- targetComponent cliRoot config spec <&> \case+componentRunner cliRoot defaultPkg config spec =+ targetComponent cliRoot defaultPkg config spec <&> \case ExplicitTarget t -> t.component.runner DefaultTarget t -> t.component.runner _ -> Nothing@@ -29,7 +35,8 @@ envRunner :: EnvRunnerOptions -> M EnvRunner envRunner opts = do config <- either pure jsonConfig opts.config- fromMaybe config.defaultEnv . join <$> traverse (componentRunner opts.root config.packages) opts.component+ let runner = componentRunner opts.root config.mainPackage config.packages+ fromMaybe config.defaultEnv . join <$> traverse runner opts.component printEnvRunner :: EnvRunnerOptions -> M () printEnvRunner opts = do
lib/Hix/Ghci.hs view
@@ -32,7 +32,7 @@ import Hix.Monad (M, noteGhci) import qualified Hix.Options as Options import Hix.Options (- ExtraGhciOptions,+ ExtraGhciOptions (ExtraGhciOptions), ExtraGhcidOptions (ExtraGhcidOptions), GhciOptions (GhciOptions), GhcidOptions,@@ -110,7 +110,7 @@ assemble opt = do config <- either pure jsonConfig opt.config root <- rootDir opt.root- Target {..} <- targetComponentOrError opt.root config.packages opt.component+ Target {..} <- targetComponentOrError opt.root config.mainPackage config.packages opt.component script <- ghciScript config package sourceDir opt pure GhciTest { script,@@ -139,9 +139,16 @@ hClose handle pure path +argFrag :: Text -> Text+argFrag "" = ""+argFrag s = [exon| #{s}|]++optArg :: Maybe Text -> Text+optArg = foldMap argFrag+ searchPathArg :: NonEmpty (Path Abs Dir) -> Text searchPathArg paths =- [exon| -i#{colonSeparated}|]+ [exon|-i#{colonSeparated}|] where colonSeparated = Text.intercalate ":" (pathText <$> toList paths) @@ -154,10 +161,12 @@ ghciCmdline test extra scriptFile runScriptFile = GhciRun {..} where- shell = [exon|##{Text.unwords (coerce test.args)}#{sp} -ghci-script=##{toFilePath scriptFile}#{extraOpts}|]+ cmdline = [exon|ghci#{shell}#{optArg run}|]+ shell = [exon|#{argFrag args}#{argFrag sp} -ghci-script=##{toFilePath scriptFile}#{argFrag extraOpts}|]+ args = Text.unwords (coerce test.args) run = runScriptFile <&> \ f -> [exon|-ghci-script=##{toFilePath f}|] sp = foldMap searchPathArg (nonEmpty test.searchPath)- extraOpts | Just o <- extra = [exon| ##{o}|]+ extraOpts | Just (ExtraGhciOptions o) <- extra = o | otherwise = "" ghciCmdlineFromOptions ::@@ -178,7 +187,7 @@ ghci <- ghciCmdlineFromOptions tmp opt.ghci let test = fromMaybe "main" ghci.test.test- pure (GhcidRun [exon|ghcid --command="ghci #{ghci.shell}" --test='##{test}'#{foldMap extra opt.extra}|] ghci)+ pure (GhcidRun [exon|ghcid --command="ghci#{ghci.shell}" --test='##{test}'#{foldMap extra opt.extra}|] ghci) where extra (ExtraGhcidOptions o) = [exon| ##{o}|]
lib/Hix/Preproc.hs view
@@ -9,6 +9,7 @@ import qualified Data.ByteString.Builder as ByteStringBuilder import Data.ByteString.Builder (Builder, byteString, charUtf8, stringUtf8) import Data.Generics.Labels ()+import qualified Data.Map.Strict as Map import Distribution.PackageDescription (BuildInfo (..)) import Distribution.Simple (PerCompilerFlavor (PerCompilerFlavor)) import qualified Exon@@ -34,7 +35,6 @@ import Hix.Optparse (JsonConfig) import qualified Hix.Prelude as Prelude import Hix.Prelude (Prelude (Prelude), findPrelude)-import qualified Data.Map.Strict as Map type Regex = IndexedTraversal' Int ByteString Match @@ -461,7 +461,7 @@ M CabalConfig fromConfig cliRoot source pconf = do conf <- either pure jsonConfig pconf- target <- targetComponentOrError cliRoot conf.packages (TargetForFile source)+ target <- targetComponentOrError cliRoot Nothing conf.packages (TargetForFile source) pure CabalConfig { extensions = stringUtf8 <$> target.component.language : target.component.extensions, ghcOptions = stringUtf8 <$> target.component.ghcOptions,
test/Hix/Test/BootstrapTest.hs view
@@ -19,7 +19,7 @@ name: red-panda version: 0.1.0.0-synopsis: A Haskell project+synopsis: A Haskell "project" description: See https://hackage.haskell.org/package/red-panda/docs/RedPanda.html author: Panda maintainer: Panda@@ -31,6 +31,7 @@ exposed-modules: RedPanda other-modules:+ NormalPanda Paths_red_panda autogen-modules: Paths_red_panda@@ -49,13 +50,12 @@ base hiding (Prelude) , incipit-base (IncipitBase as Prelude) , incipit-base hiding (IncipitBase)+ reexported-modules:+ Control.Monad+ , Data.Maybe executable red-panda main-is: Main.hs- other-modules:- Paths_red_panda- autogen-modules:- Paths_red_panda hs-source-dirs: app ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall@@ -69,9 +69,6 @@ main-is: Main.hs other-modules: RedPanda.Test.NameTest- Paths_red_panda- autogen-modules:- Paths_red_panda hs-source-dirs: test ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall@@ -103,12 +100,21 @@ build-type = "Simple"; license = "BSD-2-Clause-Patent"; license-file = "LICENSE";+ version = "0.1.0.0"; meta = { maintainer = "Panda";- synopsis = "A Haskell project";+ synopsis = "A Haskell \"project\""; }; }; library = {+ enable = true;+ prelude = {+ package = {+ name = "incipit-base";+ version = ">=0.4 && <0.6";+ };+ module = "IncipitBase";+ }; dependencies = [ "containers" "base >=4 && <5"@@ -122,13 +128,16 @@ ghc-options = [ "-Wall" ];- prelude = {- package = {- name = "incipit-base";- version = ">=0.4 && <0.6";- };- module = "IncipitBase";+ component = {+ other-modules = [+ "NormalPanda"+ "Paths_red_panda"+ ]; };+ reexported-modules = [+ "Control.Monad"+ "Data.Maybe"+ ]; }; executables.red-panda = { dependencies = [@@ -152,6 +161,11 @@ ghc-options = [ "-Wall" ];+ component = {+ other-modules = [+ "RedPanda.Test.NameTest"+ ];+ }; }; }; };
test/Hix/Test/GhciTest.hs view
@@ -19,7 +19,7 @@ import Hix.Data.GhciConfig (ChangeDir (ChangeDir), EnvConfig (EnvConfig), GhciConfig (..)) import qualified Hix.Data.GhciTest as GhciTest import Hix.Env (envRunner)-import Hix.Ghci (assemble, ghcidCmdlineFromOptions)+import Hix.Ghci (assemble, ghciCmdlineFromOptions, ghcidCmdlineFromOptions) import Hix.Monad (runM) import qualified Hix.Options as Options import Hix.Options (@@ -95,8 +95,9 @@ GhciOptions { config = Left GhciConfig { packages,+ mainPackage = Nothing, setup = [("generic", "import Test.Tasty")],- run = [("generic", ("check . property . test"))],+ run = [("generic", "check . property . test")], args = ["-Werror"] }, root = Nothing,@@ -132,6 +133,44 @@ cmdline <- evalEither res ghcidTarget root cmdline.ghci.scriptFile === cmdline.cmdline +mainOptions :: GhciOptions+mainOptions =+ GhciOptions {+ config = Left GhciConfig {+ packages,+ mainPackage = Just "core",+ setup = [("generic", "import Test.Tasty")],+ run = [("generic", "")],+ args = []+ },+ root = Nothing,+ component = TargetForComponent (ComponentCoords Nothing Nothing),+ test = TestOptions {+ mod = "Main",+ test = Nothing,+ runner = Nothing,+ cd = ChangeDir True+ },+ extra = Nothing+ }++mainPackageTarget ::+ Path Abs Dir ->+ Path Abs File ->+ Text+mainPackageTarget cwd scriptFile =+ [exon|ghci -i#{path} -ghci-script=#{pathText scriptFile}|]+ where+ path = [exon|#{dir}packages/core/test/:#{dir}packages/api/lib/:#{dir}packages/core/lib/|]+ dir = pathText cwd++test_mainPackage :: TestT IO ()+test_mainPackage = do+ res <- lift $ withSystemTempDir "hix-test" \ tmp ->+ runM root (ghciCmdlineFromOptions tmp mainOptions)+ cmdline <- evalEither res+ mainPackageTarget root cmdline.scriptFile === cmdline.cmdline+ spec2 :: TargetSpec spec2 = TargetForFile (root </> [relfile|packages/core/test/Main.hs|])@@ -148,7 +187,7 @@ res <- evalEither =<< liftIO (runM root (envRunner conf)) target === res where- conf = EnvRunnerOptions (Left (EnvConfig packages defaultRunner)) Nothing (Just spec)+ conf = EnvRunnerOptions (Left (EnvConfig packages defaultRunner Nothing)) Nothing (Just spec) test_componentEnv :: TestT IO () test_componentEnv = do