content: {-# LANGUAGE TupleSections #-}
  
  module Settings (
      getExtraArgs, getArgs, getLibraryWays, getRtsWays, flavour, knownPackages,
      findPackageByName, unsafeFindPackageByName, unsafeFindPackageByPath,
      isLibrary, stagePackages, getBignumBackend, getBignumCheck, completeSetting,
      queryBuildTarget, queryHostTarget, queryTargetTarget,
      queryBuild, queryHost, queryTarget,
      queryArch, queryOS, queryVendor
      ) where
  
  import CommandLine
  import Expression
  import Flavour
  import Packages
  import Settings.Parser
  import UserSettings (userFlavours, userPackages, userDefaultFlavour)
  
  import {-# SOURCE #-} Settings.Default
  import Settings.Flavours.Benchmark
  import Settings.Flavours.Development
  import Settings.Flavours.GhcInGhci
  import Settings.Flavours.Performance
  import Settings.Flavours.Quick
  import Settings.Flavours.Quickest
  import Settings.Flavours.QuickCross
  import Settings.Flavours.Validate
  import Settings.Flavours.Release
  
  import Hadrian.Oracles.TextFile
  import GHC.Toolchain.Target
  import GHC.Platform.ArchOS
  
  getExtraArgs :: Args
  getExtraArgs = expr flavour >>= extraArgs
  
  getArgs :: Args
  getArgs = mconcat [ defaultBuilderArgs, getExtraArgs, defaultPackageArgs ]
  
  getLibraryWays :: Ways
  getLibraryWays = expr flavour >>= libraryWays
  
  getRtsWays :: Ways
  getRtsWays = expr flavour >>= rtsWays
  
  getBignumBackend :: Expr String
  getBignumBackend = expr $ cmdBignum >>= \case
     Nothing -> bignumBackend <$> flavour
     Just b  -> pure b
  
  getBignumCheck :: Expr Bool
  getBignumCheck = expr $ cmdBignum >>= \case
     Nothing -> bignumCheck <$> flavour
     Just _  -> cmdBignumCheck
  
  stagePackages :: Stage -> Action [Package]
  stagePackages stage = do
      f <- flavour
      packages f stage
  
  hadrianFlavours :: [Flavour]
  hadrianFlavours =
      [ benchmarkFlavour, defaultFlavour, developmentFlavour Stage1
      , developmentFlavour Stage2, performanceFlavour
      , releaseFlavour
      , quickFlavour, quickValidateFlavour, quickDebugFlavour
      , quickestFlavour
      , quickCrossFlavour
      , ghcInGhciFlavour, validateFlavour, slowValidateFlavour
      ]
  
  -- | This action looks up a flavour with the name given on the
  --   command line with @--flavour@, defaulting to 'userDefaultFlavour'
  --   when no explicit @--flavour@ is passed. It then applies any
  --   potential setting update specified on the command line or in a
  --   <build root>/hadrian.settings file, using @k = v@ or @k += v@ style
  --   syntax. See Note [Hadrian settings] at the bottom of this file.
  flavour :: Action Flavour
  flavour = do
      flavourName <- fromMaybe userDefaultFlavour <$> cmdFlavour
      kvs <- userSetting ([] :: [KeyVal])
      let flavours = hadrianFlavours ++ userFlavours
          (settingErrs, tweak) = applySettings kvs
  
      -- This used to be a command line argument, and is now a flavour transformer.
      uid_hash_cmd <- cmdUnitIdHash
      let flagsTweak = if uid_hash_cmd then enableHashUnitIds else id
  
      when (not $ null settingErrs) $ fail
        $ "failed to apply key-value settings:\n\t" ++ unlines (map (" - " ++) settingErrs) ++
          "\t   Entries should look something like \"stage1.containers.ghc.hs.opts += -Werror\""
  
      case parseFlavour flavours flavourTransformers flavourName of
        Left err -> fail err
        Right f -> return $ flagsTweak (tweak f)
  
  -- TODO: switch to Set Package as the order of packages should not matter?
  -- Otherwise we have to keep remembering to sort packages from time to time.
  knownPackages :: [Package]
  knownPackages = sort $ ghcPackages ++ userPackages
  
  -- TODO: Speed up? Switch to Set?
  -- Note: this is slow but we keep it simple as there are just ~50 packages
  findPackageByName :: PackageName -> Maybe Package
  findPackageByName name = find (\pkg -> pkgName pkg == name) knownPackages
  
  unsafeFindPackageByName :: PackageName -> Package
  unsafeFindPackageByName name = fromMaybe (error msg) $ findPackageByName name
    where
      msg = "unsafeFindPackageByName: No package with name " ++ name
  
  unsafeFindPackageByPath :: FilePath -> Package
  unsafeFindPackageByPath path = err $ find (\pkg -> pkgPath pkg == path) knownPackages
    where
      err = fromMaybe $ error ("findPackageByPath: No package for path " ++ path)
  
  -- * Combinators for querying configuration defined in the toolchain
  --
  -- Be careful querying values from the HOST and BUILD targets until the targets
  -- are only generated by ghc-toolchain:
  -- See Note [The dummy values in the HOST target description]
  queryBuild, queryHost, queryTarget :: (Target -> a) -> Expr a
  queryBuild  f = expr $ queryBuildTarget f
  queryHost   f = expr $ queryHostTarget f
  queryTarget f = expr $ queryTargetTarget f
  queryArch, queryOS, queryVendor :: Target -> String
  queryArch = stringEncodeArch . archOS_arch . tgtArchOs
  queryOS   = stringEncodeOS . archOS_OS . tgtArchOs
  queryVendor = fromMaybe "" . tgtVendor
  