Skip to content

Commit a0affbc

Browse files
authored
Merge pull request #6049 from commercialhaskell/fix6046
Fix #6046 Unregister local packages for sub libraries
2 parents bc7c17c + 7bbcc9f commit a0affbc

File tree

9 files changed

+148
-23
lines changed

9 files changed

+148
-23
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Bug fixes:
3636
* `stack build` with `--file-watch` or `--file-watch-poll` outputs 'pretty'
3737
error messages, as intended. See
3838
[#5978](https://github.com/commercialhaskell/stack/issues/5978).
39+
* `stack build` unregisters any local packages for the sub libraries of a local
40+
package that is to be unregistered. See
41+
[#6046](https://github.com/commercialhaskell/stack/issues/6046).
3942

4043
## v2.9.3
4144

src/Stack/Build/ConstructPlan.hs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ module Stack.Build.ConstructPlan
99
) where
1010

1111
import Control.Monad.RWS.Strict hiding ( (<>) )
12-
import Control.Monad.State.Strict ( execState )
1312
import qualified Data.List as L
1413
import qualified Data.Map.Strict as M
1514
import qualified Data.Map.Strict as Map
@@ -21,6 +20,7 @@ import Distribution.Types.PackageName ( mkPackageName )
2120
import Generics.Deriving.Monoid ( memptydefault, mappenddefault )
2221
import Path ( parent )
2322
import RIO.Process ( HasProcessContext (..), findExecutable )
23+
import RIO.State ( State, execState )
2424
import Stack.Build.Cache ( tryGetFlagCache )
2525
import Stack.Build.Haddock ( shouldHaddockDeps )
2626
import Stack.Build.Source ( loadLocalPackage )
@@ -363,7 +363,7 @@ data UnregisterState = UnregisterState
363363
}
364364

365365
-- | Determine which packages to unregister based on the given tasks and
366-
-- already registered local packages
366+
-- already registered local packages.
367367
mkUnregisterLocal ::
368368
Map PackageName Task
369369
-- ^ Tasks
@@ -376,12 +376,18 @@ mkUnregisterLocal ::
376376
-- unregister target packages.
377377
-> Map GhcPkgId (PackageIdentifier, Text)
378378
mkUnregisterLocal tasks dirtyReason localDumpPkgs initialBuildSteps =
379-
-- We'll take multiple passes through the local packages. This
380-
-- will allow us to detect that a package should be unregistered,
381-
-- as well as all packages directly or transitively depending on
382-
-- it.
379+
-- We'll take multiple passes through the local packages. This will allow us
380+
-- to detect that a package should be unregistered, as well as all packages
381+
-- directly or transitively depending on it.
383382
loop Map.empty localDumpPkgs
384383
where
384+
loop ::
385+
Map GhcPkgId (PackageIdentifier, Text)
386+
-- ^ Current local packages to unregister.
387+
-> [DumpPackage]
388+
-- ^ Current local packages to keep.
389+
-> Map GhcPkgId (PackageIdentifier, Text)
390+
-- ^ Revised local packages to unregister.
385391
loop toUnregister keep
386392
-- If any new packages were added to the unregister Map, we need to loop
387393
-- through the remaining packages again to detect if a transitive dependency
@@ -393,43 +399,71 @@ mkUnregisterLocal tasks dirtyReason localDumpPkgs initialBuildSteps =
393399
where
394400
-- Run the unregister checking function on all packages we currently think
395401
-- we'll be keeping.
396-
us = execState (mapM_ go keep) UnregisterState
402+
us = execState (mapM_ go keep) initialUnregisterState
403+
initialUnregisterState = UnregisterState
397404
{ usToUnregister = toUnregister
398405
, usKeep = []
399406
, usAnyAdded = False
400407
}
401408

409+
go :: DumpPackage -> State UnregisterState ()
402410
go dp = do
403411
us <- get
404-
case go' (usToUnregister us) ident deps of
405-
-- Not unregistering, add it to the keep list
412+
case maybeUnregisterReason (usToUnregister us) ident mParentLibId deps of
413+
-- Not unregistering, add it to the keep list.
406414
Nothing -> put us { usKeep = dp : usKeep us }
407-
-- Unregistering, add it to the unregister Map and indicate that a package
408-
-- was in fact added to the unregister Map so we loop again.
415+
-- Unregistering, add it to the unregister Map; and indicate that a
416+
-- package was in fact added to the unregister Map, so we loop again.
409417
Just reason -> put us
410418
{ usToUnregister = Map.insert gid (ident, reason) (usToUnregister us)
411419
, usAnyAdded = True
412420
}
413421
where
414422
gid = dpGhcPkgId dp
415423
ident = dpPackageIdent dp
424+
mParentLibId = dpParentLibIdent dp
416425
deps = dpDepends dp
417426

418-
go' toUnregister ident deps
419-
-- If we're planning on running a task on it, then it must be unregistered,
420-
-- unless it's a target and an initial-build-steps build is being done.
421-
| Just task <- Map.lookup name tasks
422-
= if initialBuildSteps && taskIsTarget task && taskProvides task == ident
423-
then Nothing
424-
else Just $ fromMaybe "" $ Map.lookup name dirtyReason
427+
maybeUnregisterReason ::
428+
Map GhcPkgId (PackageIdentifier, Text)
429+
-- ^ Current local packages to unregister.
430+
-> PackageIdentifier
431+
-- ^ Package identifier.
432+
-> Maybe PackageIdentifier
433+
-- ^ If package for sub library, package identifier of the parent.
434+
-> [GhcPkgId]
435+
-- ^ Dependencies of the package.
436+
-> Maybe Text
437+
-- ^ If to be unregistered, the reason for doing so.
438+
maybeUnregisterReason toUnregister ident mParentLibId deps
439+
-- If the package is not for a sub library, then it is directly relevant. If
440+
-- it is, then the relevant package is the parent. If we are planning on
441+
-- running a task on the relevant package, then the package must be
442+
-- unregistered, unless it is a target and an initial-build-steps build is
443+
-- being done.
444+
| Just task <- Map.lookup relevantPkgName tasks =
445+
if initialBuildSteps
446+
&& taskIsTarget task
447+
&& taskProvides task == relevantPkgId
448+
then Nothing
449+
else Just $ fromMaybe "" $ Map.lookup relevantPkgName dirtyReason
425450
-- Check if a dependency is going to be unregistered
426-
| (dep, _):_ <- mapMaybe (`Map.lookup` toUnregister) deps
427-
= Just $ "Dependency being unregistered: " <> T.pack (packageIdentifierString dep)
451+
| (dep, _):_ <- mapMaybe (`Map.lookup` toUnregister) deps =
452+
Just $ "Dependency being unregistered: "
453+
<> T.pack (packageIdentifierString dep)
428454
-- None of the above, keep it!
429455
| otherwise = Nothing
430456
where
431-
name :: PackageName
432-
name = pkgName ident
457+
-- If the package is not for a sub library, then the relevant package
458+
-- identifier is that of the package. If it is, then the relevant package
459+
-- identifier is that of the parent.
460+
relevantPkgId :: PackageIdentifier
461+
relevantPkgId = fromMaybe ident mParentLibId
462+
-- If the package is not for a sub library, then the relevant package name
463+
-- is that of the package. If it is, then the relevant package name is
464+
-- that of the parent.
465+
relevantPkgName :: PackageName
466+
relevantPkgName = maybe (pkgName ident) pkgName mParentLibId
433467

434468
-- | Given a 'LocalPackage' and its 'lpTestBench', adds a 'Task' for running its
435469
-- tests and benchmarks.

src/Stack/Types/Config.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2335,17 +2335,27 @@ newtype GhcPkgExe
23352335
getGhcPkgExe :: HasCompiler env => RIO env GhcPkgExe
23362336
getGhcPkgExe = view $ compilerPathsL.to cpPkg
23372337

2338-
-- | Dump information for a single package
2338+
-- | Type representing dump information for a single package, as output by the
2339+
-- @ghc-pkg describe@ command.
23392340
data DumpPackage = DumpPackage
23402341
{ dpGhcPkgId :: !GhcPkgId
2342+
-- ^ The @id@ field.
23412343
, dpPackageIdent :: !PackageIdentifier
2344+
-- ^ The @name@ and @version@ fields. The @name@ field is the munged package
2345+
-- name. If the package is not for a sub library, its munged name is its
2346+
-- name.
23422347
, dpParentLibIdent :: !(Maybe PackageIdentifier)
2348+
-- ^ The @package-name@ and @version@ fields, if @package-name@ is present.
2349+
-- That field is present if the package is for a sub library.
23432350
, dpLicense :: !(Maybe C.License)
23442351
, dpLibDirs :: ![FilePath]
2352+
-- ^ The @library-dirs@ field.
23452353
, dpLibraries :: ![Text]
2354+
-- ^ The @hs-libraries@ field.
23462355
, dpHasExposedModules :: !Bool
23472356
, dpExposedModules :: !(Set ModuleName)
23482357
, dpDepends :: ![GhcPkgId]
2358+
-- ^ The @depends@ field (packages on which this package depends).
23492359
, dpHaddockInterfaces :: ![FilePath]
23502360
, dpHaddockHtml :: !(Maybe FilePath)
23512361
, dpIsExposed :: !Bool
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import StackTest
2+
3+
-- This tests building a package with a library and an internal sub library,
4+
-- where the library depends on the sub library, first version 0.1.0.0 (the
5+
-- Cabal file is @foo.cabal1@) and then version 0.2.0.0 (the Cabal file is
6+
-- @foo.cabal2@).
7+
main :: IO ()
8+
main = do
9+
copy "foo.cabal1" "foo.cabal"
10+
stack ["build"]
11+
copy "foo.cabal2" "foo.cabal"
12+
stack ["build"]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cabal-version: 2.0
2+
name: foo
3+
version: 0.1.0.0
4+
build-type: Simple
5+
6+
library
7+
exposed-modules:
8+
Lib
9+
other-modules:
10+
Sub
11+
hs-source-dirs:
12+
src
13+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
14+
build-depends:
15+
base >=4.7 && <5
16+
, sub
17+
default-language: Haskell2010
18+
19+
library sub
20+
exposed-modules:
21+
Sub
22+
hs-source-dirs:
23+
src
24+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
25+
build-depends:
26+
base >=4.7 && <5
27+
default-language: Haskell2010
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cabal-version: 2.0
2+
name: foo
3+
version: 0.2.0.0
4+
build-type: Simple
5+
6+
library
7+
exposed-modules:
8+
Lib
9+
other-modules:
10+
Sub
11+
hs-source-dirs:
12+
src
13+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
14+
build-depends:
15+
base >=4.7 && <5
16+
, sub
17+
default-language: Haskell2010
18+
19+
library sub
20+
exposed-modules:
21+
Sub
22+
hs-source-dirs:
23+
src
24+
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
25+
build-depends:
26+
base >=4.7 && <5
27+
default-language: Haskell2010
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Lib
2+
( someFunc
3+
) where
4+
5+
import Sub ( someFunc )
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Sub
2+
( someFunc
3+
) where
4+
5+
someFunc :: IO ()
6+
someFunc = putStrLn "someFunc"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
resolver: lts-20.8

0 commit comments

Comments
 (0)