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

Fix Cabal version selection for build-type:Custom #108

Merged
merged 5 commits into from
May 2, 2020
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
6 changes: 6 additions & 0 deletions cabal-helper.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ extra-source-files: README.md
tests/fliblib/stack.yaml
tests/fliblib/lib/*.hs

tests/custom-setup/*.hs
tests/custom-setup/*.cabal
tests/custom-setup/packages.list
tests/custom-setup/stack.yaml

tests/bkpregex/*.hs
tests/bkpregex/*.cabal
tests/bkpregex/packages.list
Expand Down Expand Up @@ -137,6 +142,7 @@ common c-h-internal
CabalHelper.Compiletime.Program.GHC
CabalHelper.Compiletime.Sandbox
CabalHelper.Compiletime.Types
CabalHelper.Compiletime.Types.Cabal
CabalHelper.Compiletime.Types.RelativePath
CabalHelper.Runtime.Compat
CabalHelper.Runtime.HelperMain
Expand Down
193 changes: 109 additions & 84 deletions lib/Distribution/Helper.hs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ import CabalHelper.Compiletime.Log
import CabalHelper.Compiletime.Process
import CabalHelper.Compiletime.Sandbox
import CabalHelper.Compiletime.Types
import CabalHelper.Compiletime.Types.Cabal
import CabalHelper.Compiletime.Types.RelativePath
import CabalHelper.Shared.InterfaceTypes
import CabalHelper.Shared.Common
Expand Down Expand Up @@ -281,19 +282,25 @@ getUnitModTimes
package_yaml_path = pSourceDir </> "package.yaml"
setup_config_path = distdirv1 </> "setup-config"

-- | Get a random unit from the project. Sometimes we need to get info we
-- can only get after configuring _any_ unit but we do assume that this
-- info is uniform across units.
someUnit :: ProjInfo pt -> Unit pt
someUnit proj_info =
NonEmpty.head $ pUnits $
NonEmpty.head $ piPackages proj_info

-- | The version of GHC the project is configured to use for compilation.
compilerVersion :: Query pt (String, Version)
compilerVersion = Query $ \qe ->
getProjInfo qe >>= \proj_info ->
let someUnit = NonEmpty.head $ pUnits $
NonEmpty.head $ piPackages proj_info in
let unit = someUnit proj_info in
-- ^ ASSUMPTION: Here we assume the compiler version is uniform across all
-- units so we just pick any one.
case piImpl proj_info of
ProjInfoV1 {} -> uiCompilerId <$> getUnitInfo qe someUnit
ProjInfoV1 {} -> uiCompilerId <$> getUnitInfo qe unit
ProjInfoV2 { piV2CompilerId } -> return piV2CompilerId
ProjInfoStack {} -> uiCompilerId <$> getUnitInfo qe someUnit
ProjInfoStack {} -> uiCompilerId <$> getUnitInfo qe unit

-- | All local packages currently active in a project\'s build plan.
projectPackages :: Query pt (NonEmpty (Package pt))
Expand Down Expand Up @@ -409,6 +416,25 @@ getProjInfo qe = do
readProjInfo qe proj_conf mtime pre_info
}


-- | Get the cabal version we need to build for this project.
getCabalLibVersion :: QueryEnv pt -> Reconfigured pt -> ProjInfo pt -> IO CabalVersion
getCabalLibVersion _ _ ProjInfo{piImpl=ProjInfoV1 {piV1CabalVersion}} =
return piV1CabalVersion
getCabalLibVersion qe reconf proj_info = do
unit <- case reconf of
AlreadyReconfigured unit ->
return unit
Haven'tReconfigured -> do
let unit = someUnit proj_info
reconfigureUnit qe unit
return unit
let DistDirLib distdir = uDistDir $ unit
hdr <- readSetupConfigHeader $ distdir </> "setup-config"
let ("Cabal", cabalVer) = uhSetupId hdr
return $ CabalVersion cabalVer


getUnitInfo :: QueryEnv pt -> Unit pt -> IO UnitInfo
getUnitInfo qe@QueryEnv{..} unit@Unit{uDistDir} = do
pre_info <- getPreInfo qe
Expand All @@ -426,8 +452,9 @@ getUnitInfo qe@QueryEnv{..} unit@Unit{uDistDir} = do
, cKeyValid = (==)

, cRegen = \mtimes -> do
reconfigureUnit qe unit
helper <- getHelper pre_info proj_info qe
reconf <- reconfigureUnit qe unit
cabal_ver <- getCabalLibVersion qe reconf proj_info
helper <- getHelper qe pre_info proj_info cabal_ver
readUnitInfo helper unit mtimes
}

Expand Down Expand Up @@ -456,8 +483,11 @@ shallowReconfigureProject QueryEnv
shallowReconfigureProject qe = do
buildProjectTarget qe Nothing DryRun

reconfigureUnit :: QueryEnvI c pt -> Unit pt -> IO ()
reconfigureUnit qe u = buildProjectTarget qe (Just u) OnlyCfg
data Reconfigured pt = AlreadyReconfigured (Unit pt) | Haven'tReconfigured
reconfigureUnit :: QueryEnvI c pt -> Unit pt -> IO (Reconfigured pt)
reconfigureUnit qe u = do
buildProjectTarget qe (Just u) OnlyCfg
return (AlreadyReconfigured u)

buildUnits :: [Unit pt] -> Query pt ()
buildUnits units = Query $ \qe -> do
Expand Down Expand Up @@ -488,6 +518,8 @@ buildProjectTarget qe mu stage = do
cmd <- return $ case stage of
DryRun | SCV1 <- cpt ->
CabalInstall.CIConfigure
-- TODO: in v1 we configure twice because we do configure for
-- DryRun and OnlyCfg.
OnlyCfg ->
CabalInstall.CIConfigure
_ ->
Expand All @@ -502,7 +534,7 @@ buildProjectTarget qe mu stage = do
Just Unit{uImpl} -> concat
[ if uiV2OnlyDependencies uImpl
then ["--only-dependencies"] else []
, uiV2Components uImpl
, map snd $ filter ((/= ChSetupHsName) . fst) $ uiV2Components uImpl
]
case qeProjLoc of
ProjLocV2File {plCabalProjectFile} ->
Expand Down Expand Up @@ -537,43 +569,39 @@ getFileModTime f = do

readProjInfo
:: QueryEnvI c pt -> ProjConf pt -> ProjConfModTimes -> PreInfo pt -> IO (ProjInfo pt)
readProjInfo qe pc pcm pi = withVerbosity $ do
readProjInfo qe pc pcm _pi = withVerbosity $ do
let projloc = qeProjLoc qe
case (qeDistDir qe, pc) of
(DistDirCabal SCV1 distdir, ProjConfV1{pcV1CabalFile}) -> do
setup_config_path <- canonicalizePath (distdir </> "setup-config")
mhdr <- readSetupConfigHeader setup_config_path
case mhdr of
Just hdr@(UnitHeader (pkg_name_bs, _pkg_ver) ("Cabal", hdrCabalVersion) _compId) -> do
let
v3_0_0_0 = makeVersion [3,0,0,0]
pkg_name
| hdrCabalVersion >= v3_0_0_0 = BSU.toString pkg_name_bs
| otherwise = BS8.unpack pkg_name_bs
pkg = Package
{ pPackageName = pkg_name
, pSourceDir = plCabalProjectDir projloc
, pCabalFile = CabalFile pcV1CabalFile
, pFlags = []
, pUnits = (:|[]) Unit
{ uUnitId = UnitId pkg_name
, uPackage = pkg { pUnits = () }
, uDistDir = DistDirLib distdir
, uImpl = UnitImplV1
}
}
piImpl = ProjInfoV1 { piV1SetupHeader = hdr }
return ProjInfo
{ piCabalVersion = hdrCabalVersion
, piProjConfModTimes = pcm
, piPackages = pkg :| []
, piImpl
hdr@(UnitHeader (pkg_name_bs, _pkg_ver) ("Cabal", hdrCabalVersion) _)
<- readSetupConfigHeader setup_config_path
let
v3_0_0_0 = makeVersion [3,0,0,0]
pkg_name
| hdrCabalVersion >= v3_0_0_0 = BSU.toString pkg_name_bs
| otherwise = BS8.unpack pkg_name_bs
pkg = Package
{ pPackageName = pkg_name
, pSourceDir = plCabalProjectDir projloc
, pCabalFile = CabalFile pcV1CabalFile
, pFlags = []
, pUnits = (:|[]) Unit
{ uUnitId = UnitId pkg_name
, uPackage = pkg { pUnits = () }
, uDistDir = DistDirLib distdir
, uImpl = UnitImplV1
}
Just UnitHeader {uhSetupId=(setup_name, _)} ->
panicIO $ printf "Unknown Setup package-id in setup-config header '%s': '%s'"
(BS8.unpack setup_name) setup_config_path
Nothing ->
panicIO $ printf "Could not read '%s' header" setup_config_path
}
piImpl = ProjInfoV1
{ piV1SetupHeader = hdr
, piV1CabalVersion = CabalVersion hdrCabalVersion
}
return ProjInfo
{ piProjConfModTimes = pcm
, piPackages = pkg :| []
, piImpl
}

(DistDirCabal SCV2 distdirv2, _) -> do
let plan_path = distdirv2 </> "cache" </> "plan.json"
Expand All @@ -590,8 +618,7 @@ readProjInfo qe pc pcm pi = withVerbosity $ do

Just pkgs <- NonEmpty.nonEmpty <$> CabalInstall.planPackages plan
return ProjInfo
{ piCabalVersion = makeDataVersion pjCabalLibVersion
, piProjConfModTimes = pcm
{ piProjConfModTimes = pcm
, piPackages = NonEmpty.sortWith pPackageName pkgs
, piImpl = ProjInfoV2
{ piV2Plan = plan
Expand All @@ -602,33 +629,26 @@ readProjInfo qe pc pcm pi = withVerbosity $ do
(DistDirStack{}, _) -> do
Just cabal_files <- NonEmpty.nonEmpty <$> Stack.listPackageCabalFiles qe
pkgs <- mapM (Stack.getPackage qe) cabal_files
Just (cabalVer:_) <- runMaybeT $
let ?progs = qePrograms qe in
let PreInfoStack {piStackProjPaths} = pi in
GHC.listCabalVersions (Just (sppGlobalPkgDb piStackProjPaths))
-- ^ See [Note Stack Cabal Version]
return ProjInfo
{ piCabalVersion = cabalVer
, piProjConfModTimes = pcm
{ piProjConfModTimes = pcm
, piPackages = NonEmpty.sortWith pPackageName pkgs
, piImpl = ProjInfoStack
}

-- [Note Stack Cabal Version]
--
-- Stack just uses ghc-pkg on the global-pkg-db to determine the
-- appropriate Cabal version for a resolver when building, see
-- Stack.Setup.pathsFromCompiler(cabalPkgVer). We do essentially the same
-- thing here.
--
-- The code for building Setup.hs is in Stack.Build.Execute and the version
-- of cabal is set in withSingleContext.withCabal.getPackageArgs.
--
-- Note there is some special casing going on (see 'depsMinusCabal'), they
-- use the packages from the snapshot pkg-db except Cabal which comes from
-- the global pkg-db.

readUnitInfo :: Helper pt -> Unit pt -> UnitModTimes -> IO UnitInfo
readUnitInfo helper u@Unit{uImpl=ui@UnitImplV2{uiV2Components}} umt
| ChSetupHsName `elem` map fst uiV2Components = do
let unit' = u {
uImpl = ui
{ uiV2Components = filter ((/= ChSetupHsName) . fst) uiV2Components
}
}
-- TODO: Add a synthetic UnitInfo for the setup executable. Cabal
-- doesn't allow building it via a target on the cmdline and it
-- doesn't really exist as far as setup-config is concerned but
-- plan.json has the dependency versions for custom-setup so we
-- should be able to represet that as a UnitInfo.
readUnitInfo helper unit' umt
readUnitInfo helper unit@Unit {uUnitId=uiUnitId} uiModTimes = do
res <- runHelper helper unit
[ "package-id"
Expand Down Expand Up @@ -698,7 +718,8 @@ prepare :: Query pt ()
prepare = Query $ \qe -> do
pre_info <- getPreInfo qe
proj_info <- getProjInfo qe
void $ getHelper pre_info proj_info qe
cabal_ver <- getCabalLibVersion qe Haven'tReconfigured proj_info
void $ getHelper qe pre_info proj_info cabal_ver

-- | Create @cabal_macros.h@, @Paths_\<pkg\>.hs@ and other generated files
-- in the usual place. See 'Distribution.Simple.Build.initialBuildSteps'.
Expand All @@ -709,7 +730,8 @@ writeAutogenFiles :: Unit pt -> Query pt ()
writeAutogenFiles unit = Query $ \qe -> do
pre_info <- getPreInfo qe
proj_info <- getProjInfo qe
helper <- getHelper pre_info proj_info qe
cabal_ver <- getCabalLibVersion qe Haven'tReconfigured proj_info
helper <- getHelper qe pre_info proj_info cabal_ver
void $ runHelper helper unit ["write-autogen-files"]

-- | Get the path to the sandbox package-db in a project
Expand Down Expand Up @@ -766,19 +788,19 @@ configurePrograms qe@QueryEnv{..} pre_info = withVerbosity $ do
newtype Helper pt
= Helper { runHelper :: Unit pt -> [String] -> IO [Maybe ChResponse] }

getHelper :: PreInfo pt -> ProjInfo pt -> QueryEnvI c pt -> IO (Helper pt)
getHelper _pre_info ProjInfo{piCabalVersion} qe@QueryEnv{..}
| piCabalVersion == bultinCabalVersion = return $ Helper $
getHelper :: QueryEnvI c pt -> PreInfo pt -> ProjInfo pt -> CabalVersion -> IO (Helper pt)
getHelper qe@QueryEnv{..} _pre_info _proj_info cabal_ver
| cabal_ver == bultinCabalVersion = return $ Helper $
\Unit{ uDistDir=DistDirLib distdir
, uPackage=Package{pCabalFile=CabalFile cabal_file}
} args ->
let pt = dispHelperProjectType (projTypeOfQueryEnv qe) in
helper_main $ cabal_file : distdir : pt : args
getHelper pre_info proj_info qe@QueryEnv{..} = do
getHelper qe@QueryEnv{..} pre_info proj_info cabal_ver = do
withVerbosity $ do
let ?progs = qePrograms
t0 <- Clock.getTime Monotonic
eexe <- compileHelper $ mkCompHelperEnv qeProjLoc qeDistDir pre_info proj_info
eexe <- compileHelper $ mkCompHelperEnv qeProjLoc qeDistDir pre_info proj_info cabal_ver
t1 <- Clock.getTime Monotonic
let dt = (/10^9) $ fromInteger $ Clock.toNanoSecs $ Clock.diffTimeSpec t0 t1
dt :: Float
Expand All @@ -805,49 +827,52 @@ mkCompHelperEnv
-> DistDir pt
-> PreInfo pt
-> ProjInfo pt
-> CabalVersion
-> CompHelperEnv
mkCompHelperEnv
projloc
(DistDirCabal SCV1 distdir)
PreInfoCabal
ProjInfo{piCabalVersion}
ProjInfo {}
cabal_ver
= CompHelperEnv
{ cheCabalVer = CabalVersion piCabalVersion
{ cheCabalVer = cabal_ver
, cheProjDir = plCabalProjectDir projloc
, cheProjLocalCacheDir = distdir
, chePkgDb = Nothing
, chePlanJson = Nothing
, chePkgDb = []
, chePjUnits = Nothing
, cheDistV2 = Nothing
}
mkCompHelperEnv
projloc
(DistDirCabal SCV2 distdir)
PreInfoCabal
ProjInfo{piImpl=ProjInfoV2{piV2Plan=plan}}
cabal_ver
= CompHelperEnv {..}
where
cheProjDir = plCabalProjectDir projloc
cheCabalVer = CabalVersion $ makeDataVersion pjCabalLibVersion
cheCabalVer = cabal_ver
cheProjLocalCacheDir = distdir </> "cache"
chePkgDb = Nothing
chePlanJson = Just plan
chePkgDb = []
chePjUnits = Just $ pjUnits plan
cheDistV2 = Just distdir
PlanJson {pjCabalLibVersion=Ver pjCabalLibVersion } = plan
mkCompHelperEnv
(ProjLocStackYaml stack_yaml)
(DistDirStack mworkdir)
PreInfoStack
{ piStackProjPaths=StackProjPaths
{ sppGlobalPkgDb }
{ sppGlobalPkgDb, sppSnapPkgDb, sppLocalPkgDb }
}
ProjInfo { piCabalVersion }
ProjInfo {}
cabal_ver
= let workdir = fromMaybe ".stack-work" $ unRelativePath <$> mworkdir in
let projdir = takeDirectory stack_yaml in
CompHelperEnv
{ cheCabalVer = CabalVersion $ piCabalVersion
{ cheCabalVer = cabal_ver
, cheProjDir = projdir
, cheProjLocalCacheDir = projdir </> workdir
, chePkgDb = Just sppGlobalPkgDb
, chePlanJson = Nothing
, chePkgDb = [sppGlobalPkgDb, sppSnapPkgDb, sppLocalPkgDb]
, chePjUnits = Nothing
, cheDistV2 = Nothing
}
Loading