diff --git a/Cabal/Distribution/Simple/ShowBuildInfo.hs b/Cabal/Distribution/Simple/ShowBuildInfo.hs index 2a41962fb6e..9375c81efa8 100644 --- a/Cabal/Distribution/Simple/ShowBuildInfo.hs +++ b/Cabal/Distribution/Simple/ShowBuildInfo.hs @@ -2,7 +2,7 @@ -- This module defines a simple JSON-based format for exporting basic -- information about a Cabal package and the compiler configuration Cabal -- would use to build it. This can be produced with the --- @cabal new-show-build-info@ command. +-- @cabal show-build-info@ command. -- -- -- This format is intended for consumption by external tooling and should diff --git a/cabal-install/Distribution/Client/CmdBuild.hs b/cabal-install/Distribution/Client/CmdBuild.hs index d4123b42ef5..702ee9ee531 100644 --- a/cabal-install/Distribution/Client/CmdBuild.hs +++ b/cabal-install/Distribution/Client/CmdBuild.hs @@ -8,7 +8,8 @@ module Distribution.Client.CmdBuild ( -- * Internals exposed for testing TargetProblem(..), selectPackageTargets, - selectComponentTarget + selectComponentTarget, + reportTargetProblems ) where import Distribution.Client.ProjectOrchestration diff --git a/cabal-install/Distribution/Client/CmdShowBuildInfo.hs b/cabal-install/Distribution/Client/CmdShowBuildInfo.hs index cc5a41bb6cc..311595ca022 100644 --- a/cabal-install/Distribution/Client/CmdShowBuildInfo.hs +++ b/cabal-install/Distribution/Client/CmdShowBuildInfo.hs @@ -1,27 +1,41 @@ --- | cabal-install CLI command: build +-- | cabal-install CLI command: show-build-info -- -module Distribution.Client.CmdShowBuildInfo ( - -- * The @build@ CLI and action - showBuildInfoCommand, - showBuildInfoAction - ) where +module Distribution.Client.CmdShowBuildInfo where +-- ( +-- -- * The @show-build-info@ CLI and action +-- showBuildInfoCommand, +-- showBuildInfoAction +-- ) +import Distribution.Client.Compat.Prelude + ( when, find, fromMaybe ) import Distribution.Client.ProjectOrchestration import Distribution.Client.CmdErrorMessages import Distribution.Client.CmdInstall.ClientInstallFlags import Distribution.Client.Setup - ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags ) + ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags + ) import qualified Distribution.Client.Setup as Client import Distribution.Simple.Setup - ( HaddockFlags, fromFlagOrDefault, TestFlags ) + ( HaddockFlags, TestFlags + , fromFlagOrDefault + ) import Distribution.Simple.Command - ( CommandUI(..), usageAlternatives ) + ( CommandUI(..), option, reqArg', usageAlternatives + ) import Distribution.Verbosity ( Verbosity, silent ) import Distribution.Simple.Utils - ( wrapText, die') -import Distribution.Types.UnitId (UnitId) + ( wrapText, die', withTempDirectory ) +import Distribution.Types.UnitId + ( UnitId, mkUnitId ) +import Distribution.Types.Version + ( mkVersion ) +import Distribution.Types.PackageDescription + ( buildType ) +import Distribution.Deprecated.Text + ( display ) import qualified Data.Map as Map import qualified Distribution.Simple.Setup as Cabal @@ -31,67 +45,78 @@ import qualified Distribution.Client.InstallPlan as InstallPlan import Distribution.Client.ProjectPlanning.Types import Distribution.Client.ProjectPlanning ( setupHsConfigureFlags, setupHsConfigureArgs, - setupHsBuildFlags, setupHsBuildArgs, + setupHsBuildFlags, setupHsBuildArgs, setupHsScriptOptions ) import Distribution.Client.DistDirLayout (distBuildDirectory) import Distribution.Client.Types ( PackageLocation(..), GenericReadyPackage(..) ) import Distribution.Client.JobControl (newLock, Lock) import Distribution.Simple.Configure (tryGetPersistBuildConfig) -import Data.List (find) +import qualified Distribution.Client.CmdInstall as CmdInstall -showBuildInfoCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, TestFlags) -showBuildInfoCommand = Client.installCommand { - commandName = "new-show-build-info", +import System.Directory (getTemporaryDirectory) +import System.FilePath (()) + +showBuildInfoCommand :: CommandUI ShowBuildInfoFlags +showBuildInfoCommand = CmdInstall.installCommand { + commandName = "show-build-info", commandSynopsis = "Show project build information", - commandUsage = usageAlternatives "new-show-build-info" [ "[TARGETS] [FLAGS]" ], + commandUsage = usageAlternatives "show-build-info" [ "[TARGETS] [FLAGS]" ], commandDescription = Just $ \_ -> wrapText $ - "Build one or more targets from within the project. The available " - ++ "targets are the packages in the project as well as individual " - ++ "components within those packages, including libraries, executables, " - ++ "test-suites or benchmarks. Targets can be specified by name or " - ++ "location. If no target is specified then the default is to build " - ++ "the package in the current directory.\n\n" - - ++ "Dependencies are built or rebuilt as necessary. Additional " - ++ "configuration flags can be specified on the command line and these " - ++ "extend the project configuration from the 'cabal.project', " - ++ "'cabal.project.local' and other files.", + "Provides detailed json output for the given package.\n" + ++ "Contains information about the different build components and compiler flags.\n", commandNotes = Just $ \pname -> "Examples:\n" - ++ " " ++ pname ++ " new-build\n" - ++ " Build the package in the current directory or all packages in the project\n" - ++ " " ++ pname ++ " new-build pkgname\n" - ++ " Build the package named pkgname in the project\n" - ++ " " ++ pname ++ " new-build ./pkgfoo\n" - ++ " Build the package in the ./pkgfoo directory\n" - ++ " " ++ pname ++ " new-build cname\n" - ++ " Build the component named cname module Distribution.Client.InstallPlanin the project\n" - ++ " " ++ pname ++ " new-build cname --module Distribution.Client.InstallPlanenable-profiling\n" - ++ " Build the component in profilingmodule Distribution.Client.InstallPlan mode (including dependencies as needed)\n\n" - - ++ cmdCommonHelpTextNewBuildBeta + ++ " " ++ pname ++ " show-build-info\n" + ++ " Shows build information about the current package\n" + ++ " " ++ pname ++ " show-build-info .\n" + ++ " Shows build information about the current package\n" + ++ " " ++ pname ++ " show-build-info ./pkgname \n" + ++ " Shows build information about the package located in './pkgname'\n" + ++ cmdCommonHelpTextNewBuildBeta, + commandOptions = \showOrParseArgs -> + Client.liftOptions buildInfoInstallCommandFlags (\pf flags -> flags { buildInfoInstallCommandFlags = pf }) (commandOptions CmdInstall.installCommand showOrParseArgs) + ++ + [ option [] ["buildinfo-json-output"] + "Write the result to the given file instead of stdout" + buildInfoOutputFile (\pf flags -> flags { buildInfoOutputFile = pf }) + (reqArg' "FILE" Just (maybe [] pure)), + option [] ["unit-ids-json"] + "Show build-info only for selected unit-id's." + buildInfoUnitIds (\pf flags -> flags { buildInfoUnitIds = pf }) + (reqArg' "UNIT-ID" (Just . words) (fromMaybe [])) + ], + commandDefaultFlags = defaultShowBuildInfoFlags + } +data ShowBuildInfoFlags = ShowBuildInfoFlags + { buildInfoInstallCommandFlags :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, TestFlags, ClientInstallFlags) + , buildInfoOutputFile :: Maybe FilePath + , buildInfoUnitIds :: Maybe [String] + } + +defaultShowBuildInfoFlags :: ShowBuildInfoFlags +defaultShowBuildInfoFlags = ShowBuildInfoFlags + { buildInfoInstallCommandFlags = (mempty, mempty, mempty, mempty, mempty, mempty) + , buildInfoOutputFile = Nothing + , buildInfoUnitIds = Nothing + } --- | The @build@ command does a lot. It brings the install plan up to date, +-- | The @show-build-info@ command does a lot. It brings the install plan up to date, -- selects that part of the plan needed by the given or implicit targets and -- then executes the plan. -- -- For more details on how this works, see the module -- "Distribution.Client.ProjectOrchestration" -- -showBuildInfoAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, TestFlags) - -> [String] -> GlobalFlags -> IO () -showBuildInfoAction (configFlags, configExFlags, installFlags, haddockFlags, testFlags) - targetStrings globalFlags = do - - baseCtx <- establishProjectBaseContext verbosity cliConfig - let baseCtx' = baseCtx { - buildSettings = (buildSettings baseCtx) { - buildSettingDryRun = True - } - } +showBuildInfoAction :: ShowBuildInfoFlags -> [String] -> GlobalFlags -> IO () +showBuildInfoAction (ShowBuildInfoFlags (configFlags, configExFlags, installFlags, haddockFlags, testFlags, clientInstallFlags) fileOutput unitIds) + targetStrings globalFlags = do + baseCtx <- establishProjectBaseContext verbosity cliConfig OtherCommand + let baseCtx' = baseCtx + { buildSettings = (buildSettings baseCtx) { buildSettingDryRun = True } + } targetSelectors <- either (reportTargetSelectorProblems verbosity) return =<< readTargetSelectors (localPackages baseCtx') Nothing targetStrings @@ -113,79 +138,127 @@ showBuildInfoAction (configFlags, configExFlags, installFlags, haddockFlags, tes return (elaboratedPlan, targets) scriptLock <- newLock - showTargets verbosity baseCtx' buildCtx scriptLock - + showTargets fileOutput unitIds verbosity baseCtx' buildCtx scriptLock where -- Default to silent verbosity otherwise it will pollute our json output verbosity = fromFlagOrDefault silent (configVerbosity configFlags) cliConfig = commandLineFlagsToProjectConfig globalFlags configFlags configExFlags - installFlags defaultClientInstallFlags + installFlags clientInstallFlags haddockFlags testFlags -- Pretty nasty piecemeal out of json, but I can't see a way to retrieve output of the setupWrapper'd tasks -showTargets :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> IO () -showTargets verbosity baseCtx buildCtx lock = do - putStr "[" - mapM_ showSeparated (zip [0..] targets) - putStrLn "]" +showTargets :: Maybe FilePath -> Maybe [String] -> Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> IO () +showTargets fileOutput unitIds verbosity baseCtx buildCtx lock = do + tempDir <- getTemporaryDirectory + withTempDirectory verbosity tempDir "show-build-info" $ \dir -> do + mapM_ (doShowInfo dir) targets + case fileOutput of + Nothing -> outputResult dir putStr targets + Just fp -> do + writeFile fp "" + outputResult dir (appendFile fp) targets + where configured = [p | InstallPlan.Configured p <- InstallPlan.toList (elaboratedPlanOriginal buildCtx)] - targets = fst <$> (Map.toList . targetsMap $ buildCtx) - doShowInfo unitId = showInfo verbosity baseCtx buildCtx lock configured unitId - showSeparated (idx, unitId) - | idx == length targets - 1 = doShowInfo unitId - | otherwise = doShowInfo unitId >> putStrLn "," - -showInfo :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> [ElaboratedConfiguredPackage] -> UnitId -> IO () -showInfo verbosity baseCtx buildCtx lock pkgs targetUnitId - | Nothing <- mbPkg = die' verbosity $ "No unit " ++ show targetUnitId - | Just pkg <- mbPkg = do - let shared = elaboratedShared buildCtx - install = elaboratedPlanOriginal buildCtx - dirLayout = distDirLayout baseCtx - buildDir = distBuildDirectory dirLayout (elabDistDirParams shared pkg) - flags = setupHsBuildFlags pkg shared verbosity buildDir - args = setupHsBuildArgs pkg - srcDir = case (elabPkgSourceLocation pkg) of - LocalUnpackedPackage fp -> fp - _ -> "" - scriptOptions = setupHsScriptOptions - (ReadyPackage pkg) - install - shared - dirLayout - srcDir - buildDir - False - lock - configureFlags = setupHsConfigureFlags (ReadyPackage pkg) shared verbosity buildDir - configureArgs = setupHsConfigureArgs pkg - --Configure the package if there's no existing config - lbi <- tryGetPersistBuildConfig buildDir - case lbi of - Left _ -> setupWrapper - verbosity - scriptOptions - (Just $ elabPkgDescription pkg) - (Cabal.configureCommand defaultProgramDb) - (const $ configureFlags) - (const configureArgs) - Right _ -> pure () - setupWrapper - verbosity - scriptOptions - (Just $ elabPkgDescription pkg) - (Cabal.showBuildInfoCommand defaultProgramDb) - (const flags) - (const args) - where mbPkg = find ((targetUnitId ==) . elabUnitId) pkgs - --- | This defines what a 'TargetSelector' means for the @write-autogen-files@ command. + targets = maybe (fst <$> (Map.toList . targetsMap $ buildCtx)) (map mkUnitId) unitIds + doShowInfo :: FilePath -> UnitId -> IO () + doShowInfo dir unitId = + showInfo + (dir unitIdToFilePath unitId) + verbosity + baseCtx + buildCtx + lock + configured + unitId + + outputResult :: FilePath -> (String -> IO ()) -> [UnitId] -> IO () + outputResult dir printer units = do + let unroll [] = return () + unroll [x] = do + content <- readFile (dir unitIdToFilePath x) + printer content + unroll (x:xs) = do + content <- readFile (dir unitIdToFilePath x) + printer content + printer "," + unroll xs + printer "[" + unroll units + printer "]" + + unitIdToFilePath :: UnitId -> FilePath + unitIdToFilePath unitId = "build-info-" ++ display unitId ++ ".json" + +showInfo :: FilePath -> Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> [ElaboratedConfiguredPackage] -> UnitId -> IO () +showInfo fileOutput verbosity baseCtx buildCtx lock pkgs targetUnitId = + case mbPkg of + Nothing -> die' verbosity $ "No unit " ++ display targetUnitId + Just pkg -> do + let shared = elaboratedShared buildCtx + install = elaboratedPlanOriginal buildCtx + dirLayout = distDirLayout baseCtx + buildDir = distBuildDirectory dirLayout (elabDistDirParams shared pkg) + buildType' = buildType (elabPkgDescription pkg) + flags = setupHsBuildFlags pkg shared verbosity buildDir + args = setupHsBuildArgs pkg + srcDir = case (elabPkgSourceLocation pkg) of + LocalUnpackedPackage fp -> fp + _ -> "" + scriptOptions = setupHsScriptOptions + (ReadyPackage pkg) + install + shared + dirLayout + srcDir + buildDir + False + lock + configureFlags = setupHsConfigureFlags (ReadyPackage pkg) shared verbosity buildDir + configureArgs = setupHsConfigureArgs pkg + + -- check cabal version is corrct + (cabalVersion, _, _) <- getSetupMethod verbosity scriptOptions + (elabPkgDescription pkg) buildType' + when (cabalVersion < mkVersion [3, 0, 0,0]) + ( die' verbosity $ "Only a Cabal version >= 3.0.0.0 is supported for this command.\n" + ++ "Found version: " ++ display cabalVersion ++ "\n" + ++ "For component: " ++ display targetUnitId + ) + --Configure the package if there's no existing config + lbi <- tryGetPersistBuildConfig buildDir + case lbi of + Left _ -> setupWrapper + verbosity + scriptOptions + (Just $ elabPkgDescription pkg) + (Cabal.configureCommand defaultProgramDb) + (const configureFlags) + (const configureArgs) + Right _ -> pure () + + setupWrapper + verbosity + scriptOptions + (Just $ elabPkgDescription pkg) + (Cabal.showBuildInfoCommand defaultProgramDb) + (const (Cabal.ShowBuildInfoFlags + { Cabal.buildInfoBuildFlags = flags + , Cabal.buildInfoOutputFile = Just fileOutput + } + ) + ) + (const args) + where + mbPkg :: Maybe ElaboratedConfiguredPackage + mbPkg = find ((targetUnitId ==) . elabUnitId) pkgs + +-- | This defines what a 'TargetSelector' means for the @show-build-info@ command. -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to, -- or otherwise classifies the problem. -- --- For the @write-autogen-files@ command select all components except non-buildable and disabled +-- For the @show-build-info@ command select all components except non-buildable and disabled -- tests\/benchmarks, fail if there are no such components -- selectPackageTargets :: TargetSelector @@ -219,7 +292,7 @@ selectPackageTargets targetSelector targets -- | For a 'TargetComponent' 'TargetSelector', check if the component can be -- selected. -- --- For the @build@ command we just need the basic checks on being buildable etc. +-- For the @show-build-info@ command we just need the basic checks on being buildable etc. -- selectComponentTarget :: SubComponentTarget -> AvailableTarget k -> Either TargetProblem k @@ -229,7 +302,7 @@ selectComponentTarget subtarget = -- | The various error conditions that can occur when matching a --- 'TargetSelector' against 'AvailableTarget's for the @build@ command. +-- 'TargetSelector' against 'AvailableTarget's for the @show-build-info@ command. -- data TargetProblem = TargetProblemCommon TargetProblemCommon @@ -251,4 +324,4 @@ renderTargetProblem (TargetProblemCommon problem) = renderTargetProblem (TargetProblemNoneEnabled targetSelector targets) = renderTargetProblemNoneEnabled "build" targetSelector targets renderTargetProblem(TargetProblemNoTargets targetSelector) = - renderTargetProblemNoTargets "build" targetSelector \ No newline at end of file + renderTargetProblemNoTargets "build" targetSelector diff --git a/cabal-install/Distribution/Client/CmdWriteAutogenFiles.hs b/cabal-install/Distribution/Client/CmdWriteAutogenFiles.hs deleted file mode 100644 index 86a80b6fa53..00000000000 --- a/cabal-install/Distribution/Client/CmdWriteAutogenFiles.hs +++ /dev/null @@ -1,220 +0,0 @@ --- | cabal-install CLI command: build --- -module Distribution.Client.CmdWriteAutogenFiles ( - -- * The @build@ CLI and action - writeAutogenFilesCommand, - writeAutogenFilesAction - ) where - -import Distribution.Client.ProjectOrchestration -import Distribution.Client.CmdErrorMessages -import Distribution.Client.CmdInstall.ClientInstallFlags - -import Distribution.Client.Setup - ( GlobalFlags, ConfigFlags(..), ConfigExFlags, InstallFlags, WriteAutogenFilesFlags(..) ) -import qualified Distribution.Client.Setup as Client -import Distribution.Simple.Setup - ( HaddockFlags, fromFlagOrDefault, Flag(..), TestFlags ) -import Distribution.Simple.Command - ( CommandUI(..), usageAlternatives ) -import Distribution.Verbosity - ( Verbosity, normal ) -import Distribution.Simple.Utils - ( wrapText, die' ) -import Distribution.Simple.Configure (tryGetPersistBuildConfig) - -import qualified Data.Map as Map -import qualified Distribution.Simple.Setup as Cabal -import Distribution.Client.SetupWrapper -import Distribution.Simple.Program ( defaultProgramDb ) -import qualified Distribution.Client.InstallPlan as InstallPlan -import Distribution.Client.ProjectPlanning.Types -import Distribution.Client.ProjectPlanning ( - setupHsScriptOptions, setupHsConfigureFlags, setupHsConfigureArgs - ) -import Distribution.Client.DistDirLayout (distBuildDirectory) -import Distribution.Client.Types ( PackageLocation(..), GenericReadyPackage(..) ) -import Distribution.Client.JobControl (newLock, Lock) - -writeAutogenFilesCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, TestFlags) -writeAutogenFilesCommand = Client.installCommand { - commandName = "new-write-autogen-files", - commandSynopsis = "", - commandUsage = usageAlternatives "new-write-autogen-files" [ "[FLAGS]" ], - commandDescription = Just $ \_ -> wrapText $ - "Generate and write out the Paths_.hs and cabal_macros.h files\n" - ++ "for all components in the project", - commandNotes = Just $ \pname -> - "Examples:\n" - ++ " " ++ pname ++ " new-write-autogen-files\n" - ++ " Write for all packages in the project\n" - } - -writeAutogenFilesAction :: (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags, TestFlags) - -> [String] -> GlobalFlags -> IO () -writeAutogenFilesAction (configFlags, configExFlags, installFlags, haddockFlags, testFlags) - targetStrings globalFlags = do - baseCtx <- establishProjectBaseContext verbosity cliConfig - let baseCtx' = baseCtx { - buildSettings = (buildSettings baseCtx) { - buildSettingDryRun = True - } - } - targetSelectors <- either (reportTargetSelectorProblems verbosity) return - =<< readTargetSelectors (localPackages baseCtx') Nothing targetStrings - - buildCtx <- - runProjectPreBuildPhase verbosity baseCtx $ \elaboratedPlan -> do - -- Interpret the targets on the command line as build targets - -- (as opposed to say repl or haddock targets). - targets <- either (reportTargetProblems verbosity) return - $ resolveTargets - selectPackageTargets - selectComponentTarget - TargetProblemCommon - elaboratedPlan - Nothing - targetSelectors - - let elaboratedPlan' = pruneInstallPlanToTargets - TargetActionBuild - targets - elaboratedPlan - elaboratedPlan'' <- - if buildSettingOnlyDeps (buildSettings baseCtx') - then either (reportCannotPruneDependencies verbosity) return $ - pruneInstallPlanToDependencies (Map.keysSet targets) - elaboratedPlan' - else return elaboratedPlan' - - return (elaboratedPlan'', targets) - - scriptLock <- newLock - writeAutogenFiles verbosity baseCtx' buildCtx scriptLock (configured buildCtx) - - where - verbosity = fromFlagOrDefault normal (configVerbosity configFlags) - cliConfig = commandLineFlagsToProjectConfig - globalFlags configFlags configExFlags - installFlags defaultClientInstallFlags - haddockFlags - testFlags - configured ctx = [p | InstallPlan.Configured p <- InstallPlan.toList (elaboratedPlanToExecute ctx)] - - -writeAutogenFiles :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> Lock -> [ElaboratedConfiguredPackage] -> IO () -writeAutogenFiles verbosity baseCtx buildCtx lock pkgs = mapM_ runWrapper pkgs - where runWrapper pkg = do - let shared = elaboratedShared buildCtx - install = elaboratedPlanOriginal buildCtx - dirLayout = distDirLayout baseCtx - buildDir = distBuildDirectory dirLayout (elabDistDirParams shared pkg) - srcDir = case (elabPkgSourceLocation pkg) of - LocalUnpackedPackage fp -> fp - _ -> "" - scriptOptions = setupHsScriptOptions - (ReadyPackage pkg) - install - shared - dirLayout - srcDir - buildDir - False - lock - configureFlags = setupHsConfigureFlags (ReadyPackage pkg) shared verbosity buildDir - configureArgs = setupHsConfigureArgs pkg - --Configure the package if there's no existing config, - lbi <- tryGetPersistBuildConfig buildDir - case lbi of - Left _ -> setupWrapper - verbosity - scriptOptions - (Just $ elabPkgDescription pkg) - (Cabal.configureCommand defaultProgramDb) - (const $ configureFlags) - (const configureArgs) - Right _ -> pure () - setupWrapper - verbosity - scriptOptions - (Just $ elabPkgDescription pkg) - (Cabal.writeAutogenFilesCommand defaultProgramDb) - (const $ WriteAutogenFilesFlags (Flag buildDir) (Flag verbosity)) - (const []) - --- | This defines what a 'TargetSelector' means for the @write-autogen-files@ command. --- It selects the 'AvailableTarget's that the 'TargetSelector' refers to, --- or otherwise classifies the problem. --- --- For the @write-autogen-files@ command select all components except non-buildable and disabled --- tests\/benchmarks, fail if there are no such components --- -selectPackageTargets :: TargetSelector - -> [AvailableTarget k] -> Either TargetProblem [k] -selectPackageTargets targetSelector targets - - -- If there are any buildable targets then we select those - | not (null targetsBuildable) - = Right targetsBuildable - - -- If there are targets but none are buildable then we report those - | not (null targets) - = Left (TargetProblemNoneEnabled targetSelector targets') - - -- If there are no targets at all then we report that - | otherwise - = Left (TargetProblemNoTargets targetSelector) - where - targets' = forgetTargetsDetail targets - targetsBuildable = selectBuildableTargetsWith - (buildable targetSelector) - targets - - -- When there's a target filter like "pkg:tests" then we do select tests, - -- but if it's just a target like "pkg" then we don't build tests unless - -- they are requested by default (i.e. by using --enable-tests) - buildable (TargetPackage _ _ Nothing) TargetNotRequestedByDefault = False - buildable (TargetAllPackages Nothing) TargetNotRequestedByDefault = False - buildable _ _ = True - --- | For a 'TargetComponent' 'TargetSelector', check if the component can be --- selected. --- --- For the @build@ command we just need the basic checks on being buildable etc. --- -selectComponentTarget :: SubComponentTarget - -> AvailableTarget k -> Either TargetProblem k -selectComponentTarget subtarget = - either (Left . TargetProblemCommon) Right - . selectComponentTargetBasic subtarget - - --- | The various error conditions that can occur when matching a --- 'TargetSelector' against 'AvailableTarget's for the @build@ command. --- -data TargetProblem = - TargetProblemCommon TargetProblemCommon - - -- | The 'TargetSelector' matches targets but none are buildable - | TargetProblemNoneEnabled TargetSelector [AvailableTarget ()] - - -- | There are no targets at all - | TargetProblemNoTargets TargetSelector - deriving (Eq, Show) - -reportTargetProblems :: Verbosity -> [TargetProblem] -> IO a -reportTargetProblems verbosity = - die' verbosity . unlines . map renderTargetProblem - -renderTargetProblem :: TargetProblem -> String -renderTargetProblem (TargetProblemCommon problem) = - renderTargetProblemCommon "build" problem -renderTargetProblem (TargetProblemNoneEnabled targetSelector targets) = - renderTargetProblemNoneEnabled "build" targetSelector targets -renderTargetProblem(TargetProblemNoTargets targetSelector) = - renderTargetProblemNoTargets "build" targetSelector - -reportCannotPruneDependencies :: Verbosity -> CannotPruneDependencies -> IO a -reportCannotPruneDependencies verbosity = - die' verbosity . renderCannotPruneDependencies - diff --git a/cabal-install/Distribution/Client/Setup.hs b/cabal-install/Distribution/Client/Setup.hs index a2f06f789c9..e482ce67d5c 100644 --- a/cabal-install/Distribution/Client/Setup.hs +++ b/cabal-install/Distribution/Client/Setup.hs @@ -56,10 +56,7 @@ module Distribution.Client.Setup , doctestCommand , copyCommand , registerCommand - - --ghc-mod support commands - , showBuildInfoCommand - , writeAutogenFilesCommand, WriteAutogenFilesFlags(..) + --, showBuildInfoCommand , parsePackageArgs , liftOptions , yesNoOpt @@ -108,7 +105,6 @@ import Distribution.Simple.Setup , SDistFlags(..), HaddockFlags(..) , CleanFlags(..), DoctestFlags(..) , CopyFlags(..), RegisterFlags(..) - , WriteAutogenFilesFlags(..) , readPackageDbList, showPackageDbList , Flag(..), toFlag, flagToMaybe, flagToList, maybeToFlag , BooleanFlag(..), optionVerbosity @@ -202,7 +198,6 @@ globalCommand commands = CommandUI { , "haddock" , "hscolour" , "show-build-info" - , "write-autogen-files" , "exec" , "new-build" , "new-configure" @@ -290,7 +285,6 @@ globalCommand commands = CommandUI { , addCmd "report" , par , addCmd "show-build-info" - , addCmd "write-autogen-files" , addCmd "freeze" , addCmd "gen-bounds" , addCmd "outdated" @@ -869,25 +863,6 @@ filterTestFlags flags cabalLibVersion Cabal.testWrapper = NoFlag } --- ------------------------------------------------------------ --- * show-build-info command --- ------------------------------------------------------------ - -showBuildInfoCommand :: CommandUI (BuildFlags, BuildExFlags) -showBuildInfoCommand = parent { - commandDefaultFlags = (commandDefaultFlags parent, mempty), - commandOptions = - \showOrParseArgs -> liftOptions fst setFst - (commandOptions parent showOrParseArgs) - ++ - liftOptions snd setSnd (buildExOptions showOrParseArgs) - } - where - setFst a (_,b) = (a,b) - setSnd b (a,_) = (a,b) - - parent = Cabal.showBuildInfoCommand defaultProgramDb - -- ------------------------------------------------------------ -- * Repl command -- ------------------------------------------------------------ @@ -3012,10 +2987,10 @@ relevantConfigValuesText vs = -- ------------------------------------------------------------ --- * Commands to support ghc-mod +-- * Commands to support show-build-info -- ------------------------------------------------------------ -showBuildInfoCommand :: CommandUI (BuildFlags, BuildExFlags) +showBuildInfoCommand :: CommandUI (Cabal.ShowBuildInfoFlags, BuildExFlags) showBuildInfoCommand = parent { commandDefaultFlags = (commandDefaultFlags parent, mempty), commandOptions = @@ -3029,6 +3004,3 @@ showBuildInfoCommand = parent { setSnd b (a,_) = (a,b) parent = Cabal.showBuildInfoCommand defaultProgramDb - -writeAutogenFilesCommand :: CommandUI WriteAutogenFilesFlags -writeAutogenFilesCommand = Cabal.writeAutogenFilesCommand defaultProgramDb \ No newline at end of file diff --git a/cabal-install/Distribution/Client/SetupWrapper.hs b/cabal-install/Distribution/Client/SetupWrapper.hs index d422a2fddfb..955ac3b0c11 100644 --- a/cabal-install/Distribution/Client/SetupWrapper.hs +++ b/cabal-install/Distribution/Client/SetupWrapper.hs @@ -17,7 +17,7 @@ -- runs it with the given arguments. module Distribution.Client.SetupWrapper ( - getSetup, runSetup, runSetupCommand, setupWrapper, + getSetup, runSetup, runSetupCommand, setupWrapper, getSetupMethod, SetupScriptOptions(..), defaultSetupScriptOptions, ) where diff --git a/cabal-install/cabal-install.cabal b/cabal-install/cabal-install.cabal index b02289a5314..fde55eaaf96 100644 --- a/cabal-install/cabal-install.cabal +++ b/cabal-install/cabal-install.cabal @@ -161,8 +161,6 @@ executable cabal Distribution.Client.CmdBench Distribution.Client.CmdBuild Distribution.Client.CmdClean - Distribution.Client.CmdShowBuildInfo - Distribution.Client.CmdWriteAutogenFiles Distribution.Client.CmdConfigure Distribution.Client.CmdUpdate Distribution.Client.CmdErrorMessages @@ -173,6 +171,7 @@ executable cabal Distribution.Client.CmdInstall.ClientInstallFlags Distribution.Client.CmdRepl Distribution.Client.CmdRun + Distribution.Client.CmdShowBuildInfo Distribution.Client.CmdTest Distribution.Client.CmdLegacy Distribution.Client.CmdSdist diff --git a/cabal-install/cabal-install.cabal.pp b/cabal-install/cabal-install.cabal.pp index 0f4d208b02d..df3d56b873d 100644 --- a/cabal-install/cabal-install.cabal.pp +++ b/cabal-install/cabal-install.cabal.pp @@ -100,6 +100,7 @@ Distribution.Client.CmdInstall.ClientInstallFlags Distribution.Client.CmdRepl Distribution.Client.CmdRun + Distribution.Client.CmdShowBuildInfo Distribution.Client.CmdTest Distribution.Client.CmdLegacy Distribution.Client.CmdSdist diff --git a/cabal-install/main/Main.hs b/cabal-install/main/Main.hs index a55fe9fc979..ef8f9dbf72a 100644 --- a/cabal-install/main/Main.hs +++ b/cabal-install/main/Main.hs @@ -52,7 +52,6 @@ import Distribution.Client.Setup , doctestCommand , copyCommand , registerCommand - , WriteAutogenFilesFlags(..) ) import Distribution.Simple.Setup ( HaddockTarget(..) @@ -85,7 +84,6 @@ import qualified Distribution.Client.CmdConfigure as CmdConfigure import qualified Distribution.Client.CmdUpdate as CmdUpdate import qualified Distribution.Client.CmdBuild as CmdBuild import qualified Distribution.Client.CmdShowBuildInfo as CmdShowBuildInfo -import qualified Distribution.Client.CmdWriteAutogenFiles as CmdWriteAutogenFiles import qualified Distribution.Client.CmdRepl as CmdRepl import qualified Distribution.Client.CmdFreeze as CmdFreeze import qualified Distribution.Client.CmdHaddock as CmdHaddock @@ -158,7 +156,7 @@ import qualified Distribution.Simple as Simple import qualified Distribution.Make as Make import qualified Distribution.Types.UnqualComponentName as Make import Distribution.Simple.Build - ( startInterpreter, initialBuildSteps ) + ( startInterpreter ) import Distribution.Simple.Command ( CommandParse(..), CommandUI(..), Command, CommandSpec(..) , CommandType(..), commandsRun, commandAddAction, hiddenCommand @@ -181,7 +179,7 @@ import Distribution.Simple.Utils import Distribution.Text ( display ) import Distribution.Verbosity as Verbosity - ( Verbosity, normal, silent ) + ( Verbosity, normal ) import Distribution.Version ( Version, mkVersion, orLaterVersion ) import qualified Paths_cabal_install (version) @@ -307,11 +305,8 @@ mainWorker args = do , hiddenCmd win32SelfUpgradeCommand win32SelfUpgradeAction , hiddenCmd actAsSetupCommand actAsSetupAction , hiddenCmd manpageCommand (manpageAction commandSpecs) - -- ghc-mod supporting commands , hiddenCmd CmdShowBuildInfo.showBuildInfoCommand CmdShowBuildInfo.showBuildInfoAction - , hiddenCmd CmdWriteAutogenFiles.writeAutogenFilesCommand - CmdWriteAutogenFiles.writeAutogenFilesAction ] ++ concat [ newCmd CmdConfigure.configureCommand CmdConfigure.configureAction , newCmd CmdUpdate.updateCommand CmdUpdate.updateAction @@ -461,13 +456,14 @@ buildAction flags@(buildFlags, _) = buildActionForCommand flags where verbosity = fromFlagOrDefault normal (buildVerbosity buildFlags) -showBuildInfoAction :: (BuildFlags, BuildExFlags) -> [String] -> Action -showBuildInfoAction flags@(buildFlags, _) = buildActionForCommand - (Cabal.showBuildInfoCommand defaultProgramDb) - verbosity - flags - -- Default silent verbosity so as not to pollute json output - where verbosity = fromFlagOrDefault silent (buildVerbosity buildFlags) +-- showBuildInfoAction :: (Cabal.ShowBuildInfoFlags, BuildExFlags) -> [String] -> Action +-- showBuildInfoAction (showBuildInfoFlags, buildEx) = buildActionForCommand +-- (Cabal.showBuildInfoCommand defaultProgramDb) +-- showBuildInfoFlags +-- verbosity +-- (Cabal.buildInfoBuildFlags showBuildInfoFlags, buildEx) +-- -- Default silent verbosity so as not to pollute json output +-- where verbosity = fromFlagOrDefault silent (buildVerbosity (Cabal.buildInfoBuildFlags showBuildInfoFlags )) buildActionForCommand :: CommandUI BuildFlags -> Verbosity @@ -482,23 +478,13 @@ buildActionForCommand commandUI verbosity (buildFlags, buildExFlags) extraArgs g distPref <- findSavedDistPref config (buildDistPref buildFlags) -- Calls 'configureAction' to do the real work, so nothing special has to be -- done to support sandboxes. - config' <- reconfigure configureAction - verbosity - distPref - useSandbox - noAddSource - (buildNumJobs buildFlags) - mempty - [] - globalFlags - config - nixShell verbosity distPref globalFlags config $ do - maybeWithSandboxDirOnSearchPath useSandbox $ buildForCommand commandUI - verbosity - config' - distPref - buildFlags - extraArgs + config' <- reconfigure + configureAction verbosity distPref useSandbox noAddSource + (buildNumJobs buildFlags) mempty [] globalFlags config + + nixShell verbosity distPref globalFlags config $ + maybeWithSandboxDirOnSearchPath useSandbox $ buildForCommand + commandUI verbosity config' distPref buildFlags extraArgs -- | Actually do the work of building the package. This is separate from -- 'buildAction' so that 'testAction' and 'benchmarkAction' do not invoke @@ -506,6 +492,7 @@ buildActionForCommand commandUI verbosity (buildFlags, buildExFlags) extraArgs g build :: Verbosity -> SavedConfig -> FilePath -> BuildFlags -> [String] -> IO () build = buildForCommand (Cabal.buildCommand defaultProgramDb) +-- | Helper function buildForCommand :: CommandUI BuildFlags -> Verbosity -> SavedConfig @@ -514,12 +501,7 @@ buildForCommand :: CommandUI BuildFlags -> [String] -> IO () buildForCommand command verbosity config distPref buildFlags extraArgs = - setupWrapper verbosity - setupOptions - Nothing - command - mkBuildFlags - (const extraArgs) + setupWrapper verbosity setupOptions Nothing command mkBuildFlags (const extraArgs) where setupOptions = defaultSetupScriptOptions { useDistPref = distPref } @@ -568,8 +550,8 @@ replAction (replFlags, buildExFlags) extraArgs globalFlags = do -- be done to support sandboxes. _ <- reconfigure configureAction - verbosity distPref useSandbox noAddSource NoFlag - mempty [] globalFlags config + verbosity distPref useSandbox noAddSource NoFlag + mempty [] globalFlags config let progDb = defaultProgramDb setupOptions = defaultSetupScriptOptions { useCabalVersion = orLaterVersion $ mkVersion [1,18,0] @@ -1294,23 +1276,3 @@ manpageAction commands flagVerbosity extraArgs _ = do then dropExtension pname else pname putStrLn $ manpage cabalCmd commands - ---Further commands to support ghc-mod usage -writeAutogenFilesAction :: WriteAutogenFilesFlags -> [String] -> Action -writeAutogenFilesAction flags _ globalFlags = do - let verbosity = fromFlag (wafVerbosity flags) - load <- try (loadConfigOrSandboxConfig verbosity globalFlags) - let config = either (\(SomeException _) -> mempty) snd load - distPref <- findSavedDistPref config (wafDistPref flags) - pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref) - eLBI <- tryGetPersistBuildConfig distPref - case eLBI of - Left err -> case err of - -- Note: the build config could have been generated by a custom setup - -- script built against a different Cabal version, so it's crucial that - -- we ignore the bad version error here. - ConfigStateFileBadVersion _ _ _ -> pure () - _ -> die' verbosity (show err) - Right lbi -> do - initialBuildSteps distPref pkg lbi verbosity - pure () \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/A.cabal b/cabal-testsuite/PackageTests/ShowBuildInfo/A/A.cabal new file mode 100644 index 00000000000..2873a450394 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/A.cabal @@ -0,0 +1,32 @@ +cabal-version: 2.4 +-- Initial package description 'A.cabal' generated by 'cabal init'. For +-- further documentation, see http://haskell.org/cabal/users-guide/ + +name: A +version: 0.1.0.0 +-- synopsis: +-- description: +-- bug-reports: +license: BSD-3-Clause +license-file: LICENSE +author: Foo Bar +maintainer: cabal-dev@haskell.org +-- copyright: +-- category: +extra-source-files: CHANGELOG.md + +library + exposed-modules: A + -- other-modules: + -- other-extensions: + build-depends: base >=4.0.0 + hs-source-dirs: src + default-language: Haskell2010 + +executable A + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.0.0.0 + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/CHANGELOG.md b/cabal-testsuite/PackageTests/ShowBuildInfo/A/CHANGELOG.md new file mode 100644 index 00000000000..cfa8b563c0e --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for A + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/LICENSE b/cabal-testsuite/PackageTests/ShowBuildInfo/A/LICENSE new file mode 100644 index 00000000000..671281e7a8b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2019, Foo Bar + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Foo Bar nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/Setup.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.out b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.test.hs new file mode 100644 index 00000000000..7c8a2be90ea --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-exe-exact.test.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["exe:A", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly one" 1 (length buildInfos) + let [buildInfo] = buildInfos + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "exe" (componentType component) + assertEqual "Component name" "exe:A" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace-A" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" [] (componentModules component) + assertEqual "Component source files" ["Main.hs"] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + return () + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.out b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.test.hs new file mode 100644 index 00000000000..abdc7d649f4 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id-file.test.hs @@ -0,0 +1,92 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ withSourceCopy $do + cwd <- fmap testCurrentDir getTestEnv + let fp = cwd "unit.json" + r <- cabal' "show-build-info" ["--buildinfo-json-output=" ++ fp, "--unit-ids-json=A-0.1.0.0-inplace A-0.1.0.0-inplace-A", "-v0"] + shouldExist fp + buildInfoEither <- liftIO $ eitherDecodeFileStrict fp + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly two " 2 (length buildInfos) + let [libBuildInfo, exeBuildInfo] = buildInfos + assertExe exeBuildInfo + assertLib libBuildInfo + return () + where + assertExe :: BuildInfo -> TestM () + assertExe buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "exe" (componentType component) + assertEqual "Component name" "exe:A" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace-A" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" [] (componentModules component) + assertEqual "Component source files" ["Main.hs"] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + + assertLib :: BuildInfo -> TestM () + assertLib buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "lib" (componentType component) + assertEqual "Component name" "lib" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" ["A"] (componentModules component) + assertEqual "Component source files" [] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.out b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.test.hs new file mode 100644 index 00000000000..63d928bc21c --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact-unit-id.test.hs @@ -0,0 +1,89 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["--unit-ids-json=A-0.1.0.0-inplace A-0.1.0.0-inplace-A", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly two " 2 (length buildInfos) + let [libBuildInfo, exeBuildInfo] = buildInfos + assertExe exeBuildInfo + assertLib libBuildInfo + return () + where + assertExe :: BuildInfo -> TestM () + assertExe buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "exe" (componentType component) + assertEqual "Component name" "exe:A" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace-A" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" [] (componentModules component) + assertEqual "Component source files" ["Main.hs"] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + + assertLib :: BuildInfo -> TestM () + assertLib buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "lib" (componentType component) + assertEqual "Component name" "lib" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" ["A"] (componentModules component) + assertEqual "Component source files" [] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.out b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.test.hs new file mode 100644 index 00000000000..14b523e3992 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-multiple-exact.test.hs @@ -0,0 +1,89 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["exe:A", "lib:A", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly two " 2 (length buildInfos) + let [libBuildInfo, exeBuildInfo] = buildInfos + assertExe exeBuildInfo + assertLib libBuildInfo + return () + where + assertExe :: BuildInfo -> TestM () + assertExe buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "exe" (componentType component) + assertEqual "Component name" "exe:A" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace-A" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" [] (componentModules component) + assertEqual "Component source files" ["Main.hs"] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + + assertLib :: BuildInfo -> TestM () + assertLib buildInfo = do + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "lib" (componentType component) + assertEqual "Component name" "lib" (componentName component) + assertEqual "Component unit-id" "A-0.1.0.0-inplace" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" ["A"] (componentModules component) + assertEqual "Component source files" [] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.out b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.out new file mode 100644 index 00000000000..5f6512b4dc9 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.out @@ -0,0 +1,12 @@ +# cabal show-build-info +cabal: Internal error in target matching. It should always be possible to find a syntax that's sufficiently qualified to give an unambiguous match. However when matching 'exe:B' we found exe:B (unknown-component) which does not have an unambiguous syntax. The possible syntax and the targets they match are as follows: +'exe:B' which matches exe:B (unknown-component), :pkg:exe:lib:exe:module:B (unknown-module), :pkg:exe:lib:exe:file:B (unknown-file) +# cabal show-build-info +Resolving dependencies... +cabal: No unit B-inplace-0.1.0.0 +# cabal show-build-info +Configuring library for A-0.1.0.0.. +cabal: No unit B-inplace-0.1.0.0 +# cabal show-build-info +cabal: Internal error in target matching. It should always be possible to find a syntax that's sufficiently qualified to give an unambiguous match. However when matching 'exe:B' we found exe:B (unknown-component) which does not have an unambiguous syntax. The possible syntax and the targets they match are as follows: +'exe:B' which matches exe:B (unknown-component), :pkg:exe:lib:exe:module:B (unknown-module), :pkg:exe:lib:exe:file:B (unknown-file) diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.test.hs new file mode 100644 index 00000000000..b07607b3779 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/build-info-unknown.test.hs @@ -0,0 +1,14 @@ +import Test.Cabal.Prelude + +main = cabalTest $ do + r <- fails $ cabal' "show-build-info" ["exe:B"] + assertOutputContains "Internal error in target matching." r + + r <- fails $ cabal' "show-build-info" ["--unit-ids-json=B-inplace-0.1.0.0"] + assertOutputContains "No unit B-inplace-0.1.0.0" r + + r <- fails $ cabal' "show-build-info" ["--unit-ids-json=A-0.1.0.0-inplace B-inplace-0.1.0.0"] + assertOutputContains "No unit B-inplace-0.1.0.0" r + + r <- fails $ cabal' "show-build-info" ["--unit-ids-json=A-0.1.0.0-inplace", "exe:B"] + assertOutputContains "Internal error in target matching." r diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/cabal.project b/cabal-testsuite/PackageTests/ShowBuildInfo/A/cabal.project new file mode 100644 index 00000000000..5356e76f67c --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/cabal.project @@ -0,0 +1 @@ +packages: . \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/A.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/A.hs new file mode 100644 index 00000000000..ad7a0c07729 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/A.hs @@ -0,0 +1,4 @@ +module A where + +foo :: Int -> Int +foo = id \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/Main.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/Main.hs new file mode 100644 index 00000000000..65ae4a05d5d --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/A/src/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Haskell!" diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/B.cabal b/cabal-testsuite/PackageTests/ShowBuildInfo/B/B.cabal new file mode 100644 index 00000000000..d8ed91d655b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/B.cabal @@ -0,0 +1,24 @@ +cabal-version: 2.4 +-- Initial package description 'B.cabal' generated by 'cabal init'. For +-- further documentation, see http://haskell.org/cabal/users-guide/ + +name: B +version: 0.1.0.0 +-- synopsis: +-- description: +-- bug-reports: +license: BSD-3-Clause +license-file: LICENSE +author: Foo Bar +maintainer: cabal-dev@haskell.org +-- copyright: +-- category: +extra-source-files: CHANGELOG.md + +library + exposed-modules: A + -- other-modules: + -- other-extensions: + build-depends: base >=4.0.0.0 + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/CHANGELOG.md b/cabal-testsuite/PackageTests/ShowBuildInfo/B/CHANGELOG.md new file mode 100644 index 00000000000..5cf6ac2adb2 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for B + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/LICENSE b/cabal-testsuite/PackageTests/ShowBuildInfo/B/LICENSE new file mode 100644 index 00000000000..671281e7a8b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2019, Foo Bar + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Foo Bar nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/Setup.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/B/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.out b/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.test.hs new file mode 100644 index 00000000000..c09a36a274f --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/build-info-lib-exact.test.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["lib:B", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly one" 1 (length buildInfos) + let [buildInfo] = buildInfos + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "lib" (componentType component) + assertEqual "Component name" "lib" (componentName component) + assertEqual "Component unit-id" "B-0.1.0.0-inplace" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertEqual "Component modules" ["A"] (componentModules component) + assertEqual "Component source files" [] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + return () + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/cabal.project b/cabal-testsuite/PackageTests/ShowBuildInfo/B/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/B/src/A.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/B/src/A.hs new file mode 100644 index 00000000000..ad7a0c07729 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/B/src/A.hs @@ -0,0 +1,4 @@ +module A where + +foo :: Int -> Int +foo = id \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/CHANGELOG.md b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/CHANGELOG.md new file mode 100644 index 00000000000..624468cdfdb --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for Complex + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Complex.cabal b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Complex.cabal new file mode 100644 index 00000000000..9047830cd4f --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Complex.cabal @@ -0,0 +1,54 @@ +cabal-version: 2.4 +name: Complex +version: 0.1.0.0 +license: MIT +license-file: LICENSE +author: Bla Bla +maintainer: "" +category: Testing +extra-source-files: CHANGELOG.md + + +library + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 + exposed-modules: Lib + other-modules: Paths_complex + + ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall + +executable Complex + main-is: Main.lhs + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 + other-modules: Paths_complex + ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wredundant-constraints + -with-rtsopts=-T + +test-suite unit-test + type: exitcode-stdio-1.0 + hs-source-dirs: test + build-depends: hspec + main-is: Main.hs + +test-suite func-test + type: exitcode-stdio-1.0 + hs-source-dirs: test + build-depends: hspec + main-is: Main.hs + +benchmark complex-benchmarks + type: exitcode-stdio-1.0 + main-is: Main.hs + other-modules: + Paths_complex + hs-source-dirs: + benchmark + ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N + build-depends: + base + , criterion + , Complex + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/LICENSE b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/LICENSE new file mode 100644 index 00000000000..a234fc7e8dd --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2019 Bla Bla + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Setup.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/cabal.project b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/cabal.project new file mode 100644 index 00000000000..5356e76f67c --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/cabal.project @@ -0,0 +1 @@ +packages: . \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.out b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.test.hs new file mode 100644 index 00000000000..e56a02600ff --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/exe.test.hs @@ -0,0 +1,84 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["exe:Complex", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly one" 1 (length buildInfos) + let [buildInfo] = buildInfos + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "exe" (componentType component) + assertEqual "Component name" "exe:Complex" (componentName component) + assertEqual "Component unit-id" "Complex-0.1.0.0-inplace-Complex" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertBool "Component ghc-options contains all specified in .cabal" + (all + (`elem` componentCompilerArgs component) + [ "-threaded" + , "-rtsopts" + , "-with-rtsopts=-N" + , "-with-rtsopts=-T" + , "-Wredundant-constraints" + ] + ) + assertBool "Component ghc-options does not contain -Wall" + (all + (`notElem` componentCompilerArgs component) + [ "-Wall" + ] + ) + assertEqual "Component modules" ["Paths_complex"] (componentModules component) + assertEqual "Component source files" ["Main.lhs"] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + return () + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.out b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.out new file mode 100644 index 00000000000..6fbda9790b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.out @@ -0,0 +1 @@ +# cabal show-build-info diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.test.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.test.hs new file mode 100644 index 00000000000..d119eb633d9 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/lib.test.hs @@ -0,0 +1,83 @@ +{-# LANGUAGE DeriveGeneric #-} +import Test.Cabal.Prelude + +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Data.Aeson +import GHC.Generics + +main = cabalTest $ do + r <- cabal' "show-build-info" ["lib:Complex", "-v0"] + let buildInfoEither = eitherDecodeStrict (T.encodeUtf8 . T.pack $ resultOutput r) :: Either String [BuildInfo] + case buildInfoEither of + Left err -> fail $ "Could not parse build-info command" ++ err + Right buildInfos -> do + assertEqual "Build Infos, exactly one" 1 (length buildInfos) + let [buildInfo] = buildInfos + assertEqual "Cabal Version" "3.1.0.0" (cabalVersion buildInfo) + assertEqual "Compiler flavour" "ghc" (flavour $ compiler buildInfo) + assertBool "Compiler id" (and $ zipWith (==) "ghc" (compilerId $ compiler buildInfo)) + assertBool "Compiler path non-empty" (not . null . path $ compiler buildInfo) + assertEqual "Components, exactly one" 1 (length $ components buildInfo) + let [component] = components buildInfo + assertEqual "Component type" "lib" (componentType component) + assertEqual "Component name" "lib" (componentName component) + assertEqual "Component unit-id" "Complex-0.1.0.0-inplace" (componentUnitId component) + assertBool "Component compiler args are non-empty" (not . null $ componentCompilerArgs component) + assertBool "Component ghc-options contains all specified in .cabal" + (all + (`elem` componentCompilerArgs component) + [ "-threaded" + , "-rtsopts" + , "-with-rtsopts=-N" + , "-Wall" + ] + ) + assertBool "Component ghc-options does not contain -Wredundant-constraints" + (all + (`notElem` componentCompilerArgs component) + [ "-Wredundant-constraints" + ] + ) + assertEqual "Component modules" ["Lib", "Paths_complex"] (componentModules component) + assertEqual "Component source files" [] (componentSrcFiles component) + assertEqual "Component source directories" ["src"] (componentSrcDirs component) + return () + +data BuildInfo = BuildInfo + { cabalVersion :: String + , compiler :: CompilerInfo + , components :: [ComponentInfo] + } deriving (Generic, Show) + +data CompilerInfo = CompilerInfo + { flavour :: String + , compilerId :: String + , path :: String + } deriving (Generic, Show) + +data ComponentInfo = ComponentInfo + { componentType :: String + , componentName :: String + , componentUnitId :: String + , componentCompilerArgs :: [String] + , componentModules :: [String] + , componentSrcFiles :: [String] + , componentSrcDirs :: [String] + } deriving (Generic, Show) + +instance ToJSON BuildInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON BuildInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + + +instance ToJSON CompilerInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON CompilerInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo2 '-' } + +instance ToJSON ComponentInfo where + toEncoding = genericToEncoding defaultOptions +instance FromJSON ComponentInfo where + parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = drop 10 . camelTo2 '-' } \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Lib.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Lib.hs new file mode 100644 index 00000000000..5d35e3e9617 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Lib.hs @@ -0,0 +1,4 @@ +module Lib where + +foo :: Int -> Int +foo = (+1) \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Main.lhs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Main.lhs new file mode 100644 index 00000000000..a1b75006b8d --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/src/Main.lhs @@ -0,0 +1,9 @@ +module Main where + +import Lib + +main :: IO () +main = do + let i = foo 5 + putStrLn "Hello, Haskell!" + print i diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/test/Main.hs b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/test/Main.hs new file mode 100644 index 00000000000..3ef47688534 --- /dev/null +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/test/Main.hs @@ -0,0 +1 @@ +main = return () \ No newline at end of file