module Distribution.Client.Init.Simple
( -- * Project creation
  createProject
  -- * Gen targets
, genSimplePkgDesc
, genSimpleLibTarget
, genSimpleExeTarget
, genSimpleTestTarget
) where


import Distribution.Client.Init.Types
import Distribution.Verbosity
import Distribution.Simple.PackageIndex
import Distribution.Client.Types.SourcePackageDb (SourcePackageDb(..))
import qualified Data.List.NonEmpty as NEL
import Distribution.Client.Init.Utils (currentDirPkgName, mkPackageNameDep, fixupDocFiles)
import Distribution.Client.Init.Defaults
import Distribution.Simple.Flag (fromFlagOrDefault, flagElim, Flag (..))
import Distribution.Client.Init.FlagExtractors
import qualified Data.Set as Set
import Distribution.Types.Dependency
import Distribution.Types.PackageName (unPackageName)


createProject
    :: Interactive m
    => Verbosity
    -> InstalledPackageIndex
    -> SourcePackageDb
    -> InitFlags
    -> m ProjectSettings
createProject :: forall (m :: * -> *).
Interactive m =>
Verbosity
-> InstalledPackageIndex
-> SourcePackageDb
-> InitFlags
-> m ProjectSettings
createProject Verbosity
v InstalledPackageIndex
pkgIx SourcePackageDb
_srcDb InitFlags
initFlags = do
    PackageType
pkgType <- forall (m :: * -> *). Interactive m => InitFlags -> m PackageType
packageTypePrompt InitFlags
initFlags
    Bool
isMinimal <- forall (m :: * -> *). Interactive m => InitFlags -> m Bool
getMinimal InitFlags
initFlags
    Bool
doOverwrite <- forall (m :: * -> *). Interactive m => InitFlags -> m Bool
getOverwrite InitFlags
initFlags
    FilePath
pkgDir <- forall (m :: * -> *). Interactive m => InitFlags -> m FilePath
getPackageDir InitFlags
initFlags
    PkgDescription
pkgDesc <- forall (m :: * -> *).
Interactive m =>
Verbosity -> PkgDescription -> m PkgDescription
fixupDocFiles Verbosity
v forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *).
Interactive m =>
InitFlags -> m PkgDescription
genSimplePkgDesc InitFlags
initFlags

    let pkgName :: PackageName
pkgName = PkgDescription -> PackageName
_pkgName PkgDescription
pkgDesc
        cabalSpec :: CabalSpecVersion
cabalSpec = PkgDescription -> CabalSpecVersion
_pkgCabalVersion PkgDescription
pkgDesc
        mkOpts :: Bool -> CabalSpecVersion -> WriteOpts
mkOpts Bool
cs = Bool
-> Bool
-> Bool
-> Verbosity
-> FilePath
-> PackageType
-> PackageName
-> CabalSpecVersion
-> WriteOpts
WriteOpts
          Bool
doOverwrite Bool
isMinimal Bool
cs
          Verbosity
v FilePath
pkgDir PackageType
pkgType PackageName
pkgName

    InitFlags
basedFlags <- forall (m :: * -> *).
Interactive m =>
InstalledPackageIndex -> InitFlags -> m InitFlags
addBaseDepToFlags InstalledPackageIndex
pkgIx InitFlags
initFlags

    case PackageType
pkgType of
      PackageType
Library -> do
        LibTarget
libTarget <- forall (m :: * -> *). Interactive m => InitFlags -> m LibTarget
genSimpleLibTarget InitFlags
basedFlags
        Maybe TestTarget
testTarget <- PackageName -> Maybe TestTarget -> Maybe TestTarget
addLibDepToTest PackageName
pkgName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
Interactive m =>
InitFlags -> m (Maybe TestTarget)
genSimpleTestTarget InitFlags
basedFlags
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ WriteOpts
-> PkgDescription
-> Maybe LibTarget
-> Maybe ExeTarget
-> Maybe TestTarget
-> ProjectSettings
ProjectSettings
          (Bool -> CabalSpecVersion -> WriteOpts
mkOpts Bool
False CabalSpecVersion
cabalSpec) PkgDescription
pkgDesc
          (forall a. a -> Maybe a
Just LibTarget
libTarget) forall a. Maybe a
Nothing Maybe TestTarget
testTarget

      PackageType
Executable -> do
        ExeTarget
exeTarget <- forall (m :: * -> *). Interactive m => InitFlags -> m ExeTarget
genSimpleExeTarget InitFlags
basedFlags
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ WriteOpts
-> PkgDescription
-> Maybe LibTarget
-> Maybe ExeTarget
-> Maybe TestTarget
-> ProjectSettings
ProjectSettings
          (Bool -> CabalSpecVersion -> WriteOpts
mkOpts Bool
False CabalSpecVersion
cabalSpec) PkgDescription
pkgDesc
          forall a. Maybe a
Nothing (forall a. a -> Maybe a
Just ExeTarget
exeTarget) forall a. Maybe a
Nothing

      PackageType
LibraryAndExecutable -> do
        LibTarget
libTarget <- forall (m :: * -> *). Interactive m => InitFlags -> m LibTarget
genSimpleLibTarget InitFlags
basedFlags
        Maybe TestTarget
testTarget <- PackageName -> Maybe TestTarget -> Maybe TestTarget
addLibDepToTest PackageName
pkgName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
Interactive m =>
InitFlags -> m (Maybe TestTarget)
genSimpleTestTarget InitFlags
basedFlags
        ExeTarget
exeTarget <- PackageName -> ExeTarget -> ExeTarget
addLibDepToExe PackageName
pkgName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). Interactive m => InitFlags -> m ExeTarget
genSimpleExeTarget InitFlags
basedFlags
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ WriteOpts
-> PkgDescription
-> Maybe LibTarget
-> Maybe ExeTarget
-> Maybe TestTarget
-> ProjectSettings
ProjectSettings
          (Bool -> CabalSpecVersion -> WriteOpts
mkOpts Bool
False CabalSpecVersion
cabalSpec) PkgDescription
pkgDesc
          (forall a. a -> Maybe a
Just LibTarget
libTarget) (forall a. a -> Maybe a
Just ExeTarget
exeTarget) Maybe TestTarget
testTarget

      PackageType
TestSuite -> do
        Maybe TestTarget
testTarget <- forall (m :: * -> *).
Interactive m =>
InitFlags -> m (Maybe TestTarget)
genSimpleTestTarget InitFlags
basedFlags
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ WriteOpts
-> PkgDescription
-> Maybe LibTarget
-> Maybe ExeTarget
-> Maybe TestTarget
-> ProjectSettings
ProjectSettings
          (Bool -> CabalSpecVersion -> WriteOpts
mkOpts Bool
False CabalSpecVersion
cabalSpec) PkgDescription
pkgDesc
          forall a. Maybe a
Nothing forall a. Maybe a
Nothing Maybe TestTarget
testTarget
  where
    -- Add package name as dependency of test suite
    --
    addLibDepToTest :: PackageName -> Maybe TestTarget -> Maybe TestTarget
addLibDepToTest PackageName
_ Maybe TestTarget
Nothing = forall a. Maybe a
Nothing
    addLibDepToTest PackageName
n (Just TestTarget
t) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ TestTarget
t
      { _testDependencies :: [Dependency]
_testDependencies = TestTarget -> [Dependency]
_testDependencies TestTarget
t forall a. [a] -> [a] -> [a]
++ [PackageName -> Dependency
mkPackageNameDep PackageName
n]
      }

    -- Add package name as dependency of executable
    --
    addLibDepToExe :: PackageName -> ExeTarget -> ExeTarget
addLibDepToExe PackageName
n ExeTarget
exe = ExeTarget
exe
      { _exeDependencies :: [Dependency]
_exeDependencies = ExeTarget -> [Dependency]
_exeDependencies ExeTarget
exe forall a. [a] -> [a] -> [a]
++ [PackageName -> Dependency
mkPackageNameDep PackageName
n]
      }

genSimplePkgDesc :: Interactive m => InitFlags -> m PkgDescription
genSimplePkgDesc :: forall (m :: * -> *).
Interactive m =>
InitFlags -> m PkgDescription
genSimplePkgDesc InitFlags
flags = PackageName -> PkgDescription
mkPkgDesc forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). Interactive m => m PackageName
currentDirPkgName
  where
    defaultExtraDoc :: Maybe (Set FilePath)
defaultExtraDoc = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. a -> Set a
Set.singleton FilePath
defaultChangelog

    extractExtraDoc :: [FilePath] -> Maybe (Set FilePath)
extractExtraDoc [] = Maybe (Set FilePath)
defaultExtraDoc
    extractExtraDoc [FilePath]
fs = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Ord a => [a] -> Set a
Set.fromList [FilePath]
fs

    mkPkgDesc :: PackageName -> PkgDescription
mkPkgDesc PackageName
pkgName = CabalSpecVersion
-> PackageName
-> Version
-> SpecLicense
-> FilePath
-> FilePath
-> FilePath
-> FilePath
-> FilePath
-> Set FilePath
-> Maybe (Set FilePath)
-> PkgDescription
PkgDescription
      (forall a. a -> Flag a -> a
fromFlagOrDefault CabalSpecVersion
defaultCabalVersion (InitFlags -> Flag CabalSpecVersion
cabalVersion InitFlags
flags))
      PackageName
pkgName
      (forall a. a -> Flag a -> a
fromFlagOrDefault Version
defaultVersion (InitFlags -> Flag Version
version InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault (CabalSpecVersion -> SpecLicense
defaultLicense forall a b. (a -> b) -> a -> b
$ InitFlags -> CabalSpecVersion
getCabalVersionNoPrompt InitFlags
flags) (InitFlags -> Flag SpecLicense
license InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault FilePath
"" (InitFlags -> Flag FilePath
author InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault FilePath
"" (InitFlags -> Flag FilePath
email InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault FilePath
"" (InitFlags -> Flag FilePath
homepage InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault FilePath
"" (InitFlags -> Flag FilePath
synopsis InitFlags
flags))
      (forall a. a -> Flag a -> a
fromFlagOrDefault FilePath
"" (InitFlags -> Flag FilePath
category InitFlags
flags))
      (forall b a. b -> (a -> b) -> Flag a -> b
flagElim forall a. Monoid a => a
mempty forall a. Ord a => [a] -> Set a
Set.fromList (InitFlags -> Flag [FilePath]
extraSrc InitFlags
flags))
      (forall b a. b -> (a -> b) -> Flag a -> b
flagElim Maybe (Set FilePath)
defaultExtraDoc [FilePath] -> Maybe (Set FilePath)
extractExtraDoc (InitFlags -> Flag [FilePath]
extraDoc InitFlags
flags))

genSimpleLibTarget :: Interactive m => InitFlags -> m LibTarget
genSimpleLibTarget :: forall (m :: * -> *). Interactive m => InitFlags -> m LibTarget
genSimpleLibTarget InitFlags
flags = do
    [Dependency]
buildToolDeps <- forall (m :: * -> *). Interactive m => InitFlags -> m [Dependency]
getBuildTools InitFlags
flags
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ LibTarget
      { _libSourceDirs :: [FilePath]
_libSourceDirs = forall a. a -> Flag a -> a
fromFlagOrDefault [FilePath
defaultSourceDir] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [FilePath]
sourceDirs InitFlags
flags
      , _libLanguage :: Language
_libLanguage = forall a. a -> Flag a -> a
fromFlagOrDefault Language
defaultLanguage forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag Language
language InitFlags
flags
      , _libExposedModules :: NonEmpty ModuleName
_libExposedModules =
        forall b a. b -> (a -> b) -> Flag a -> b
flagElim (ModuleName
myLibModule forall a. a -> [a] -> NonEmpty a
NEL.:| []) [ModuleName] -> NonEmpty ModuleName
extractMods forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [ModuleName]
exposedModules InitFlags
flags
      , _libOtherModules :: [ModuleName]
_libOtherModules = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [ModuleName]
otherModules InitFlags
flags
      , _libOtherExts :: [Extension]
_libOtherExts = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Extension]
otherExts InitFlags
flags
      , _libDependencies :: [Dependency]
_libDependencies = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Dependency]
dependencies InitFlags
flags
      , _libBuildTools :: [Dependency]
_libBuildTools = [Dependency]
buildToolDeps
      }

  where
    extractMods :: [ModuleName] -> NonEmpty ModuleName
extractMods [] = ModuleName
myLibModule forall a. a -> [a] -> NonEmpty a
NEL.:| []
    extractMods [ModuleName]
as = forall a. [a] -> NonEmpty a
NEL.fromList [ModuleName]
as

genSimpleExeTarget :: Interactive m => InitFlags -> m ExeTarget
genSimpleExeTarget :: forall (m :: * -> *). Interactive m => InitFlags -> m ExeTarget
genSimpleExeTarget InitFlags
flags = do
    [Dependency]
buildToolDeps <- forall (m :: * -> *). Interactive m => InitFlags -> m [Dependency]
getBuildTools InitFlags
flags
    forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ExeTarget
      { _exeMainIs :: HsFilePath
_exeMainIs = forall b a. b -> (a -> b) -> Flag a -> b
flagElim HsFilePath
defaultMainIs FilePath -> HsFilePath
toHsFilePath forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag FilePath
mainIs InitFlags
flags
      , _exeApplicationDirs :: [FilePath]
_exeApplicationDirs  =
        forall a. a -> Flag a -> a
fromFlagOrDefault [FilePath
defaultApplicationDir] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [FilePath]
applicationDirs InitFlags
flags
      , _exeLanguage :: Language
_exeLanguage = forall a. a -> Flag a -> a
fromFlagOrDefault Language
defaultLanguage forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag Language
language InitFlags
flags
      , _exeOtherModules :: [ModuleName]
_exeOtherModules = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [ModuleName]
otherModules InitFlags
flags
      , _exeOtherExts :: [Extension]
_exeOtherExts = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Extension]
otherExts InitFlags
flags
      , _exeDependencies :: [Dependency]
_exeDependencies = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Dependency]
dependencies InitFlags
flags
      , _exeBuildTools :: [Dependency]
_exeBuildTools = [Dependency]
buildToolDeps
      }

genSimpleTestTarget :: Interactive m => InitFlags -> m (Maybe TestTarget)
genSimpleTestTarget :: forall (m :: * -> *).
Interactive m =>
InitFlags -> m (Maybe TestTarget)
genSimpleTestTarget InitFlags
flags = forall {m :: * -> *}. Interactive m => Bool -> m (Maybe TestTarget)
go forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *). Interactive m => InitFlags -> m Bool
initializeTestSuitePrompt InitFlags
flags
  where
    go :: Bool -> m (Maybe TestTarget)
go Bool
initialized
      | Bool -> Bool
not Bool
initialized = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
      | Bool
otherwise = do
        [Dependency]
buildToolDeps <- forall (m :: * -> *). Interactive m => InitFlags -> m [Dependency]
getBuildTools InitFlags
flags
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ TestTarget
          { _testMainIs :: HsFilePath
_testMainIs = forall b a. b -> (a -> b) -> Flag a -> b
flagElim HsFilePath
defaultMainIs FilePath -> HsFilePath
toHsFilePath forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag FilePath
mainIs InitFlags
flags
          , _testDirs :: [FilePath]
_testDirs  = forall a. a -> Flag a -> a
fromFlagOrDefault [FilePath
defaultTestDir] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [FilePath]
testDirs InitFlags
flags
          , _testLanguage :: Language
_testLanguage = forall a. a -> Flag a -> a
fromFlagOrDefault Language
defaultLanguage forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag Language
language InitFlags
flags
          , _testOtherModules :: [ModuleName]
_testOtherModules = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [ModuleName]
otherModules InitFlags
flags
          , _testOtherExts :: [Extension]
_testOtherExts = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Extension]
otherExts InitFlags
flags
          , _testDependencies :: [Dependency]
_testDependencies = forall a. a -> Flag a -> a
fromFlagOrDefault [] forall a b. (a -> b) -> a -> b
$ InitFlags -> Flag [Dependency]
dependencies InitFlags
flags
          , _testBuildTools :: [Dependency]
_testBuildTools = [Dependency]
buildToolDeps
          }

-- -------------------------------------------------------------------- --
-- Utils

-- | If deps are defined, and base is present, we skip the search for base.
-- otherwise, we look up @base@ and add it to the list.
addBaseDepToFlags :: Interactive m => InstalledPackageIndex -> InitFlags -> m InitFlags
addBaseDepToFlags :: forall (m :: * -> *).
Interactive m =>
InstalledPackageIndex -> InitFlags -> m InitFlags
addBaseDepToFlags InstalledPackageIndex
pkgIx InitFlags
initFlags = case InitFlags -> Flag [Dependency]
dependencies InitFlags
initFlags of
  Flag [Dependency]
as
    | forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall a. Eq a => a -> a -> Bool
(==) FilePath
"base" forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> FilePath
unPackageName forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dependency -> PackageName
depPkgName) [Dependency]
as -> forall (m :: * -> *) a. Monad m => a -> m a
return InitFlags
initFlags
    | Bool
otherwise -> do
      [Dependency]
based <- forall (m :: * -> *).
Interactive m =>
InstalledPackageIndex -> InitFlags -> m [Dependency]
dependenciesPrompt InstalledPackageIndex
pkgIx InitFlags
initFlags
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ InitFlags
initFlags
        { dependencies :: Flag [Dependency]
dependencies = forall a. a -> Flag a
Flag forall a b. (a -> b) -> a -> b
$ [Dependency]
based forall a. [a] -> [a] -> [a]
++ [Dependency]
as
        }
  Flag [Dependency]
NoFlag -> do
    [Dependency]
based <- forall (m :: * -> *).
Interactive m =>
InstalledPackageIndex -> InitFlags -> m [Dependency]
dependenciesPrompt InstalledPackageIndex
pkgIx InitFlags
initFlags
    forall (m :: * -> *) a. Monad m => a -> m a
return InitFlags
initFlags { dependencies :: Flag [Dependency]
dependencies = forall a. a -> Flag a
Flag [Dependency]
based }