Skip to content

Commit efe11b2

Browse files
committed
Remove globals that do not have their deps met commercialhaskell#949
1 parent 7b175ed commit efe11b2

4 files changed

Lines changed: 86 additions & 28 deletions

File tree

src/Stack/Build.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ build setLocalFiles mbuildLk bopts = do
9999
if boptsDryrun bopts
100100
then printPlan plan
101101
else executePlan menv bopts baseConfigOpts locals
102-
(Map.fromList $ map (\(x, y) -> (y, x)) $ Map.toList globallyRegistered)
102+
globallyRegistered
103103
sourceMap
104104
installedMap
105105
plan

src/Stack/Build/Execute.hs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Stack.Build.Execute
1717
) where
1818

1919
import Control.Applicative
20+
import Control.Arrow ((&&&))
2021
import Control.Concurrent.Execute
2122
import Control.Concurrent.Async (withAsync, wait)
2223
import Control.Concurrent.MVar.Lifted
@@ -69,6 +70,7 @@ import Stack.Types.Build
6970
import Stack.Fetch as Fetch
7071
import Stack.GhcPkg
7172
import Stack.Package
73+
import Stack.PackageDump
7274
import Stack.Constants
7375
import Stack.Types
7476
import Stack.Types.StackT
@@ -205,7 +207,7 @@ data ExecuteEnv = ExecuteEnv
205207
, eeLocals :: ![LocalPackage]
206208
, eeSourceMap :: !SourceMap
207209
, eeGlobalDB :: !(Path Abs Dir)
208-
, eeGlobalPackages :: !(Map PackageIdentifier GhcPkgId)
210+
, eeGlobalPackages :: ![DumpPackage () ()]
209211
}
210212

211213
-- | Get a compiled Setup exe
@@ -278,7 +280,7 @@ withExecuteEnv :: M env m
278280
-> BuildOpts
279281
-> BaseConfigOpts
280282
-> [LocalPackage]
281-
-> Map PackageIdentifier GhcPkgId -- ^ global packages
283+
-> [DumpPackage () ()] -- ^ global packages
282284
-> SourceMap
283285
-> (ExecuteEnv -> m a)
284286
-> m a
@@ -322,7 +324,7 @@ executePlan :: M env m
322324
-> BuildOpts
323325
-> BaseConfigOpts
324326
-> [LocalPackage]
325-
-> Map PackageIdentifier GhcPkgId -- ^ globals
327+
-> [DumpPackage () ()] -- ^ globals
326328
-> SourceMap
327329
-> InstalledMap
328330
-> Plan
@@ -701,19 +703,10 @@ withSingleContext runInBase ActionContext {..} ExecuteEnv {..} task@Task {..} md
701703
Just deps ->
702704
-- Stack always builds with the global Cabal for various
703705
-- reproducibility issues.
704-
let depsMinusCabal = filter (not . isPrefixOf "Cabal-")
705-
. map ghcPkgIdString
706-
. Map.elems
707-
. uniqueByName
708-
$ Map.union deps eeGlobalPackages
709-
-- We also provide all global packages to
710-
-- the Setup.hs file, see:
711-
-- https://github.com/commercialhaskell/stack/issues/941
712-
713-
-- We only want a single installation of each package name
714-
uniqueByName = Map.mapKeysWith
715-
const
716-
packageIdentifierName
706+
let depsMinusCabal
707+
= map ghcPkgIdString
708+
$ Set.toList
709+
$ addGlobalPackages deps eeGlobalPackages
717710
in
718711
"-clear-package-db"
719712
: "-global-package-db"
@@ -1289,3 +1282,71 @@ extraBuildOptions :: M env m => m [String]
12891282
extraBuildOptions = do
12901283
hpcIndexDir <- toFilePath . (</> dotHpc) <$> hpcRelativeDir
12911284
return ["--ghc-options", "-hpcdir " ++ hpcIndexDir ++ " -ddump-hi -ddump-to-file"]
1285+
1286+
-- | Take the given list of package dependencies and the contents of the global
1287+
-- package database, and construct a set of installed package IDs that:
1288+
--
1289+
-- * Excludes the Cabal library (it's added later)
1290+
--
1291+
-- * Includes all packages depended on by this package
1292+
--
1293+
-- * Includes all global packages, unless: (1) it's hidden, (2) it's shadowed
1294+
-- by a depended-on package, or (3) one of its dependencies is not met.
1295+
--
1296+
-- See:
1297+
--
1298+
-- * https://github.com/commercialhaskell/stack/issues/941
1299+
--
1300+
-- * https://github.com/commercialhaskell/stack/issues/944
1301+
--
1302+
-- * https://github.com/commercialhaskell/stack/issues/949
1303+
addGlobalPackages :: Map PackageIdentifier GhcPkgId -- ^ dependencies of the package
1304+
-> [DumpPackage () ()] -- ^ global packages
1305+
-> Set GhcPkgId
1306+
addGlobalPackages deps globals0 =
1307+
res
1308+
where
1309+
-- Initial set of packages: the installed IDs of all dependencies
1310+
res0 = Map.elems $ Map.filterWithKey (\ident _ -> not $ isCabal ident) deps
1311+
1312+
-- First check on globals: it's not shadowed by a dep, it's not Cabal, and
1313+
-- it's exposed
1314+
goodGlobal1 dp = not (isDep dp)
1315+
&& not (isCabal $ dpPackageIdent dp)
1316+
&& dpIsExposed dp
1317+
globals1 = filter goodGlobal1 globals0
1318+
1319+
-- Create a Map of unique package names in the global database
1320+
globals2 = Map.fromListWith chooseBest
1321+
$ map (packageIdentifierName . dpPackageIdent &&& id) globals1
1322+
1323+
-- Final result: add in globals that have their dependencies met
1324+
res = loop id (Map.elems globals2) $ Set.fromList res0
1325+
1326+
----------------------------------
1327+
-- Some auxiliary helper functions
1328+
----------------------------------
1329+
1330+
-- Is the given package identifier for any version of Cabal
1331+
isCabal (PackageIdentifier name _) = name == $(mkPackageName "Cabal")
1332+
1333+
-- Is the given package name provided by the package dependencies?
1334+
isDep dp = packageIdentifierName (dpPackageIdent dp) `Set.member` depNames
1335+
depNames = Set.map packageIdentifierName $ Map.keysSet deps
1336+
1337+
-- Choose the best of two competing global packages (the newest version)
1338+
chooseBest dp1 dp2
1339+
| getVer dp1 < getVer dp2 = dp2
1340+
| otherwise = dp1
1341+
where
1342+
getVer = packageIdentifierVersion . dpPackageIdent
1343+
1344+
-- Are all dependencies of the given package met by the given Set of
1345+
-- installed packages
1346+
depsMet dp gids = all (`Set.member` gids) (dpDepends dp)
1347+
1348+
-- Find all globals that have all of their dependencies met
1349+
loop _ [] gids = gids
1350+
loop front (dp:dps) gids
1351+
| depsMet dp gids = loop id (front dps) (Set.insert (dpGhcPkgId dp) gids)
1352+
| otherwise = loop (front . (dp:)) dps gids

src/Stack/Build/Installed.hs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,13 @@ data GetInstalledOpts = GetInstalledOpts
5757
-- ^ Require haddocks?
5858
}
5959

60-
type IsExposed = Bool
61-
6260
-- | Returns the new InstalledMap and all of the locally registered packages.
6361
getInstalled :: (M env m, PackageInstallInfo pii)
6462
=> EnvOverride
6563
-> GetInstalledOpts
6664
-> Map PackageName pii -- ^ does not contain any installed information
6765
-> m ( InstalledMap
68-
, Map GhcPkgId PackageIdentifier -- globally installed
66+
, [DumpPackage () ()] -- globally installed
6967
, Map GhcPkgId PackageIdentifier -- locally installed
7068
)
7169
getInstalled menv opts sourceMap = do
@@ -114,8 +112,8 @@ getInstalled menv opts sourceMap = do
114112
]
115113

116114
return ( installedMap
117-
, Map.map fst $ Map.filter snd globalInstalled
118-
, Map.map fst localInstalled
115+
, globalInstalled
116+
, Map.fromList $ map (dpGhcPkgId &&& dpPackageIdent) localInstalled
119117
)
120118

121119
-- | Outputs both the modified InstalledMap and the Set of all installed packages in this database
@@ -130,18 +128,18 @@ loadDatabase :: (M env m, PackageInstallInfo pii)
130128
-> Map PackageName pii -- ^ to determine which installed things we should include
131129
-> Maybe (InstallLocation, Path Abs Dir) -- ^ package database, Nothing for global
132130
-> [LoadHelper] -- ^ from parent databases
133-
-> m ([LoadHelper], Map GhcPkgId (PackageIdentifier, IsExposed))
131+
-> m ([LoadHelper], [DumpPackage () ()])
134132
loadDatabase menv opts mcache sourceMap mdb lhs0 = do
135133
wc <- getWhichCompiler
136-
(lhs1, gids) <- ghcPkgDump menv wc (fmap snd mdb)
134+
(lhs1, dps) <- ghcPkgDump menv wc (fmap snd mdb)
137135
$ conduitDumpPackage =$ sink
138136
let lhs = pruneDeps
139137
id
140138
lhId
141139
lhDeps
142140
const
143141
(lhs0 ++ lhs1)
144-
return (map (\lh -> lh { lhDeps = [] }) $ Map.elems lhs, Map.fromList gids)
142+
return (map (\lh -> lh { lhDeps = [] }) $ Map.elems lhs, dps)
145143
where
146144
conduitProfilingCache =
147145
case mcache of
@@ -159,10 +157,9 @@ loadDatabase menv opts mcache sourceMap mdb lhs0 = do
159157
=$ conduitHaddockCache
160158
=$ CL.mapMaybe (isAllowed opts mcache sourceMap (fmap fst mdb))
161159
=$ CL.consume
162-
sinkGIDs = CL.map (dpGhcPkgId &&& (dpPackageIdent &&& dpIsExposed)) =$ CL.consume
163160
sink = getZipSink $ (,)
164161
<$> ZipSink sinkDP
165-
<*> ZipSink sinkGIDs
162+
<*> ZipSink CL.consume
166163

167164
-- | Check if a can be included in the set of installed packages or not, based
168165
-- on the package selections made by the user. This does not perform any

src/Stack/SDist.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ getSDistFileList lp =
114114
(_, _mbp, locals, _extraToBuild, sourceMap) <- loadSourceMap NeedTargets bopts
115115
runInBase <- liftBaseWith $ \run -> return (void . run)
116116
withExecuteEnv menv bopts baseConfigOpts locals
117-
Map.empty -- provide empty list of globals. This is a hack around custom Setup.hs files
117+
[] -- provide empty list of globals. This is a hack around custom Setup.hs files
118118
sourceMap $ \ee -> do
119119
withSingleContext runInBase ac ee task Nothing (Just "sdist") $ \_package _cabalfp _pkgDir cabal _announce _console _mlogFile -> do
120120
let outFile = tmpdir FP.</> "source-files-list"

0 commit comments

Comments
 (0)