Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Haddock documentation and further types #6322

Merged
merged 1 commit into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 109 additions & 74 deletions src/Stack/Build/Installed.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- Determine which packages are already installed
module Stack.Build.Installed
Expand Down Expand Up @@ -30,6 +31,8 @@ import Stack.Types.GhcPkgId ( GhcPkgId )
import Stack.Types.Package
( InstallLocation (..), InstallMap, Installed (..)
, InstalledMap, InstalledPackageLocation (..)
, PackageDatabase (..), PackageDbVariety (..)
, toPackageDbVariety
)
import Stack.Types.SourceMap
( DepPackage (..), ProjectPackage (..), SourceMap (..) )
Expand Down Expand Up @@ -66,15 +69,15 @@ getInstalled {-opts-} installMap = do

let loadDatabase' = loadDatabase {-opts mcache-} installMap

(installedLibs0, globalDumpPkgs) <- loadDatabase' Nothing []
(installedLibs0, globalDumpPkgs) <- loadDatabase' GlobalPkgDb []
(installedLibs1, _extraInstalled) <-
foldM (\lhs' pkgdb ->
loadDatabase' (Just (ExtraGlobal, pkgdb)) (fst lhs')
loadDatabase' (UserPkgDb ExtraPkgDb pkgdb) (fst lhs')
) (installedLibs0, globalDumpPkgs) extraDBPaths
(installedLibs2, snapshotDumpPkgs) <-
loadDatabase' (Just (InstalledTo Snap, snapDBPath)) installedLibs1
loadDatabase' (UserPkgDb (InstalledTo Snap) snapDBPath) installedLibs1
(installedLibs3, localDumpPkgs) <-
loadDatabase' (Just (InstalledTo Local, localDBPath)) installedLibs2
loadDatabase' (UserPkgDb (InstalledTo Local) localDBPath) installedLibs2
let installedLibs = Map.fromList $ map lhPair installedLibs3

-- Add in the executables that are installed, making sure to only trust a
Expand Down Expand Up @@ -114,71 +117,83 @@ getInstalled {-opts-} installMap = do
--
-- The goal is to ascertain that the dependencies for a package are present,
-- that it has profiling if necessary, and that it matches the version and
-- location needed by the SourceMap
-- location needed by the SourceMap.
loadDatabase ::
HasEnvConfig env
=> InstallMap -- ^ to determine which installed things we should include
-> Maybe (InstalledPackageLocation, Path Abs Dir)
-- ^ package database, Nothing for global
-> [LoadHelper] -- ^ from parent databases
forall env. HasEnvConfig env
=> InstallMap
-- ^ to determine which installed things we should include
-> PackageDatabase
-- ^ package database.
-> [LoadHelper]
-- ^ from parent databases
-> RIO env ([LoadHelper], [DumpPackage])
loadDatabase installMap mdb lhs0 = do
loadDatabase installMap db lhs0 = do
pkgexe <- getGhcPkgExe
(lhs1', dps) <- ghcPkgDump pkgexe (fmap snd (maybeToList mdb)) $
conduitDumpPackage .| sink
lhs1 <- mapMaybeM (processLoadResult mdb) lhs1'
(lhs1', dps) <- ghcPkgDump pkgexe pkgDb $ conduitDumpPackage .| sink
lhs1 <- mapMaybeM processLoadResult lhs1'
let lhs = pruneDeps id lhId lhDeps const (lhs0 ++ lhs1)
pure (map (\lh -> lh { lhDeps = [] }) $ Map.elems lhs, dps)
where
mloc = fmap fst mdb
sinkDP = CL.map (isAllowed installMap mloc &&& toLoadHelper mloc)
pkgDb = case db of
GlobalPkgDb -> []
UserPkgDb _ fp -> [fp]

sinkDP = CL.map (isAllowed installMap db' &&& toLoadHelper db')
.| CL.consume
where
db' = toPackageDbVariety db
sink = getZipSink $ (,)
<$> ZipSink sinkDP
<*> ZipSink CL.consume

processLoadResult :: HasLogFunc env
=> Maybe (InstalledPackageLocation, Path Abs Dir)
-> (Allowed, LoadHelper)
-> RIO env (Maybe LoadHelper)
processLoadResult _ (Allowed, lh) = pure (Just lh)
processLoadResult mdb (reason, lh) = do
logDebug $
"Ignoring package "
<> fromString (packageNameString (fst (lhPair lh)))
<> maybe
mempty
( \db -> ", from "
<> displayShow db
<> ","
)
mdb
<> " due to"
<> case reason of
UnknownPkg -> " it being unknown to the resolver / extra-deps."
WrongLocation mloc loc -> " wrong location: " <> displayShow (mloc, loc)
WrongVersion actual wanted ->
" wanting version "
<> fromString (versionString wanted)
<> " instead of "
<> fromString (versionString actual)
pure Nothing
processLoadResult :: (Allowed, LoadHelper) -> RIO env (Maybe LoadHelper)
processLoadResult (Allowed, lh) = pure (Just lh)
processLoadResult (reason, lh) = do
logDebug $
"Ignoring package "
<> fromString (packageNameString (fst (lhPair lh)))
<> case db of
GlobalPkgDb -> mempty
UserPkgDb loc fp -> ", from " <> displayShow (loc, fp) <> ","
<> " due to"
<> case reason of
UnknownPkg -> " it being unknown to the resolver / extra-deps."
WrongLocation db' loc ->
" wrong location: " <> displayShow (db', loc)
WrongVersion actual wanted ->
" wanting version "
<> fromString (versionString wanted)
<> " instead of "
<> fromString (versionString actual)
pure Nothing

-- | Type representing results of 'isAllowed'.
data Allowed
= Allowed
-- ^ The installed package can be included in the set of relevant installed
-- packages.
| UnknownPkg
| WrongLocation (Maybe InstalledPackageLocation) InstallLocation
-- ^ The installed package cannot be included in the set of relevant
-- installed packages because the package is unknown.
| WrongLocation PackageDbVariety InstallLocation
-- ^ The installed package cannot be included in the set of relevant
-- installed packages because the package is in the wrong package database.
| WrongVersion Version Version
-- ^ The installed package cannot be included in the set of relevant
-- installed packages because the package has the wrong version.
deriving (Eq, Show)

-- | Check if a can be included in the set of installed packages or not, based
-- on the package selections made by the user. This does not perform any
-- dirtiness or flag change checks.
isAllowed :: InstallMap
-> Maybe InstalledPackageLocation
-> DumpPackage
-> Allowed
isAllowed installMap mloc dp = case Map.lookup name installMap of
-- | Check if an installed package can be included in the set of relevant
-- installed packages or not, based on the package selections made by the user.
-- This does not perform any dirtiness or flag change checks.
isAllowed ::
InstallMap
-> PackageDbVariety
-- ^ The package database providing the installed package.
-> DumpPackage
-- ^ The installed package to check.
-> Allowed
isAllowed installMap pkgDb dp = case Map.lookup name installMap of
Nothing ->
-- If the sourceMap has nothing to say about this package,
-- check if it represents a sub-library first
Expand All @@ -195,34 +210,50 @@ isAllowed installMap mloc dp = case Map.lookup name installMap of
where
PackageIdentifier name version = dpPackageIdent dp
-- Ensure that the installed location matches where the sourceMap says it
-- should be installed
checkLocation Snap = True -- snapshot deps could become mutable after getting
-- any mutable dependency
checkLocation Local =
mloc == Just (InstalledTo Local) || mloc == Just ExtraGlobal -- 'locally' installed snapshot packages can come from extra dbs
-- Check if a package is allowed if it is found in the sourceMap
-- should be installed.
checkLocation Snap =
-- snapshot deps could become mutable after getting any mutable dependency.
True
checkLocation Local = case pkgDb of
GlobalDb -> False
-- 'locally' installed snapshot packages can come from 'extra' package
-- databases.
ExtraDb -> True
WriteOnlyDb -> False
MutableDb -> True
-- Check if an installed package is allowed if it is found in the sourceMap.
checkFound (installLoc, installVer)
| not (checkLocation installLoc) = WrongLocation mloc installLoc
| not (checkLocation installLoc) = WrongLocation pkgDb installLoc
| version /= installVer = WrongVersion version installVer
| otherwise = Allowed
-- check if a package is allowed if it is not found in the sourceMap
checkNotFound = case mloc of
-- The sourceMap has nothing to say about this global package, so we can use it
Nothing -> Allowed
Just ExtraGlobal -> Allowed
-- Check if an installed package is allowed if it is not found in the
-- sourceMap.
checkNotFound = case pkgDb of
-- The sourceMap has nothing to say about this global package, so we can use
-- it.
GlobalDb -> Allowed
ExtraDb -> Allowed
-- For non-global packages, don't include unknown packages.
-- See: https://github.com/commercialhaskell/stack/issues/292
Just _ -> UnknownPkg
WriteOnlyDb -> UnknownPkg
MutableDb -> UnknownPkg

-- | Type representing certain information about an installed package.
data LoadHelper = LoadHelper
{ lhId :: !GhcPkgId
{ lhId :: !GhcPkgId
-- ^ The package's id.
, lhDeps :: ![GhcPkgId]
-- ^ Unless the package's name is that of a 'wired-in' package, a list of
-- the ids of the installed packages that are the package's dependencies.
, lhPair :: !(PackageName, (InstallLocation, Installed))
-- ^ A pair of (a) the package's name and (b) a pair of the relevant
-- database (write-only or mutable) and information about the library
-- installed.
}
deriving Show

toLoadHelper :: Maybe InstalledPackageLocation -> DumpPackage -> LoadHelper
toLoadHelper mloc dp = LoadHelper
toLoadHelper :: PackageDbVariety -> DumpPackage -> LoadHelper
toLoadHelper pkgDb dp = LoadHelper
{ lhId = gid
, lhDeps =
-- We always want to consider the wired in packages as having all of their
Expand All @@ -233,13 +264,17 @@ toLoadHelper mloc dp = LoadHelper
if name `Set.member` wiredInPackages
then []
else dpDepends dp
, lhPair = (name, (toPackageLocation mloc, Library ident gid (Right <$> dpLicense dp)))
, lhPair =
( name
, (toInstallLocation pkgDb, Library ident gid (Right <$> dpLicense dp))
)
}
where
gid = dpGhcPkgId dp
ident@(PackageIdentifier name _) = dpPackageIdent dp

toPackageLocation :: Maybe InstalledPackageLocation -> InstallLocation
toPackageLocation Nothing = Snap
toPackageLocation (Just ExtraGlobal) = Snap
toPackageLocation (Just (InstalledTo loc)) = loc
toInstallLocation :: PackageDbVariety -> InstallLocation
toInstallLocation GlobalDb = Snap
toInstallLocation ExtraDb = Snap
toInstallLocation WriteOnlyDb = Snap
toInstallLocation MutableDb = Local
38 changes: 27 additions & 11 deletions src/Stack/PackageDump.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,48 @@ instance Exception PackageDumpException where
, "."
]

-- | Call ghc-pkg dump with appropriate flags and stream to the given @Sink@,
-- for a single database
-- | Call @ghc-pkg dump@ with appropriate flags and stream to the given sink,
-- using either the global package database or the given package databases.
ghcPkgDump ::
(HasProcessContext env, HasTerm env)
=> GhcPkgExe
-> [Path Abs Dir] -- ^ if empty, use global
-> [Path Abs Dir]
-- ^ A list of package databases. If empty, use the global package
-- database.
-> ConduitM Text Void (RIO env) a
-- ^ Sink.
-> RIO env a
ghcPkgDump pkgexe = ghcPkgCmdArgs pkgexe ["dump"]

-- | Call ghc-pkg describe with appropriate flags and stream to the given
-- @Sink@, for a single database
-- | Call @ghc-pkg describe@ with appropriate flags and stream to the given
-- sink, using either the global package database or the given package
-- databases.
ghcPkgDescribe ::
(HasCompiler env, HasProcessContext env, HasTerm env)
=> GhcPkgExe
-> PackageName
-> [Path Abs Dir] -- ^ if empty, use global
-> [Path Abs Dir]
-- ^ A list of package databases. If empty, use the global package
-- database.
-> ConduitM Text Void (RIO env) a
-- ^ Sink.
-> RIO env a
ghcPkgDescribe pkgexe pkgName' = ghcPkgCmdArgs
pkgexe ["describe", "--simple-output", packageNameString pkgName']
pkgexe
["describe", "--simple-output", packageNameString pkgName']

-- | Call ghc-pkg and stream to the given @Sink@, for a single database
-- | Call @ghc-pkg@ and stream to the given sink, using the either the global
-- package database or the given package databases.
ghcPkgCmdArgs ::
(HasProcessContext env, HasTerm env)
=> GhcPkgExe
-> [String]
-> [Path Abs Dir] -- ^ if empty, use global
-- ^ A list of commands.
-> [Path Abs Dir]
-- ^ A list of package databases. If empty, use the global package
-- database.
-> ConduitM Text Void (RIO env) a
-- ^ Sink.
-> RIO env a
ghcPkgCmdArgs pkgexe@(GhcPkgExe pkgPath) cmd mpkgDbs sink = do
case reverse mpkgDbs of
Expand All @@ -95,8 +108,11 @@ ghcPkgCmdArgs pkgexe@(GhcPkgExe pkgPath) cmd mpkgDbs sink = do
args = concat
[ case mpkgDbs of
[] -> ["--global", "--no-user-package-db"]
_ -> ["--user", "--no-user-package-db"] ++
concatMap (\pkgDb -> ["--package-db", toFilePathNoTrailingSep pkgDb]) mpkgDbs
_ -> "--user"
: "--no-user-package-db"
: concatMap
(\pkgDb -> ["--package-db", toFilePathNoTrailingSep pkgDb])
mpkgDbs
, cmd
, ["--expand-pkgroot"]
]
Expand Down
Loading