From 4466310e48e8c401ca2492d0fc2c5018ad8de961 Mon Sep 17 00:00:00 2001 From: alexbiehl Date: Wed, 21 Mar 2018 17:27:28 +0100 Subject: [PATCH] Haddock: Generate haddock for components Currently settings `documentation: true` enables documentation generation via haddock for your whole package, including tests and benchmarks. However, there are additional flags to control generation of documentation for this "second class" documentation targets, which are currently not honored at the cabal-install side of things. Namely, `tests`, `benchmarks`, `executables`, etc. provided under the `haddock` section in your `$CABAL_HOME/config`. This patch adds a more sensible approach to documentation generation via haddock. Also enabling `new-haddock` to generate documentation for single components instead whole packages. The behaviour works like this: - Setting `documentation: true` or passing `--enable-documentation` to cabal-install enable documentation for any component in the build plan honoring the respective flags for tests, benchmarks, exes, foreignlibs, etc. - Invoking new-haddock with a target selector will make sure the respective flags for "second class" doc targets are set correctly. E.g. $ new-haddock tests Will generate documentation for the testsuite of your package event if you have `tests: false` in your haddock section. --- Cabal/Distribution/Simple.hs | 2 +- Cabal/Distribution/Simple/Haddock.hs | 16 +++++- Cabal/Distribution/Simple/Setup.hs | 12 ++-- Cabal/Distribution/Simple/UserHooks.hs | 2 +- cabal-install/Distribution/Client/Config.hs | 3 +- .../Distribution/Client/ProjectBuilding.hs | 12 ++-- .../Client/ProjectConfig/Legacy.hs | 3 +- .../Distribution/Client/ProjectPlanning.hs | 56 ++++++++++++++++--- .../Client/ProjectPlanning/Types.hs | 22 ++++++++ 9 files changed, 107 insertions(+), 21 deletions(-) diff --git a/Cabal/Distribution/Simple.hs b/Cabal/Distribution/Simple.hs index e45c8312ac5..4d348d94983 100644 --- a/Cabal/Distribution/Simple.hs +++ b/Cabal/Distribution/Simple.hs @@ -329,7 +329,7 @@ haddockAction hooks flags args = do hookedAction preHaddock haddockHook postHaddock (return lbi { withPrograms = progs }) - hooks flags' args + hooks flags' { haddockArgs = args } args cleanAction :: UserHooks -> CleanFlags -> Args -> IO () cleanAction hooks flags args = do diff --git a/Cabal/Distribution/Simple/Haddock.hs b/Cabal/Distribution/Simple/Haddock.hs index 0a40a877712..afbd59c9dfc 100644 --- a/Cabal/Distribution/Simple/Haddock.hs +++ b/Cabal/Distribution/Simple/Haddock.hs @@ -36,6 +36,8 @@ import Distribution.Types.ForeignLib import Distribution.Types.UnqualComponentName import Distribution.Types.ComponentLocalBuildInfo import Distribution.Types.ExecutableScope +import Distribution.Types.LocalBuildInfo +import Distribution.Types.TargetInfo import Distribution.Package import qualified Distribution.ModuleName as ModuleName import Distribution.PackageDescription as PD hiding (Flag) @@ -46,6 +48,7 @@ import Distribution.Simple.Program import Distribution.Simple.PreProcess import Distribution.Simple.Setup import Distribution.Simple.Build +import Distribution.Simple.BuildTarget import Distribution.Simple.InstallDirs import Distribution.Simple.LocalBuildInfo hiding (substPathTemplate) import Distribution.Simple.BuildPaths @@ -199,7 +202,18 @@ haddock pkg_descr lbi suffixes flags' = do , fromFlags (haddockTemplateEnv lbi (packageId pkg_descr)) flags , fromPackageDescription haddockTarget pkg_descr ] - withAllComponentsInBuildOrder pkg_descr lbi $ \component clbi -> do + targets <- readTargetInfos verbosity pkg_descr lbi (haddockArgs flags) + + let + targets' = + case targets of + [] -> allTargetsInBuildOrder' pkg_descr lbi + _ -> targets + + for_ targets' $ \target -> do + let component = targetComponent target + clbi = targetCLBI target + componentInitialBuildSteps (flag haddockDistPref) pkg_descr lbi clbi verbosity preprocessComponent pkg_descr component lbi clbi False verbosity suffixes let diff --git a/Cabal/Distribution/Simple/Setup.hs b/Cabal/Distribution/Simple/Setup.hs index 5fa0e993a73..241883b7fbf 100644 --- a/Cabal/Distribution/Simple/Setup.hs +++ b/Cabal/Distribution/Simple/Setup.hs @@ -1470,7 +1470,8 @@ data HaddockFlags = HaddockFlags { haddockDistPref :: Flag FilePath, haddockKeepTempFiles:: Flag Bool, haddockVerbosity :: Flag Verbosity, - haddockCabalFilePath :: Flag FilePath + haddockCabalFilePath :: Flag FilePath, + haddockArgs :: [String] } deriving (Show, Generic) @@ -1494,7 +1495,8 @@ defaultHaddockFlags = HaddockFlags { haddockDistPref = NoFlag, haddockKeepTempFiles= Flag False, haddockVerbosity = Flag normal, - haddockCabalFilePath = mempty + haddockCabalFilePath = mempty, + haddockArgs = mempty } haddockCommand :: CommandUI HaddockFlags @@ -1504,8 +1506,10 @@ haddockCommand = CommandUI , commandDescription = Just $ \_ -> "Requires the program haddock, version 2.x.\n" , commandNotes = Nothing - , commandUsage = \pname -> - "Usage: " ++ pname ++ " haddock [FLAGS]\n" + , commandUsage = usageAlternatives "haddock" $ + [ "[FLAGS]" + , "COMPONENTS [FLAGS]" + ] , commandDefaultFlags = defaultHaddockFlags , commandOptions = \showOrParseArgs -> haddockOptions showOrParseArgs diff --git a/Cabal/Distribution/Simple/UserHooks.hs b/Cabal/Distribution/Simple/UserHooks.hs index 31e9cd66aea..56f91dc20a6 100644 --- a/Cabal/Distribution/Simple/UserHooks.hs +++ b/Cabal/Distribution/Simple/UserHooks.hs @@ -207,7 +207,7 @@ emptyUserHooks preDoctest = rn, doctestHook = ru, postDoctest = ru, - preHaddock = rn, + preHaddock = rn', haddockHook = ru, postHaddock = ru, preTest = rn', diff --git a/cabal-install/Distribution/Client/Config.hs b/cabal-install/Distribution/Client/Config.hs index 97b9c6dcaa3..b114e003002 100644 --- a/cabal-install/Distribution/Client/Config.hs +++ b/cabal-install/Distribution/Client/Config.hs @@ -413,7 +413,8 @@ instance Semigroup SavedConfig where haddockDistPref = combine haddockDistPref, haddockKeepTempFiles = combine haddockKeepTempFiles, haddockVerbosity = combine haddockVerbosity, - haddockCabalFilePath = combine haddockCabalFilePath + haddockCabalFilePath = combine haddockCabalFilePath, + haddockArgs = lastNonEmpty haddockArgs } where combine = combine' savedHaddockFlags diff --git a/cabal-install/Distribution/Client/ProjectBuilding.hs b/cabal-install/Distribution/Client/ProjectBuilding.hs index 10a2a93df03..24c28151464 100644 --- a/cabal-install/Distribution/Client/ProjectBuilding.hs +++ b/cabal-install/Distribution/Client/ProjectBuilding.hs @@ -366,11 +366,12 @@ packageFileMonitorKeyValues elab = -- elab_config = elab { - elabBuildTargets = [], - elabTestTargets = [], + elabBuildTargets = [], + elabTestTargets = [], elabBenchTargets = [], - elabReplTarget = Nothing, - elabBuildHaddocks = False + elabReplTarget = Nothing, + elabHaddockTargets = [], + elabBuildHaddocks = False } -- The second part is the value used to guard the build step. So this is @@ -1217,7 +1218,7 @@ buildInplaceUnpackedPackage verbosity -- Haddock phase whenHaddock $ annotateFailureNoLog HaddocksFailed $ do - setup haddockCommand haddockFlags [] + setup haddockCommand haddockFlags haddockArgs let haddockTarget = elabHaddockForHackage pkg when (haddockTarget == Cabal.ForHackage) $ do let dest = distDirectory name <.> "tar.gz" @@ -1304,6 +1305,7 @@ buildInplaceUnpackedPackage verbosity haddockCommand = Cabal.haddockCommand haddockFlags _ = setupHsHaddockFlags pkg pkgshared verbosity builddir + haddockArgs = setupHsHaddockArgs pkg scriptOptions = setupHsScriptOptions rpkg pkgshared srcdir builddir diff --git a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs index 4999740d1ca..9a86104a3be 100644 --- a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs @@ -733,7 +733,8 @@ convertToLegacyPerPackageConfig PackageConfig {..} = haddockDistPref = mempty, haddockKeepTempFiles = mempty, haddockVerbosity = mempty, - haddockCabalFilePath = mempty + haddockCabalFilePath = mempty, + haddockArgs = mempty } diff --git a/cabal-install/Distribution/Client/ProjectPlanning.hs b/cabal-install/Distribution/Client/ProjectPlanning.hs index a9fe664b44a..c597fea5237 100644 --- a/cabal-install/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/Distribution/Client/ProjectPlanning.hs @@ -56,6 +56,7 @@ module Distribution.Client.ProjectPlanning ( setupHsCopyFlags, setupHsRegisterFlags, setupHsHaddockFlags, + setupHsHaddockArgs, packageHashInputs, @@ -1727,6 +1728,8 @@ elaborateInstallPlan verbosity platform compiler compilerprogdb pkgConfigDB elabTestTargets = [] elabBenchTargets = [] elabReplTarget = Nothing + elabHaddockTargets = [] + elabBuildHaddocks = perPkgOptionFlag pkgid False packageConfigDocumentation @@ -2437,6 +2440,7 @@ pkgHasEphemeralBuildTargets elab = isJust (elabReplTarget elab) || (not . null) (elabTestTargets elab) || (not . null) (elabBenchTargets elab) + || (not . null) (elabHaddockTargets elab) || (not . null) [ () | ComponentTarget _ subtarget <- elabBuildTargets elab , subtarget /= WholeComponent ] @@ -2535,11 +2539,22 @@ setRootTargets targetAction perPkgTargetsMap = (Just tgts, TargetActionBuild) -> elab { elabBuildTargets = tgts } (Just tgts, TargetActionTest) -> elab { elabTestTargets = tgts } (Just tgts, TargetActionBench) -> elab { elabBenchTargets = tgts } - (Just [tgt], TargetActionRepl) -> elab { elabReplTarget = Just tgt } - (Just _, TargetActionHaddock) -> elab { elabBuildHaddocks = True } + (Just [tgt], TargetActionRepl) -> elab { elabReplTarget = Just tgt + , elabBuildHaddocks = False } + (Just tgts, TargetActionHaddock) -> + foldr setElabHaddockTargets (elab { elabHaddockTargets = tgts + , elabBuildHaddocks = True }) tgts (Just _, TargetActionRepl) -> error "pruneInstallPlanToTargets: multiple repl targets" + setElabHaddockTargets tgt elab + | isTestComponentTarget tgt = elab { elabHaddockTestSuites = True } + | isBenchComponentTarget tgt = elab { elabHaddockBenchmarks = True } + | isForeignLibComponentTarget tgt = elab { elabHaddockForeignLibs = True } + | isExeComponentTarget tgt = elab { elabHaddockExecutables = True } + | isSubLibComponentTarget tgt = elab { elabHaddockInternal = True } + | otherwise = elab + -- | Assuming we have previously set the root build targets (i.e. the user -- targets but not rev deps yet), the first pruning pass does two things: -- @@ -2560,14 +2575,16 @@ pruneInstallPlanPass1 pkgs = roots = mapMaybe find_root pkgs' prune elab = PrunedPackage elab' (pruneOptionalDependencies elab') - where elab' = addOptionalStanzas elab + where elab' = + setDocumentation + $ addOptionalStanzas elab find_root (InstallPlan.Configured (PrunedPackage elab _)) = if not (null (elabBuildTargets elab) && null (elabTestTargets elab) && null (elabBenchTargets elab) && isNothing (elabReplTarget elab) - && not (elabBuildHaddocks elab)) + && null (elabHaddockTargets elab)) then Just (installedUnitId elab) else Nothing find_root _ = Nothing @@ -2613,6 +2630,26 @@ pruneInstallPlanPass1 pkgs = <> optionalStanzasWithDepsAvailable availablePkgs elab pkg addOptionalStanzas elab = elab + setDocumentation :: ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage + setDocumentation elab@ElaboratedConfiguredPackage { elabPkgOrComp = ElabComponent comp } = + elab { + elabBuildHaddocks = + elabBuildHaddocks elab && documentationEnabled (compSolverName comp) elab + } + + where + documentationEnabled c = + case c of + CD.ComponentLib -> const True + CD.ComponentSubLib _ -> elabHaddockInternal + CD.ComponentFLib _ -> elabHaddockForeignLibs + CD.ComponentExe _ -> elabHaddockExecutables + CD.ComponentTest _ -> elabHaddockTestSuites + CD.ComponentBench _ -> elabHaddockBenchmarks + CD.ComponentSetup -> const False + + setDocumentation elab = elab + -- Calculate package dependencies but cut out those needed only by -- optional stanzas that we've determined we will not enable. -- These pruned deps are not persisted in this pass since they're based on @@ -3159,7 +3196,7 @@ setupHsConfigureFlags (ReadyPackage elab@ElaboratedConfiguredPackage{..}) configVanillaLib = toFlag elabVanillaLib configSharedLib = toFlag elabSharedLib configStaticLib = toFlag elabStaticLib - + configDynExe = toFlag elabDynExe configGHCiLib = toFlag elabGHCiLib configProfExe = mempty @@ -3391,9 +3428,15 @@ setupHsHaddockFlags (ElaboratedConfiguredPackage{..}) _ verbosity builddir = haddockDistPref = toFlag builddir, haddockKeepTempFiles = mempty, --TODO: from build settings haddockVerbosity = toFlag verbosity, - haddockCabalFilePath = mempty + haddockCabalFilePath = mempty, + haddockArgs = mempty } +setupHsHaddockArgs :: ElaboratedConfiguredPackage -> [String] +-- TODO: Does the issue #3335 affects test as well +setupHsHaddockArgs elab = + map (showComponentTarget (packageId elab)) (elabHaddockTargets elab) + {- setupHsTestFlags :: ElaboratedConfiguredPackage -> ElaboratedSharedConfig @@ -3582,4 +3625,3 @@ inplaceBinRoot inplaceBinRoot layout config package = distBuildDirectory layout (elabDistDirParams config package) "build" - diff --git a/cabal-install/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/Distribution/Client/ProjectPlanning/Types.hs index ef537cc41ef..138d76b5219 100644 --- a/cabal-install/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/Distribution/Client/ProjectPlanning/Types.hs @@ -45,7 +45,11 @@ module Distribution.Client.ProjectPlanning.Types ( showBenchComponentTarget, SubComponentTarget(..), + isSubLibComponentTarget, + isForeignLibComponentTarget, + isExeComponentTarget, isTestComponentTarget, + isBenchComponentTarget, -- * Setup script SetupScriptStyle(..), @@ -289,6 +293,8 @@ data ElaboratedConfiguredPackage elabTestTargets :: [ComponentTarget], elabBenchTargets :: [ComponentTarget], elabReplTarget :: Maybe ComponentTarget, + elabHaddockTargets :: [ComponentTarget], + elabBuildHaddocks :: Bool, --pkgSourceDir ? -- currently passed in later because they can use temp locations @@ -667,6 +673,22 @@ showBenchComponentTarget :: PackageId -> ComponentTarget -> Maybe String showBenchComponentTarget _ (ComponentTarget (CBenchName n) _) = Just $ display n showBenchComponentTarget _ _ = Nothing +isBenchComponentTarget :: ComponentTarget -> Bool +isBenchComponentTarget (ComponentTarget (CBenchName _) _) = True +isBenchComponentTarget _ = False + +isForeignLibComponentTarget :: ComponentTarget -> Bool +isForeignLibComponentTarget (ComponentTarget (CFLibName _) _) = True +isForeignLibComponentTarget _ = False + +isExeComponentTarget :: ComponentTarget -> Bool +isExeComponentTarget (ComponentTarget (CExeName _) _ ) = True +isExeComponentTarget _ = False + +isSubLibComponentTarget :: ComponentTarget -> Bool +isSubLibComponentTarget (ComponentTarget (CSubLibName _) _) = True +isSubLibComponentTarget _ = False + --------------------------- -- Setup.hs script policy --