hix 0.7.0 → 0.7.1
raw patch · 26 files changed
+494/−103 lines, 26 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Hix.Managed.Cabal.Repo: indexOutdated :: Path Abs File -> IO Bool
- Hix.Managed.Cabal.Repo: matchIndexState :: Verbosity -> RepoContext -> Repo -> HackageIndexState -> M (Maybe IndexProblem)
+ Hix.Data.VersionBounds: inclusiveRange :: VersionBounds -> VersionRange
+ Hix.Data.VersionBounds: maybeInclusiveRange :: VersionBounds -> Maybe VersionRange
+ Hix.Managed.Cabal.Print: resolverPackageId :: ResolverPackage a -> PackageId
+ Hix.Managed.Cabal.Repo: IndexCorrupt :: Timestamp -> IndexProblem
+ Hix.Managed.Cabal.Repo: IndexMatch :: HackageIndexState -> ValidIndex
+ Hix.Managed.Cabal.Repo: IndexRecent :: NominalDiffTime -> ValidIndex
+ Hix.Managed.Cabal.Repo: currentIndexState :: Verbosity -> RepoContext -> Repo -> M (Maybe HackageIndexState)
+ Hix.Managed.Cabal.Repo: data ValidIndex
+ Hix.Managed.Cabal.Repo: instance GHC.Classes.Eq Hix.Managed.Cabal.Repo.ValidIndex
+ Hix.Managed.Cabal.Repo: instance GHC.Generics.Generic Hix.Managed.Cabal.Repo.ValidIndex
+ Hix.Managed.Cabal.Repo: instance GHC.Show.Show Hix.Managed.Cabal.Repo.ValidIndex
+ Hix.Managed.Cabal.Repo: logValid :: ValidIndex -> M ()
+ Hix.Managed.Cabal.Repo: maxIndexAge :: NominalDiffTime
+ Hix.Managed.Cabal.Repo: maxIndexAgeDays :: Int
+ Hix.Managed.Cabal.Sort: sortDeps :: forall a. SolveResources -> (a -> PackageName) -> [a] -> M [a]
+ Hix.Managed.Cabal.Sort: sortMutations :: forall a. SolveResources -> [DepMutation a] -> M [DepMutation a]
+ Hix.Managed.Data.BuildConfig: [$sel:timeout:BuildConfig] :: BuildConfig -> Maybe BuildTimeout
+ Hix.Managed.Data.BuildConfig: [$sel:toposortMutations:BuildConfig] :: BuildConfig -> Bool
+ Hix.Managed.Data.StageState: Finished :: BuildStatus -> BuildResult
+ Hix.Managed.Data.StageState: TimedOut :: BuildResult
+ Hix.Managed.Data.StageState: buildUnsuccessful :: BuildResult -> Bool
+ Hix.Managed.Data.StageState: data BuildResult
+ Hix.Managed.Data.StageState: instance GHC.Classes.Eq Hix.Managed.Data.StageState.BuildResult
+ Hix.Managed.Data.StageState: instance GHC.Generics.Generic Hix.Managed.Data.StageState.BuildResult
+ Hix.Managed.Data.StageState: instance GHC.Show.Show Hix.Managed.Data.StageState.BuildResult
+ Hix.Managed.Data.Targets: firstMTargets :: Monad m => a -> (a -> Bool) -> (LocalPackage -> m a) -> Targets -> m a
+ Hix.Managed.Handlers.Build: BuildTimeout :: Int -> BuildTimeout
+ Hix.Managed.Handlers.Build: instance Data.Aeson.Types.FromJSON.FromJSON Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Classes.Eq Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Classes.Ord Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Enum.Enum Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Generics.Generic Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Num.Num Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Real.Integral Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Real.Real Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: instance GHC.Show.Show Hix.Managed.Handlers.Build.BuildTimeout
+ Hix.Managed.Handlers.Build: newtype BuildTimeout
+ Hix.Managed.Handlers.Build.Prod: [$sel:buildTimeout:BuilderResources] :: BuilderResources -> Maybe BuildTimeout
+ Hix.Managed.Handlers.Cabal: [$sel:sortMutations:CabalHandlers] :: CabalHandlers -> forall a. [DepMutation a] -> M [DepMutation a]
- Hix.Managed.Build: logBuildResult :: Text -> BuildStatus -> M ()
+ Hix.Managed.Build: logBuildResult :: Text -> BuildResult -> M ()
- Hix.Managed.Cabal.Repo: IndexOutdated :: IndexProblem
+ Hix.Managed.Cabal.Repo: IndexOutdated :: NominalDiffTime -> IndexProblem
- Hix.Managed.Cabal.Repo: indexProblem :: SolveConfig -> RepoContext -> Repo -> Path Abs File -> M (Maybe IndexProblem)
+ Hix.Managed.Cabal.Repo: indexProblem :: SolveConfig -> RepoContext -> Repo -> Path Abs File -> M (Either IndexProblem ValidIndex)
- Hix.Managed.Data.BuildConfig: BuildConfig :: Natural -> Natural -> Natural -> Bool -> Bool -> Bool -> BuildConfig
+ Hix.Managed.Data.BuildConfig: BuildConfig :: Natural -> Natural -> Natural -> Bool -> Bool -> Bool -> Bool -> Maybe BuildTimeout -> BuildConfig
- Hix.Managed.Data.StageState: buildStatus :: Bool -> BuildStatus
+ Hix.Managed.Data.StageState: buildStatus :: BuildResult -> BuildStatus
- Hix.Managed.Handlers.Build: EnvBuilder :: CabalHandlers -> (Versions -> [PackageId] -> M (Overrides, BuildStatus)) -> EnvBuilder
+ Hix.Managed.Handlers.Build: EnvBuilder :: CabalHandlers -> (Versions -> [PackageId] -> M (Overrides, BuildResult)) -> EnvBuilder
- Hix.Managed.Handlers.Build: [$sel:buildWithState:EnvBuilder] :: EnvBuilder -> Versions -> [PackageId] -> M (Overrides, BuildStatus)
+ Hix.Managed.Handlers.Build: [$sel:buildWithState:EnvBuilder] :: EnvBuilder -> Versions -> [PackageId] -> M (Overrides, BuildResult)
- Hix.Managed.Handlers.Build: testBuilder :: (Versions -> [PackageId] -> M (Overrides, BuildStatus)) -> (Builder -> M a) -> M a
+ Hix.Managed.Handlers.Build: testBuilder :: (Versions -> [PackageId] -> M (Overrides, BuildResult)) -> (Builder -> M a) -> M a
- Hix.Managed.Handlers.Build: versionsBuilder :: HackageHandlers -> (Versions -> M BuildStatus) -> (Builder -> M a) -> M a
+ Hix.Managed.Handlers.Build: versionsBuilder :: HackageHandlers -> (Versions -> M BuildResult) -> (Builder -> M a) -> M a
- Hix.Managed.Handlers.Build.Prod: BuilderResources :: HackageHandlers -> StateFileHandlers -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Path Abs Dir -> BuilderResources
+ Hix.Managed.Handlers.Build.Prod: BuilderResources :: HackageHandlers -> StateFileHandlers -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Path Abs Dir -> Maybe BuildTimeout -> BuilderResources
- Hix.Managed.Handlers.Build.Prod: buildPackage :: Path Abs Dir -> EnvName -> LocalPackage -> M Bool
+ Hix.Managed.Handlers.Build.Prod: buildPackage :: Maybe BuildTimeout -> Path Abs Dir -> EnvName -> LocalPackage -> M BuildResult
- Hix.Managed.Handlers.Build.Prod: buildWithState :: EnvBuilderResources -> Versions -> [PackageId] -> M (Overrides, BuildStatus)
+ Hix.Managed.Handlers.Build.Prod: buildWithState :: EnvBuilderResources -> Versions -> [PackageId] -> M (Overrides, BuildResult)
- Hix.Managed.Handlers.Build.Prod: handlersProd :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> CabalConfig -> Bool -> m BuildHandlers
+ Hix.Managed.Handlers.Build.Prod: handlersProd :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Maybe BuildTimeout -> CabalConfig -> Bool -> m BuildHandlers
- Hix.Managed.Handlers.Build.Prod: withBuilder :: HackageHandlers -> StateFileHandlers -> StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> (Builder -> M a) -> M a
+ Hix.Managed.Handlers.Build.Prod: withBuilder :: HackageHandlers -> StateFileHandlers -> StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Maybe BuildTimeout -> (Builder -> M a) -> M a
- Hix.Managed.Handlers.Build.Test: chooseHandlers :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> CabalConfig -> Maybe SpecialBuildHandlers -> m BuildHandlers
+ Hix.Managed.Handlers.Build.Test: chooseHandlers :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Maybe BuildTimeout -> CabalConfig -> Maybe SpecialBuildHandlers -> m BuildHandlers
- Hix.Managed.Handlers.Build.Test: handlersBumpTest :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> CabalConfig -> Bool -> m BuildHandlers
+ Hix.Managed.Handlers.Build.Test: handlersBumpTest :: MonadIO m => StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix -> Maybe BuildTimeout -> CabalConfig -> Bool -> m BuildHandlers
- Hix.Managed.Handlers.Build.Test: handlersUnitTest :: MonadIO m => GhcPackages -> (Versions -> M BuildStatus) -> m (BuildHandlers, IORef [Expr], IORef [FailedMutation])
+ Hix.Managed.Handlers.Build.Test: handlersUnitTest :: MonadIO m => GhcPackages -> (Versions -> M BuildResult) -> m (BuildHandlers, IORef [Expr], IORef [FailedMutation])
- Hix.Managed.Handlers.Cabal: CabalHandlers :: (SolverState -> M (Maybe SolverPlan)) -> (PackageName -> Maybe Version) -> CabalHandlers
+ Hix.Managed.Handlers.Cabal: CabalHandlers :: (SolverState -> M (Maybe SolverPlan)) -> (PackageName -> Maybe Version) -> (forall a. [DepMutation a] -> M [DepMutation a]) -> CabalHandlers
Files
- hix.cabal +4/−1
- lib/Hix/Data/VersionBounds.hs +10/−0
- lib/Hix/Managed/Build.hs +16/−8
- lib/Hix/Managed/Bump/App.hs +4/−1
- lib/Hix/Managed/Cabal/Print.hs +15/−5
- lib/Hix/Managed/Cabal/Repo.hs +70/−28
- lib/Hix/Managed/Cabal/Sort.hs +45/−0
- lib/Hix/Managed/Data/BuildConfig.hs +8/−2
- lib/Hix/Managed/Data/Constraints.hs +2/−2
- lib/Hix/Managed/Data/Query.hs +4/−0
- lib/Hix/Managed/Data/StageState.hs +15/−3
- lib/Hix/Managed/Data/Targets.hs +17/−0
- lib/Hix/Managed/Handlers/Build.hs +10/−5
- lib/Hix/Managed/Handlers/Build/Prod.hs +31/−15
- lib/Hix/Managed/Handlers/Build/Test.hs +10/−7
- lib/Hix/Managed/Handlers/Cabal.hs +5/−2
- lib/Hix/Managed/Handlers/Cabal/Prod.hs +4/−2
- lib/Hix/Managed/Lower/App.hs +3/−1
- lib/Hix/Managed/Lower/Stabilize.hs +3/−4
- lib/Hix/Options.hs +4/−0
- test/Hix/Test/Managed/LowerInit/MutationTest.hs +2/−2
- test/Hix/Test/Managed/LowerNativeTest.hs +1/−1
- test/Hix/Test/Managed/LowerOptimize/OrderTest.hs +133/−0
- test/Hix/Test/Managed/Run.hs +29/−13
- test/Hix/Test/Managed/SolveTest.hs +46/−0
- test/Hix/Test/ManagedTest.hs +3/−1
hix.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hix-version: 0.7.0+version: 0.7.1 synopsis: Haskell/Nix development build tools description: See https://hackage.haskell.org/package/hix/docs/Hix.html category: Build@@ -90,6 +90,7 @@ Hix.Managed.Cabal.Repo Hix.Managed.Cabal.Resources Hix.Managed.Cabal.Solve+ Hix.Managed.Cabal.Sort Hix.Managed.Cabal.Targets Hix.Managed.Constraints Hix.Managed.Data.BuildConfig@@ -337,9 +338,11 @@ Hix.Test.Managed.LowerNativeTest Hix.Test.Managed.LowerOptimize.CandidatesTest Hix.Test.Managed.LowerOptimize.MutationTest+ Hix.Test.Managed.LowerOptimize.OrderTest Hix.Test.Managed.LowerStabilize.MutationTest Hix.Test.Managed.ProjectContextProtoTest Hix.Test.Managed.Run+ Hix.Test.Managed.SolveTest Hix.Test.Managed.UnsafeIsString Hix.Test.ManagedTest Hix.Test.NewTest
lib/Hix/Data/VersionBounds.hs view
@@ -8,6 +8,7 @@ VersionRange, earlierVersion, intersectVersionRanges,+ orEarlierVersion, orLaterVersion, simplifyVersionRange, thisVersion,@@ -117,6 +118,15 @@ instance Pretty VersionBounds where pretty = pretty . majorRange++maybeInclusiveRange :: VersionBounds -> Maybe VersionRange+maybeInclusiveRange =+ maybeRange \case+ BoundLower -> orLaterVersion+ BoundUpper -> orEarlierVersion++inclusiveRange :: VersionBounds -> VersionRange+inclusiveRange = fromMaybe range0 . maybeInclusiveRange anyBounds :: VersionBounds anyBounds =
lib/Hix/Managed/Build.hs view
@@ -33,8 +33,10 @@ import Hix.Managed.Data.StageContext (StageContext (StageContext)) import qualified Hix.Managed.Data.StageState import Hix.Managed.Data.StageState (+ BuildResult (Finished, TimedOut), BuildStatus (Failure, Success), StageState,+ buildStatus, failed, initStageState, iterations,@@ -42,6 +44,8 @@ ) import qualified Hix.Managed.Handlers.Build import Hix.Managed.Handlers.Build (EnvBuilder)+import qualified Hix.Managed.Handlers.Cabal+import Hix.Managed.Handlers.Cabal (CabalHandlers (CabalHandlers)) import qualified Hix.Managed.Handlers.Mutation import Hix.Managed.Handlers.Mutation (MutationHandlers) import Hix.Managed.StageState (updateStageState)@@ -56,13 +60,14 @@ Log.info [exon|Building targets in '##{env}' with #{description}...|] Log.debugP (vcat ["Overrides:", prettyL overrides]) -logBuildResult :: Text -> BuildStatus -> M ()-logBuildResult description status =- Log.info [exon|Build with ##{description} #{result status}|]+logBuildResult :: Text -> BuildResult -> M ()+logBuildResult description result =+ Log.info [exon|Build with ##{description} #{describeResult result}|] where- result = \case- Success -> "succeeded"- Failure -> "failed"+ describeResult = \case+ Finished Success -> "succeeded"+ Finished Failure -> "failed"+ TimedOut -> "timed out" updateMutationState :: (Version -> VersionBounds -> VersionBounds) ->@@ -92,7 +97,7 @@ logBuildInputs context.env description reinstallable (overrides, status) <- builder.buildWithState versions reinstallable logBuildResult description status- pure (overrides, status)+ pure (overrides, buildStatus status) where reinstallable = filter isReinstallableId overrideVersions @@ -210,7 +215,10 @@ s -> M (StageState a s) processQuery candidates handlers conf StageContext {env, builder, state, query = query} ext = do- mutations <- reinstallableCandidates candidates query+ mutations <- postprocess =<< reinstallableCandidates candidates query convergeMutations handlers conf builder env stageState mutations where+ postprocess | conf.toposortMutations = sortMutations+ | otherwise = pure stageState = initStageState state ext+ CabalHandlers {sortMutations} = builder.cabal
lib/Hix/Managed/Bump/App.hs view
@@ -6,6 +6,7 @@ import Hix.Data.Options (BumpOptions (BumpOptions)) import Hix.Json (jsonConfigE) import Hix.Managed.Bump.Optimize (bumpOptimizeMain)+import qualified Hix.Managed.Data.BuildConfig import qualified Hix.Managed.Data.ProjectContextProto import Hix.Managed.Handlers.Build.Test (chooseHandlers) import Hix.Managed.ProjectContext (withProjectContext)@@ -13,5 +14,7 @@ bumpCli :: BumpOptions -> M () bumpCli BumpOptions {common = opts} = do context <- jsonConfigE Client opts.context- handlers <- liftIO (chooseHandlers opts.stateFile context.envs context.buildOutputsPrefix opts.cabal opts.handlers)+ handlers <- liftIO $+ chooseHandlers opts.stateFile context.envs context.buildOutputsPrefix opts.project.build.timeout opts.cabal+ opts.handlers withProjectContext handlers opts.project context (bumpOptimizeMain handlers)
lib/Hix/Managed/Cabal/Print.hs view
@@ -3,21 +3,31 @@ import qualified Distribution.Client.SolverInstallPlan as SolverInstallPlan import Distribution.Client.SolverInstallPlan (ResolverPackage (..), SolverInstallPlan, SolverPlanPackage) import Distribution.InstalledPackageInfo (InstalledPackageInfo (InstalledPackageInfo, sourcePackageId))-import Distribution.Pretty (pretty) import Distribution.Solver.Types.InstSolverPackage (InstSolverPackage (InstSolverPackage, instSolverPkgIPI)) import Distribution.Solver.Types.SolverPackage (SolverPackage (..)) import Distribution.Solver.Types.SourcePackage (SourcePackage (..)) import Exon (exon) import Hix.Data.Monad (M)+import qualified Hix.Data.PackageId as PackageId+import Hix.Data.PackageId (PackageId) import qualified Hix.Log as Log+import Hix.Pretty (showP) -showPackage :: SolverPlanPackage -> String-showPackage = \case+resolverPackageId :: ResolverPackage a -> PackageId+resolverPackageId = \case PreExisting InstSolverPackage {instSolverPkgIPI = InstalledPackageInfo {sourcePackageId}} ->- "existing: " <> show (pretty sourcePackageId)+ PackageId.fromCabal sourcePackageId Configured SolverPackage {solverPkgSource = SourcePackage {srcpkgPackageId}} ->- "configured: " <> show (pretty srcpkgPackageId)+ PackageId.fromCabal srcpkgPackageId++showPackage :: SolverPlanPackage -> String+showPackage pkg =+ [exon|#{desc}: #{showP (resolverPackageId pkg)}|]+ where+ desc = case pkg of+ PreExisting {} -> "existing"+ Configured {} -> "configured" printPlan :: SolverInstallPlan -> M () printPlan plan = do
lib/Hix/Managed/Cabal/Repo.hs view
@@ -1,20 +1,26 @@ module Hix.Managed.Cabal.Repo where -import Data.Time (UTCTime (..), showGregorian, timeToTimeOfDay)+import Data.Time (+ NominalDiffTime,+ UTCTime (..),+ diffUTCTime,+ getCurrentTime,+ nominalDay,+ showGregorian,+ timeToTimeOfDay,+ ) import Distribution.Client.CmdUpdate (updateAction) import qualified Distribution.Client.GlobalFlags import Distribution.Client.GlobalFlags (GlobalFlags (..)) import Distribution.Client.IndexUtils (currentIndexTimestamp, indexBaseName)-import Distribution.Client.IndexUtils.Timestamp (timestampToUTCTime)+import Distribution.Client.IndexUtils.Timestamp (Timestamp, timestampToUTCTime) import Distribution.Client.NixStyleOptions (NixStyleFlags (..)) import Distribution.Client.Setup (RepoContext, withRepoContext) import Distribution.Client.Types (RemoteRepo (..), Repo (RepoSecure), RepoName (RepoName)) import qualified Distribution.Client.Types.Repo-import Distribution.Compat.Time (getFileAge) import Distribution.Verbosity (Verbosity) import Exon (exon)-import Path (Abs, File, Path, addExtension, parseAbsFile, toFilePath)-import Path.IO (doesFileExist)+import Path (Abs, File, Path, addExtension, parseAbsFile) import Hix.Data.Error (Error (Fatal)) import Hix.Error (pathText)@@ -26,8 +32,8 @@ HackageRepoName (HackageRepoName), SolveConfig (SolveConfig), )-import Hix.Maybe (justIf) import Hix.Monad (M, catchIOM, eitherFatalShow, noteFatal, tryIOM, tryIOMWith, withLower)+import Hix.Pretty (showP) withRepoContextM :: SolveConfig ->@@ -51,14 +57,18 @@ data IndexProblem = IndexMissing |- IndexOutdated+ IndexOutdated NominalDiffTime | IndexMismatch+ |+ IndexCorrupt Timestamp deriving stock (Eq, Show, Generic) -indexOutdated :: Path Abs File -> IO Bool-indexOutdated (toFilePath -> index) =- (> 7) <$> getFileAge index+data ValidIndex =+ IndexMatch HackageIndexState+ |+ IndexRecent NominalDiffTime+ deriving stock (Eq, Show, Generic) updateRequest :: SolveConfig ->@@ -72,6 +82,12 @@ HackageRepoName (toString -> hackage) = hackageRepoName +maxIndexAgeDays :: Int+maxIndexAgeDays = 7++maxIndexAge :: NominalDiffTime+maxIndexAge = nominalDay * fromIntegral maxIndexAgeDays+ updateIndex :: SolveConfig -> GlobalFlags ->@@ -80,13 +96,14 @@ M () updateIndex conf global main problem = do Log.verbose [exon|Hackage snapshot #{message}, fetching...|]- tryIOMWith (\ err -> Fatal [exon|Fetching hackage snapshot failed: #{err}|]) do+ tryIOMWith (\ err -> Fatal [exon|Fetching Hackage snapshot failed: #{err}|]) do updateAction main [updateRequest conf] global where message = case problem of IndexMissing -> "doesn't exist"- IndexOutdated -> "is older than 7 days"+ IndexOutdated age -> [exon|is older than #{show maxIndexAgeDays} days (#{show age})|] IndexMismatch -> "differs from requested index state"+ IndexCorrupt stamp -> [exon|has corrupt timestamp (#{show stamp})|] indexPath :: Repo -> M (Path Abs File) indexPath repo =@@ -96,34 +113,59 @@ where err = "Bad Hackage repo config" -matchIndexState ::+currentIndexState :: Verbosity -> RepoContext -> Repo ->- HackageIndexState ->- M (Maybe IndexProblem)-matchIndexState verbosity ctx repo (HackageIndexState target) =- catchIOM (match <$> currentIndexTimestamp verbosity ctx repo) (\ _ -> pure (Just IndexMissing))- where- match current | current == target = Nothing- | otherwise = Just IndexMismatch+ M (Maybe HackageIndexState)+currentIndexState verbosity ctx repo =+ catchIOM (Just . HackageIndexState <$> currentIndexTimestamp verbosity ctx repo) (const (pure Nothing)) indexProblem :: SolveConfig -> RepoContext -> Repo -> Path Abs File ->- M (Maybe IndexProblem)+ M (Either IndexProblem ValidIndex) indexProblem SolveConfig {verbosity, cabal} ctx repo path = do- Log.debug [exon|Checking hackage snapshot at #{pathText path}|]- tryIOM (doesFileExist path) >>= \case- False -> pure (Just IndexMissing)- True+ now <- tryIOM getCurrentTime+ Log.debug [exon|Checking Hackage snapshot at #{pathText path}|]+ currentIndexState verbosity ctx repo <&> \case+ -- There is no index, so the target is irrelevant.+ Nothing -> Left IndexMissing+ Just currentState+ -- If a target index state was specified, we only care whether it matches exactly.+ -- The later conditions are irrelevant. | Just target <- cabal.indexState- -> matchIndexState verbosity ctx repo target+ -> if currentState == target+ then Right (IndexMatch target)+ else Left IndexMismatch+ -- If no target was specified, the age of the current index must be below the threshold.+ -- The guard expresses that the timestamp could be parsed.+ | Just current <- currentUTC+ , let age = diffUTCTime now current+ -> if diffUTCTime now current > maxIndexAge+ then Left (IndexOutdated age)+ else Right (IndexRecent age)+ -- If the current state's timestamp can't be converted to UTCTime, it may be corrupt, so we update. | otherwise- -> flip justIf IndexOutdated <$> tryIOM (indexOutdated path)+ -> Left (IndexCorrupt (coerce currentState))+ where+ currentUTC = timestampToUTCTime (coerce currentState) +logValid ::+ ValidIndex ->+ M ()+logValid = \case+ IndexMatch (HackageIndexState ts) -> Log.debug [exon|Snapshot matches target: #{showP ts}|]+ IndexRecent age ->+ Log.debug [exon|Snapshot is less than #{desc} old (maximum #{show maxIndexAgeDays}).|]+ where+ desc | days == 1 = "a day"+ | otherwise = [exon|#{show days} days|]+ days :: Int+ days = maybe 0 ceiling (age / nominalDay)+ -- TODO currentIndexTimestamp has a different signature in later versions ensureHackageIndex :: SolveConfig ->@@ -134,4 +176,4 @@ withRepoContextM conf global \ ctx -> do repo <- fullHackageRepo conf ctx path <- indexPath repo- traverse_ (updateIndex conf global main) =<< indexProblem conf ctx repo path+ either (updateIndex conf global main) logValid =<< indexProblem conf ctx repo path
+ lib/Hix/Managed/Cabal/Sort.hs view
@@ -0,0 +1,45 @@+module Hix.Managed.Cabal.Sort where++import qualified Data.Map.Strict as Map+import Data.Map.Strict ((!?))+import Distribution.Client.SolverInstallPlan (topologicalOrder)+import Exon (exon)++import Hix.Data.Monad (M)+import qualified Hix.Data.PackageId+import qualified Hix.Log as Log+import Hix.Managed.Cabal.Data.SolveResources (SolveResources)+import Hix.Managed.Cabal.Print (resolverPackageId)+import Hix.Managed.Cabal.Solve (solveForTargets)+import Hix.Managed.Cabal.Targets (solveTarget)+import Hix.Managed.Data.Mutable (MutableDep (MutableDep))+import Hix.Managed.Data.Mutation (DepMutation (..))+import Hix.Data.PackageName (PackageName)++sortDeps ::+ ∀ a .+ SolveResources ->+ (a -> PackageName) ->+ [a] ->+ M [a]+sortDeps resources name mutations =+ solveForTargets resources id targets >>= \case+ Right plan ->+ pure (mapMaybe original (topologicalOrder plan))+ Left err -> do+ Log.error [exon|No plan for mutations: ##{err}|]+ pure mutations+ where+ original k = byName !? (resolverPackageId k).name+ byName = Map.fromList [(name m, m) | m <- mutations]+ targets = [solveTarget (name m) mempty | m <- mutations]++sortMutations ::+ ∀ a .+ SolveResources ->+ [DepMutation a] ->+ M [DepMutation a]+sortMutations resources =+ sortDeps resources name+ where+ name DepMutation {package = MutableDep package} = package
lib/Hix/Managed/Data/BuildConfig.hs view
@@ -1,5 +1,7 @@ module Hix.Managed.Data.BuildConfig where +import Hix.Managed.Handlers.Build (BuildTimeout)+ data BuildConfig = BuildConfig { maxIterations :: Natural,@@ -7,7 +9,9 @@ maxFailedPost :: Natural, lookup :: Bool, validate :: Bool,- buildOutput :: Bool+ buildOutput :: Bool,+ toposortMutations :: Bool,+ timeout :: Maybe BuildTimeout } deriving stock (Eq, Show, Generic) @@ -18,5 +22,7 @@ maxFailedPost = 0, lookup = False, validate = False,- buildOutput = False+ buildOutput = False,+ toposortMutations = True,+ timeout = Nothing }
lib/Hix/Managed/Data/Constraints.hs view
@@ -8,7 +8,7 @@ import Hix.Class.Map (LookupMaybe, NMap, nPretty) import Hix.Data.PackageName (PackageName)-import Hix.Data.VersionBounds (VersionBounds, anyBounds)+import Hix.Data.VersionBounds (VersionBounds, anyBounds, inclusiveRange) import Hix.Pretty (prettyL) -- | Left-biased semigroup op.@@ -37,7 +37,7 @@ instance Pretty MutationConstraints where pretty MutationConstraints {mutation, oldest, installed, force, prefer} =- pretty mutation <+>+ pretty (inclusiveRange mutation) <+> flags [("oldest", oldest), ("installed", installed)] <+> foldMap pref prefer <+> foldMap spec force
lib/Hix/Managed/Data/Query.hs view
@@ -5,11 +5,15 @@ import Hix.Data.PackageName (PackageName) import Hix.Managed.Data.QueryDep (QueryDep) +-- | User-selected restriction of packages that should be processed.+-- Given as positional arguments on the command line.+-- If empty, all packages are processed. newtype RawQuery = RawQuery [PackageName] deriving stock (Eq, Show, Generic) deriving newtype (IsList) +-- | Stage-specific subset of the validated environment subset of 'RawQuery', adorned with metadata. newtype Query = Query (NonEmpty QueryDep) deriving stock (Eq, Show, Generic)
lib/Hix/Managed/Data/StageState.hs view
@@ -18,10 +18,22 @@ Success -> Just a Failure -> Nothing -buildStatus :: Bool -> BuildStatus+data BuildResult =+ Finished BuildStatus+ |+ TimedOut+ deriving stock (Eq, Show, Generic)++buildUnsuccessful :: BuildResult -> Bool+buildUnsuccessful = \case+ Finished Success -> False+ Finished Failure -> True+ TimedOut -> True++buildStatus :: BuildResult -> BuildStatus buildStatus = \case- True -> Success- False -> Failure+ Finished s -> s+ TimedOut -> Failure data BuildSuccess = CandidateBuilt MutableId
lib/Hix/Managed/Data/Targets.hs view
@@ -6,6 +6,7 @@ singleTarget, sortTargets, allMTargets,+ firstMTargets, overTargets, ) where @@ -78,6 +79,22 @@ simple :: Packages [LocalPackage] simple = nMap (onlyFrom targetSet) (nRestrictKeys targetSet deps) targetSet = Set.fromList targets++firstMTargets ::+ Monad m =>+ a ->+ (a -> Bool) ->+ (LocalPackage -> m a) ->+ Targets ->+ m a+firstMTargets success cond f (Targets targets) =+ foldr chain (pure success) targets+ where+ chain a z = do+ res <- f a+ if cond res+ then pure res+ else z allMTargets :: Monad m =>
lib/Hix/Managed/Handlers/Build.hs view
@@ -16,7 +16,7 @@ import Hix.Managed.Data.Initial (Initial) import Hix.Managed.Data.ManagedPackage (ManagedPackage) import Hix.Managed.Data.Packages (Packages)-import Hix.Managed.Data.StageState (BuildStatus (Failure))+import Hix.Managed.Data.StageState (BuildResult (Finished), BuildStatus (Failure)) import qualified Hix.Managed.Handlers.Cabal as Solve import qualified Hix.Managed.Handlers.Cabal as Cabal import Hix.Managed.Handlers.Cabal (CabalHandlers)@@ -32,10 +32,15 @@ deriving stock (Eq, Show, Generic) deriving newtype (IsString, Ord, FromJSON) +newtype BuildTimeout =+ BuildTimeout Int+ deriving stock (Eq, Show, Generic)+ deriving newtype (Num, Real, Enum, Integral, Ord, FromJSON)+ data EnvBuilder = EnvBuilder { cabal :: CabalHandlers,- buildWithState :: Versions -> [PackageId] -> M (Overrides, BuildStatus)+ buildWithState :: Versions -> [PackageId] -> M (Overrides, BuildResult) } data Builder =@@ -56,11 +61,11 @@ latestVersion :: PackageName -> M (Maybe Version) } -testBuilder :: (Versions -> [PackageId] -> M (Overrides, BuildStatus)) -> (Builder -> M a) -> M a+testBuilder :: (Versions -> [PackageId] -> M (Overrides, BuildResult)) -> (Builder -> M a) -> M a testBuilder buildWithState use = use Builder {withEnvBuilder = \ cabal _ _ useE -> useE EnvBuilder {cabal, buildWithState}} -versionsBuilder :: HackageHandlers -> (Versions -> M BuildStatus) -> (Builder -> M a) -> M a+versionsBuilder :: HackageHandlers -> (Versions -> M BuildResult) -> (Builder -> M a) -> M a versionsBuilder hackage build = testBuilder \ versions overrideVersions -> do overrides <- packageOverrides hackage overrideVersions@@ -73,7 +78,7 @@ stateFile = StateFileHandlers.handlersNull, report = Report.handlersNull, cabal = \ _ _ -> pure Solve.handlersNull,- withBuilder = testBuilder \ _ _ -> pure (mempty, Failure),+ withBuilder = testBuilder \ _ _ -> pure (mempty, Finished Failure), versions = \ _ -> pure [], latestVersion = \ _ -> pure Nothing }
lib/Hix/Managed/Handlers/Build/Prod.hs view
@@ -14,11 +14,13 @@ inherit, nullStream, proc,- runProcess, setStderr, setStdout, setWorkingDir,+ waitExitCode,+ withProcessTerm, )+import System.Timeout (timeout) import Hix.Data.EnvName (EnvName) import Hix.Data.Error (Error (Fatal))@@ -38,12 +40,18 @@ import Hix.Managed.Data.EnvState (EnvState) import Hix.Managed.Data.Envs (Envs) import Hix.Managed.Data.Initial (Initial)-import Hix.Managed.Data.StageState (BuildStatus, buildStatus)+import Hix.Managed.Data.StageState (BuildResult (Finished, TimedOut), BuildStatus (Failure, Success), buildUnsuccessful) import qualified Hix.Managed.Data.StateFileConfig import Hix.Managed.Data.StateFileConfig (StateFileConfig)-import Hix.Managed.Data.Targets (allMTargets)+import Hix.Managed.Data.Targets (firstMTargets) import qualified Hix.Managed.Handlers.Build-import Hix.Managed.Handlers.Build (BuildHandlers (..), BuildOutputsPrefix, Builder (Builder), EnvBuilder (EnvBuilder))+import Hix.Managed.Handlers.Build (+ BuildHandlers (..),+ BuildOutputsPrefix,+ BuildTimeout,+ Builder (Builder),+ EnvBuilder (EnvBuilder),+ ) import Hix.Managed.Handlers.Cabal (CabalHandlers) import qualified Hix.Managed.Handlers.Cabal.Prod as CabalHandlers import Hix.Managed.Handlers.Hackage (HackageHandlers)@@ -62,7 +70,8 @@ stateFileHandlers :: StateFileHandlers, envsConf :: Envs EnvConfig, buildOutputsPrefix :: Maybe BuildOutputsPrefix,- root :: Path Abs Dir+ root :: Path Abs Dir,+ buildTimeout :: Maybe BuildTimeout } data EnvBuilderResources =@@ -103,17 +112,22 @@ args = toString <$> cmd ++ [exon|path:#{".#"}#{installable}|] : extra buildPackage ::+ Maybe BuildTimeout -> Path Abs Dir -> EnvName -> LocalPackage ->- M Bool-buildPackage root env target = do+ M BuildResult+buildPackage processTimeout root env target = do debug <- M (asks (.debug)) conf <- nixProc root ["-L", "build"] [exon|env.##{env}.##{target}|] []- tryIOM (runProcess (err debug conf)) <&> \case- ExitSuccess -> True- ExitFailure _ -> False+ tryIOM (withProcessTerm (err debug conf) (limit . waitExitCode)) <&> \case+ Just ExitSuccess -> Finished Success+ Just (ExitFailure _) -> Finished Failure+ Nothing -> TimedOut where+ limit | Just t <- processTimeout = timeout (coerce t * 1_000_000)+ | otherwise = fmap Just+ err = \case True -> setStdout inherit False -> id@@ -122,11 +136,11 @@ EnvBuilderResources -> Versions -> [PackageId] ->- M (Overrides, BuildStatus)+ M (Overrides, BuildResult) buildWithState EnvBuilderResources {global, context = context@EnvContext {env, targets}} _ overrideVersions = do overrides <- packageOverrides global.hackage overrideVersions writeBuildStateFor "current build" global.stateFileHandlers global.root context overrides- status <- buildStatus <$> allMTargets (buildPackage global.root env) targets+ status <- firstMTargets (Finished Success) buildUnsuccessful (buildPackage global.buildTimeout global.root env) targets pure (overrides, status) -- | This used to have the purpose of reading an updated GHC package db using the current managed state, but this has@@ -159,9 +173,10 @@ StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix ->+ Maybe BuildTimeout -> (Builder -> M a) -> M a-withBuilder hackage stateFileHandlers stateFileConf envsConf buildOutputsPrefix use =+withBuilder hackage stateFileHandlers stateFileConf envsConf buildOutputsPrefix buildTimeout use = withTempProject stateFileConf.projectRoot \ root -> do let resources = BuilderResources {..} use Builder {withEnvBuilder = withEnvBuilder resources}@@ -171,10 +186,11 @@ StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix ->+ Maybe BuildTimeout -> CabalConfig -> Bool -> m BuildHandlers-handlersProd stateFileConf envsConf buildOutputsPrefix cabalConf oldest = do+handlersProd stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf oldest = do manager <- liftIO (newManager tlsManagerSettings) hackage <- HackageHandlers.handlersProd let stateFile = StateFileHandlers.handlersProd stateFileConf@@ -182,7 +198,7 @@ stateFile, report = ReportHandlers.handlersProd, cabal = CabalHandlers.handlersProd cabalConf oldest,- withBuilder = withBuilder hackage stateFile stateFileConf envsConf buildOutputsPrefix,+ withBuilder = withBuilder hackage stateFile stateFileConf envsConf buildOutputsPrefix buildTimeout, versions = versionsHackage manager, latestVersion = latestVersionHackage manager }
lib/Hix/Managed/Handlers/Build/Test.hs view
@@ -16,11 +16,12 @@ import Hix.Managed.Data.EnvConfig (EnvConfig) import Hix.Managed.Data.Envs (Envs) import Hix.Managed.Data.Mutation (FailedMutation)-import Hix.Managed.Data.StageState (BuildStatus)+import Hix.Managed.Data.StageState (BuildResult) import Hix.Managed.Data.StateFileConfig (StateFileConfig) import Hix.Managed.Handlers.Build ( BuildHandlers (..), BuildOutputsPrefix,+ BuildTimeout, SpecialBuildHandlers (TestBumpHandlers), versionsBuilder, )@@ -35,7 +36,7 @@ handlersUnitTest :: MonadIO m => GhcPackages ->- (Versions -> M BuildStatus) ->+ (Versions -> M BuildResult) -> m (BuildHandlers, IORef [Expr], IORef [FailedMutation]) handlersUnitTest ghcPackages builder = do (stateFile, stateFileRef) <- StateFile.handlersUnitTest@@ -67,11 +68,12 @@ StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix ->+ Maybe BuildTimeout -> CabalConfig -> Bool -> m BuildHandlers-handlersBumpTest stateFileConf envsConf buildOutputsPrefix cabalConf oldest = do- handlers <- handlersProd stateFileConf envsConf buildOutputsPrefix cabalConf oldest+handlersBumpTest stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf oldest = do+ handlers <- handlersProd stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf oldest pure handlers { cabal = CabalHandlers.handlersTest cabalConf oldest, latestVersion = latestVersionNixTestBump@@ -82,11 +84,12 @@ StateFileConfig -> Envs EnvConfig -> Maybe BuildOutputsPrefix ->+ Maybe BuildTimeout -> CabalConfig -> Maybe SpecialBuildHandlers -> m BuildHandlers-chooseHandlers stateFileConf envsConf buildOutputsPrefix cabalConf = \case- Just TestBumpHandlers -> handlersBumpTest stateFileConf envsConf buildOutputsPrefix cabalConf oldest- Nothing -> handlersProd stateFileConf envsConf buildOutputsPrefix cabalConf oldest+chooseHandlers stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf = \case+ Just TestBumpHandlers -> handlersBumpTest stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf oldest+ Nothing -> handlersProd stateFileConf envsConf buildOutputsPrefix buildTimeout cabalConf oldest where oldest = False
lib/Hix/Managed/Handlers/Cabal.hs view
@@ -10,18 +10,21 @@ import Hix.Managed.Cabal.Data.SolverState (SolverState) import Hix.Managed.Data.Constraints (EnvConstraints) import Hix.Managed.Data.Mutable (MutableDep, MutableVersions, depName)+import Hix.Managed.Data.Mutation (DepMutation) data CabalHandlers = CabalHandlers { solveForVersion :: SolverState -> M (Maybe SolverPlan),- installedVersion :: PackageName -> Maybe Version+ installedVersion :: PackageName -> Maybe Version,+ sortMutations :: ∀ a . [DepMutation a] -> M [DepMutation a] } handlersNull :: CabalHandlers handlersNull = CabalHandlers { solveForVersion = \ _ -> pure Nothing,- installedVersion = const Nothing+ installedVersion = const Nothing,+ sortMutations = pure } installedVersions ::
lib/Hix/Managed/Handlers/Cabal/Prod.hs view
@@ -13,12 +13,13 @@ import Hix.Data.PackageId (PackageId (PackageId)) import qualified Hix.Data.PackageName as PackageName import Hix.Data.PackageName (PackageName)-import Hix.Managed.Cabal.Data.Config (GhcDb, CabalConfig)+import Hix.Managed.Cabal.Data.Config (CabalConfig, GhcDb) import qualified Hix.Managed.Cabal.Data.SolveResources as SolveResources import Hix.Managed.Cabal.Data.SolveResources (SolveResources (SolveResources), solverParams) import Hix.Managed.Cabal.Installed (installedVersion) import qualified Hix.Managed.Cabal.Resources as SolveResources import Hix.Managed.Cabal.Solve (solveWithCabal)+import Hix.Managed.Cabal.Sort (sortMutations) import Hix.Managed.Data.ManagedPackage (ManagedPackage) import Hix.Managed.Data.Packages (Packages) import Hix.Managed.Handlers.Cabal (CabalHandlers (..))@@ -35,7 +36,8 @@ solveResources <- trans <$> SolveResources.acquire packages cabalConf ghc pure CabalHandlers { solveForVersion = solveWithCabal solveResources {solverParams},- installedVersion = installedVersion solveResources.installedPkgIndex+ installedVersion = installedVersion solveResources.installedPkgIndex,+ sortMutations = sortMutations solveResources } where solverParams | oldest = setPreferenceDefault PreferAllOldest
lib/Hix/Managed/Lower/App.hs view
@@ -5,6 +5,7 @@ import qualified Hix.Data.Options import Hix.Data.Options (LowerOptions (LowerOptions)) import Hix.Json (jsonConfigE)+import qualified Hix.Managed.Data.BuildConfig import Hix.Managed.Data.LowerConfig (LowerConfig, lowerConfig) import Hix.Managed.Data.ProjectContext (ProjectContext) import qualified Hix.Managed.Data.ProjectContextProto@@ -23,7 +24,8 @@ M () lowerCli main opts@LowerOptions {common} = do context <- jsonConfigE Client common.context- handlers <- chooseHandlers common.stateFile context.envs context.buildOutputsPrefix common.cabal common.handlers+ handlers <- chooseHandlers common.stateFile context.envs context.buildOutputsPrefix common.project.build.timeout+ common.cabal common.handlers withProjectContext handlers common.project context (main conf handlers) where conf = lowerConfig opts
lib/Hix/Managed/Lower/Stabilize.hs view
@@ -60,12 +60,11 @@ execStatelessStage "stabilize-initial" \ StageContext {env, initial, builder} -> buildVersions builder env "initial lower bounds" initial <&> \case Success -> StageNoAction (Just "Env builds successfully with the initial bounds.")- Failure ->- StageFailure (FailedPrecondition msg)+ Failure -> StageFailure (FailedPrecondition msg) where msg = [- "Cannot stabilize since the build with initial bounds failed.",+ [exon|Cannot stabilize since the build with initial bounds failed.|], "Please run 'lower.init --reset' or fix the build manually." ] @@ -136,7 +135,7 @@ lowerStabilizeStages handlers conf = validateCurrent >>= \case Success -> unit- Failure -> stabilizeIfPossible handlers conf+ _ -> stabilizeIfPossible handlers conf lowerStabilizeMain :: BuildHandlers ->
lib/Hix/Options.hs view
@@ -77,6 +77,7 @@ import Hix.Managed.Data.Query (RawQuery (RawQuery)) import qualified Hix.Managed.Data.StateFileConfig import Hix.Managed.Data.StateFileConfig (StateFileConfig (StateFileConfig))+import Hix.Managed.Handlers.Build (BuildTimeout (BuildTimeout)) import Hix.Optparse ( JsonConfig, absDirOption,@@ -256,12 +257,15 @@ lookup <- switch (long "lookup" <> short 'n' <> help "Only print latest versions (bump)") validate <- switch (long "validate" <> help "Validate new versions, but don't update the project state") buildOutput <- switch (long "build-output" <> help "Show output from Nix builds")+ timeout <- fmap BuildTimeout <$> optional (option auto (long "build-timeout" <> help buildTimeoutHelp)) pure BuildConfig {..} where maxIterationsHelp = "Number of restarts when some dependencies fail" maxFailedPreHelp = maxFailedHelp "prior to the first" maxFailedPostHelp = maxFailedHelp "after the last" maxFailedHelp variant = [exon|Number of majors that may fail before aborting, #{variant} success|]+ buildTimeoutHelp = "Kill Nix builds after this duration in seconds"+ toposortMutations = True projectOptionsParser :: Parser ProjectOptions projectOptionsParser = do
test/Hix/Test/Managed/LowerInit/MutationTest.hs view
@@ -27,7 +27,7 @@ import Hix.NixExpr (renderRootExpr) import Hix.Pretty (showP) import Hix.Test.Hedgehog (eqLines, listEqZip)-import Hix.Test.Managed.Run (Result (..), TestParams (..), lowerTest, testParams)+import Hix.Test.Managed.Run (Result (..), TestParams (..), lowerTest, testParams, nosortOptions) import Hix.Test.Utils (UnitTest) packages :: Packages ManagedPackageProto@@ -433,6 +433,6 @@ log = True, ghcPackages, state,- projectOptions = def {envs = ["lower-main", "lower-special"], readUpperBounds = True},+ projectOptions = nosortOptions {envs = ["lower-main", "lower-special"], readUpperBounds = True}, build }
test/Hix/Test/Managed/LowerNativeTest.hs view
@@ -233,7 +233,7 @@ projectRoot = Just root } envsConfig = [("lower", EnvConfig {targets = ["root"], ghc = GhcDbSystem Nothing})]- handlers <- Build.handlersProd stateFileConf envsConfig Nothing def False+ handlers <- Build.handlersProd stateFileConf envsConfig Nothing Nothing def False let opts = projectOptions ["lower"]
+ test/Hix/Test/Managed/LowerOptimize/OrderTest.hs view
@@ -0,0 +1,133 @@+module Hix.Test.Managed.LowerOptimize.OrderTest where++import Hix.Data.Monad (M)+import Hix.Data.Version (Versions)+import Hix.Managed.Cabal.Changes (SolverPlan (..))+import qualified Hix.Managed.Cabal.Data.Packages+import Hix.Managed.Cabal.Data.Packages (GhcPackages (GhcPackages))+import Hix.Managed.Cabal.Data.SourcePackage (SourcePackages)+import Hix.Managed.Data.Constraints (EnvConstraints)+import Hix.Managed.Data.ManagedPackageProto (ManagedPackageProto, managedPackages)+import Hix.Managed.Data.Packages (Packages)+import qualified Hix.Managed.Data.ProjectStateProto+import Hix.Managed.Data.ProjectStateProto (ProjectStateProto (ProjectStateProto))+import Hix.Managed.Data.StageState (BuildStatus (Success))+import Hix.Managed.Lower.Optimize (lowerOptimizeMain)+import Hix.Test.Hedgehog (listEqZip)+import Hix.Test.Managed.Run (Result (..), TestParams (..), lowerTest, testParams)+import Hix.Test.Utils (UnitTest)++packages :: Packages ManagedPackageProto+packages =+ managedPackages [(("local1", "1.0"), ["dep1", "dep2", "dep3"])]++packageDb :: SourcePackages+packageDb =+ [+ ("dep1", [+ ([1, 8], []),+ ([1, 9], []),+ ([2, 0], []),+ ([2, 1], [])+ ]),+ ("dep2", [+ ([1, 9], ["dep1 <1.9"]),+ ([2, 0], []),+ ([2, 1], [])+ ]),+ ("dep3", [+ ([1, 9], ["dep2 <2"]),+ ([2, 0], ["dep2 <2"]),+ ([2, 1], [])+ ])+ ]++ghcPackages :: GhcPackages+ghcPackages = GhcPackages {installed = [], available = packageDb}++state :: ProjectStateProto+state =+ ProjectStateProto {+ bounds = [+ ("local1", [+ ("dep1", ">=2.1"),+ ("dep2", ">=2.1"),+ ("dep3", ">=2.1")+ ])+ ],+ versions = [+ ("lower", [+ ("dep1", [2, 1]),+ ("dep2", [2, 1]),+ ("dep3", [2, 1])+ ])+ ],+ overrides = [("lower", [])],+ initial = [+ ("lower", [+ ("dep1", [2, 1]),+ ("dep2", [2, 1]),+ ("dep3", [2, 1])+ ])+ ],+ resolving = False+ }++build :: Versions -> M BuildStatus+build _ = pure Success++cabalTarget :: [(EnvConstraints, Maybe SolverPlan)]+cabalTarget =+ [+ ([+ "dep1 <=2.1",+ "dep2 <=2.1",+ "dep3 ==2.0"+ ], plan ["dep1-1.8", "dep2-1.9", "dep3-2.0"]),+ ([+ "dep1 <=2.1",+ "dep2 <=2.1",+ "dep3 ==1.9"+ ], plan ["dep1-1.8", "dep2-1.9", "dep3-1.9"]),+ ([+ "dep1 <=1.8",+ "dep2 ==2.0",+ "dep3 <=1.9"+ ], Nothing),+ ([+ "dep1 <=1.8",+ "dep2 ==1.9",+ "dep3 <=1.9"+ ], plan ["dep1-1.8", "dep2-1.9", "dep3-1.9"]),+ ([+ "dep1 ==2.0",+ "dep2 <=1.9",+ "dep3 <=1.9"+ ], Nothing),+ ([+ "dep1 ==1.9",+ "dep2 <=1.9",+ "dep3 <=1.9"+ ], Nothing),+ ([+ "dep1 ==1.8",+ "dep2 <=1.9",+ "dep3 <=1.9"+ ], plan ["dep1-1.8", "dep2-1.9", "dep3-1.9"])+ ]+ where+ plan changes = Just SolverPlan {changes, matching = [], nonReinstallable = Nothing}++test_mutationOrder :: UnitTest+test_mutationOrder = do+ Result {cabalLog} <- lowerTest params lowerOptimizeMain+ listEqZip cabalTarget cabalLog+ where+ params =+ (testParams False packages) {+ cabalLog = True,+ ghcPackages,+ state,+ build,+ projectOptions = def+ }
test/Hix/Test/Managed/Run.hs view
@@ -7,6 +7,7 @@ import Hix.Data.EnvName (EnvName) import Hix.Data.Monad (M) import Hix.Data.NixExpr (Expr)+import qualified Hix.Data.Options as ProjectOptions import Hix.Data.Options (ProjectOptions) import Hix.Data.PackageName (LocalPackage) import Hix.Data.Version (Versions)@@ -14,6 +15,7 @@ import Hix.Managed.Cabal.Data.Config (GhcDb (GhcDbSynthetic)) import qualified Hix.Managed.Cabal.Data.Packages import Hix.Managed.Cabal.Data.Packages (GhcPackages (GhcPackages))+import Hix.Managed.Data.BuildConfig (BuildConfig (toposortMutations)) import Hix.Managed.Data.Constraints (EnvConstraints) import qualified Hix.Managed.Data.EnvConfig import Hix.Managed.Data.EnvConfig (EnvConfig (EnvConfig))@@ -24,7 +26,7 @@ import Hix.Managed.Data.ProjectContextProto (ProjectContextProto (..)) import Hix.Managed.Data.ProjectResult (ProjectResult) import Hix.Managed.Data.ProjectStateProto (ProjectStateProto)-import Hix.Managed.Data.StageState (BuildStatus (Failure))+import Hix.Managed.Data.StageState (BuildResult (Finished), BuildStatus (Failure)) import qualified Hix.Managed.Handlers.Build as BuildHandlers import Hix.Managed.Handlers.Build (BuildHandlers (..)) import qualified Hix.Managed.Handlers.Build.Test as BuildHandlers@@ -45,6 +47,9 @@ build :: Versions -> M BuildStatus } +nosortOptions :: ProjectOptions+nosortOptions = def {ProjectOptions.build = def {toposortMutations = False}}+ testParams :: Bool -> Packages ManagedPackageProto ->@@ -58,15 +63,16 @@ packages, ghcPackages = GhcPackages {installed = [], available = []}, state = def,- projectOptions = def,+ projectOptions = nosortOptions, build = const (pure Failure) } -data Result =+data Result a = Result { stateFile :: Expr, cabalLog :: [(EnvConstraints, Maybe SolverPlan)],- log :: [Text]+ log :: [Text],+ result :: a } testProjectContext ::@@ -85,14 +91,14 @@ defaultEnv = [(defaultEnvName, nKeys params.packages)] -managedTest ::+managedTest' :: EnvName -> TestParams ->- (BuildHandlers -> ProjectContext -> M ProjectResult) ->- TestT IO Result-managedTest defaultEnvName params main =+ (BuildHandlers -> ProjectOptions -> ProjectContextProto -> M a) ->+ TestT IO (Result a)+managedTest' defaultEnvName params main = withFrozenCallStack do- (handlers0, stateFileRef, _) <- BuildHandlers.handlersUnitTest params.ghcPackages params.build+ (handlers0, stateFileRef, _) <- BuildHandlers.handlersUnitTest params.ghcPackages (fmap Finished . params.build) (cabalRef, handlers1) <- if params.cabalLog then first Just <$> BuildHandlers.logCabal handlers0@@ -102,8 +108,8 @@ if params.log then handlers1 {report = ReportHandlers.handlersProd} else handlers1- (log, result) <- liftIO (runner (withProjectContext handlers params.projectOptions context (main handlers)))- evalEither result+ (log, e_result) <- liftIO (runner (main handlers params.projectOptions context))+ result <- evalEither e_result stateFile <- evalMaybe . head =<< liftIO (readIORef stateFileRef) cabalLog <- fold <$> for cabalRef \ ref -> reverse <$> liftIO (readIORef ref) pure Result {..}@@ -113,10 +119,20 @@ context = testProjectContext defaultEnvName params +managedTest ::+ EnvName ->+ TestParams ->+ (BuildHandlers -> ProjectContext -> M ProjectResult) ->+ TestT IO (Result ())+managedTest defaultEnvName params main =+ withFrozenCallStack do+ managedTest' defaultEnvName params \ handlers options context ->+ withProjectContext handlers options context (main handlers)+ lowerTest :: TestParams -> (BuildHandlers -> ProjectContext -> M ProjectResult) ->- TestT IO Result+ TestT IO (Result ()) lowerTest params main = withFrozenCallStack do managedTest "lower" params main@@ -124,7 +140,7 @@ bumpTest :: TestParams -> (BuildHandlers -> ProjectContext -> M ProjectResult) ->- TestT IO Result+ TestT IO (Result ()) bumpTest params main = withFrozenCallStack do managedTest "latest" params main
+ test/Hix/Test/Managed/SolveTest.hs view
@@ -0,0 +1,46 @@+module Hix.Test.Managed.SolveTest where++import qualified Data.Set as Set+import Hedgehog (evalEither)++import Hix.Class.Map (nKeys)+import qualified Hix.Managed.Cabal.Changes+import Hix.Managed.Cabal.Data.Config (GhcDb (GhcDbSystem))+import Hix.Managed.Cabal.Data.SolverState (solverState)+import qualified Hix.Managed.Cabal.Resources as SolveResources+import Hix.Managed.Cabal.Solve (solveWithCabal)+import Hix.Managed.Cabal.Sort (sortDeps)+import Hix.Managed.Data.EnvContext (EnvDeps (EnvDeps))+import Hix.Managed.Data.Mutable (unsafeMutableDep)+import Hix.Pretty (prettyL, showP, showPL)+import Hix.Test.Managed.UnsafeIsString ()+import Hix.Test.Utils (UnitTest, runMTest)++test_solve :: UnitTest+test_solve =+ evalEither =<< liftIO do+ runMTest True do+ res <- SolveResources.acquire mempty def (GhcDbSystem Nothing)+ result <- solveWithCabal res state+ sorted <- sortDeps res id (nKeys constraints)+ liftIO do+ putStrLn ""+ putStrLn "Constraints:"+ putStrLn (showP constraints)+ putStrLn ""+ putStrLn "Changes:"+ putStrLn (maybe "no plan" (show . prettyL . (.changes)) result)+ putStrLn ""+ putStrLn "Sorted:"+ putStrLn (showPL sorted)+ where+ state = solverState [] (EnvDeps (Set.fromList (unsafeMutableDep <$> nKeys constraints)) mempty) constraints def+ constraints =+ [+ ("ansi-terminal", mempty),+ ("async", mempty),+ ("polysemy-conc", mempty),+ ("polysemy-time", mempty),+ ("stm", mempty),+ ("time", mempty)+ ]
test/Hix/Test/ManagedTest.hs view
@@ -12,6 +12,7 @@ import Hix.Test.Managed.LowerNativeTest () import Hix.Test.Managed.LowerOptimize.CandidatesTest (test_candidatesOptimize) import Hix.Test.Managed.LowerOptimize.MutationTest (test_lowerOptimizeMutation)+import Hix.Test.Managed.LowerOptimize.OrderTest (test_mutationOrder) import Hix.Test.Managed.LowerStabilize.MutationTest (test_lowerStabilizeMutation) import Hix.Test.Managed.ProjectContextProtoTest (test_parseProjectContextProto) import Hix.Test.Utils (unitTest)@@ -29,7 +30,8 @@ unitTest "lower.optimize" test_lowerOptimizeMutation, unitTest "lower.stabilize" test_lowerStabilizeMutation, unitTest "lower.auto stabilize" test_lowerAutoMutationStabilize,- test_lowerAutoMutationOptimize+ test_lowerAutoMutationOptimize,+ unitTest "mutation ordering" test_mutationOrder ], unitTest "parse ProjectContext" test_parseProjectContextProto, test_buildOutput,