packages feed

stack 0.1.5.0 → 0.1.6.0

raw patch · 58 files changed

+5937/−975 lines, 58 filesdep +ansi-terminaldep +hpcdep ~Cabaldep ~aesondep ~asyncPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: ansi-terminal, hpc

Dependency ranges changed: Cabal, aeson, async, attoparsec, base16-bytestring, base64-bytestring, bifunctors, binary, binary-tagged, blaze-builder, byteable, bytestring, conduit, conduit-combinators, conduit-extra, containers, cryptohash, cryptohash-conduit, deepseq, directory, either, enclosed-exceptions, exceptions, extra, fast-logger, file-embed, filelock, filepath, fsnotify, gitrev, hashable, hastache, http-client, http-client-tls, http-conduit, http-types, ignore, lifted-base, monad-control, monad-logger, monad-loops, mtl, old-locale, optparse-applicative, optparse-simple, path, persistent, persistent-sqlite, persistent-template, pretty, process, project-template, resourcet, retry, safe, split, stack, stm, streaming-commons, tar, template-haskell, temporary, text, time, transformers, transformers-base, unix-compat, unordered-containers, vector, vector-binary-instances, void, word8, yaml, zlib

API changes (from Hackage documentation)

- Stack.Constants: globalConfigPath :: Config -> Path Abs File
- Stack.Constants: implicitGlobalDir :: Path Abs Dir -> Path Abs Dir
- Stack.Docker: dockerOptsFromMonoid :: Maybe Project -> Path Abs Dir -> DockerOptsMonoid -> DockerOpts
- Stack.Setup: ensureGHC :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, HasGHCVariant env, MonadBaseControl IO m) => SetupOpts -> m (Maybe ExtraDirs)
- Stack.Setup: instance GHC.Base.Monoid Stack.Setup.ExtraDirs
- Stack.Solver: getCompilerVersion :: (MonadLogger m, MonadCatch m, MonadBaseControl IO m, MonadIO m) => EnvOverride -> WhichCompiler -> m CompilerVersion
- Stack.Types.Build: instance GHC.Classes.Eq Stack.Types.Build.Installed
- Stack.Types.Build: instance GHC.Classes.Ord Stack.Types.Build.Installed
- Stack.Types.Build: instance GHC.Show.Show Stack.Types.Build.Installed
- Stack.Types.Compiler: compilerVersionName :: CompilerVersion -> Text
- Stack.Types.Config: [globalModifyCodePage] :: GlobalOpts -> !Bool
- Stack.Types.Config: [globalReExec] :: GlobalOpts -> !Bool
- Stack.Types.Config: hpcDirSuffix :: Path Rel Dir
- Stack.Types.Docker: [dockerMonoidExists] :: DockerOptsMonoid -> !(Maybe Bool)
+ Path.IO: withCanonicalizedSystemTempDirectory :: (MonadMask m, MonadIO m) => String -> (Path Abs Dir -> m a) -> m a
+ Path.IO: withCanonicalizedTempDirectory :: (MonadMask m, MonadIO m) => FilePath -> String -> (Path Abs Dir -> m a) -> m a
+ Stack.Build: queryBuildInfo :: M env m => [Text] -> m ()
+ Stack.Build.Coverage: generateHpcUnifiedReport :: (MonadIO m, MonadReader env m, HasConfig env, MonadLogger m, MonadBaseControl IO m, MonadCatch m, HasEnvConfig env) => m ()
+ Stack.Build.Coverage: updateTixFile :: (MonadIO m, MonadReader env m, HasConfig env, MonadLogger m, MonadBaseControl IO m, MonadCatch m, HasEnvConfig env) => Path Abs File -> String -> m ()
+ Stack.Config: getImplicitGlobalProjectDir :: (MonadIO m, MonadLogger m) => Config -> m (Path Abs Dir)
+ Stack.Config: getIsGMP4 :: (MonadIO m, MonadBaseControl IO m, MonadCatch m, MonadLogger m) => EnvOverride -> m Bool
+ Stack.Config.Docker: InvalidDatabasePathException :: SomeException -> StackDockerConfigException
+ Stack.Config.Docker: ResolverNotSupportedException :: String -> StackDockerConfigException
+ Stack.Config.Docker: data StackDockerConfigException
+ Stack.Config.Docker: dockerOptsFromMonoid :: MonadThrow m => Maybe Project -> Path Abs Dir -> DockerOptsMonoid -> m DockerOpts
+ Stack.Config.Docker: instance GHC.Exception.Exception Stack.Config.Docker.StackDockerConfigException
+ Stack.Config.Docker: instance GHC.Show.Show Stack.Config.Docker.StackDockerConfigException
+ Stack.Constants: defaultGlobalConfigPath :: Maybe (Path Abs File)
+ Stack.Constants: defaultGlobalConfigPathDeprecated :: Maybe (Path Abs File)
+ Stack.Constants: defaultUserConfigPath :: Path Abs Dir -> Path Abs File
+ Stack.Constants: defaultUserConfigPathDeprecated :: Path Abs Dir -> Path Abs File
+ Stack.Constants: implicitGlobalProjectDir :: Path Abs Dir -> Path Abs Dir
+ Stack.Constants: implicitGlobalProjectDirDeprecated :: Path Abs Dir -> Path Abs Dir
+ Stack.Docker.GlobalDB: getDockerImageExe :: Config -> String -> FilePath -> UTCTime -> IO (Maybe Bool)
+ Stack.Docker.GlobalDB: instance Data.Aeson.Types.Class.FromJSON (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance Data.Aeson.Types.Class.ToJSON (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance Database.Persist.Class.PersistEntity.PersistEntity Stack.Docker.GlobalDB.DockerImageExe
+ Stack.Docker.GlobalDB: instance Database.Persist.Class.PersistField.PersistField (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance Database.Persist.Class.PersistField.PersistField Stack.Docker.GlobalDB.DockerImageExe
+ Stack.Docker.GlobalDB: instance Database.Persist.Class.PersistStore.ToBackendKey Database.Persist.Sql.Types.SqlBackend Stack.Docker.GlobalDB.DockerImageExe
+ Stack.Docker.GlobalDB: instance Database.Persist.Sql.Class.PersistFieldSql (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance Database.Persist.Sql.Class.PersistFieldSql Stack.Docker.GlobalDB.DockerImageExe
+ Stack.Docker.GlobalDB: instance GHC.Classes.Eq (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance GHC.Classes.Ord (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance GHC.Read.Read (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance GHC.Show.Show (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: instance GHC.Show.Show Stack.Docker.GlobalDB.DockerImageExe
+ Stack.Docker.GlobalDB: instance Web.PathPieces.PathPiece (Database.Persist.Class.PersistEntity.Key Stack.Docker.GlobalDB.DockerImageExe)
+ Stack.Docker.GlobalDB: setDockerImageExe :: Config -> String -> FilePath -> UTCTime -> Bool -> IO ()
+ Stack.Docker.GlobalDB: type DockerImageExeId = Key DockerImageExe
+ Stack.Ghci: [ghciPkgCFiles] :: GhciPkgInfo -> Set (Path Abs File)
+ Stack.Ide: getPackageOptsAndTargetFiles :: (MonadThrow m, MonadIO m, MonadReader env m, HasEnvConfig env) => Path Abs Dir -> GhciPkgInfo -> m ([FilePath], [FilePath])
+ Stack.Init: getImplicitGlobalProjectDir :: (MonadIO m, MonadLogger m) => Config -> m (Path Abs Dir)
+ Stack.Init: tryDeprecatedPath :: (MonadIO m, MonadLogger m) => Maybe Text -> (Path Abs a -> m Bool) -> Path Abs a -> Path Abs a -> m (Path Abs a, Bool)
+ Stack.New: [newOptsCreateBare] :: NewOpts -> Bool
+ Stack.Options: evalOptsParser :: Maybe String -> Parser EvalOpts
+ Stack.Setup: ensureCompiler :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, HasGHCVariant env, MonadBaseControl IO m) => SetupOpts -> m (Maybe ExtraDirs)
+ Stack.Setup: ensureDockerStackExe :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m) => Platform -> m (Path Abs File)
+ Stack.Setup.Installed: ExtraDirs :: ![FilePath] -> ![FilePath] -> ![FilePath] -> ExtraDirs
+ Stack.Setup.Installed: Tool :: PackageIdentifier -> Tool
+ Stack.Setup.Installed: ToolGhcjs :: CompilerVersion -> Tool
+ Stack.Setup.Installed: [edBins] :: ExtraDirs -> ![FilePath]
+ Stack.Setup.Installed: [edInclude] :: ExtraDirs -> ![FilePath]
+ Stack.Setup.Installed: [edLib] :: ExtraDirs -> ![FilePath]
+ Stack.Setup.Installed: data ExtraDirs
+ Stack.Setup.Installed: data Tool
+ Stack.Setup.Installed: extraDirs :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m) => Tool -> m ExtraDirs
+ Stack.Setup.Installed: getCompilerVersion :: (MonadLogger m, MonadCatch m, MonadBaseControl IO m, MonadIO m) => EnvOverride -> WhichCompiler -> m CompilerVersion
+ Stack.Setup.Installed: installDir :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m) => Path Abs Dir -> Tool -> m (Path Abs Dir)
+ Stack.Setup.Installed: instance GHC.Base.Monoid Stack.Setup.Installed.ExtraDirs
+ Stack.Setup.Installed: listInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m) => m [Tool]
+ Stack.Setup.Installed: markInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m) => Tool -> m ()
+ Stack.Setup.Installed: parseToolText :: Text -> Maybe Tool
+ Stack.Setup.Installed: toolNameString :: Tool -> String
+ Stack.Setup.Installed: toolString :: Tool -> String
+ Stack.Setup.Installed: unmarkInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m) => Tool -> m ()
+ Stack.Types.Build: SolverMissingCabalInstall :: StackBuildException
+ Stack.Types.Build: SolverMissingGHC :: StackBuildException
+ Stack.Types.Build: [bcoExtraDBs] :: BaseConfigOpts -> ![(Path Abs Dir)]
+ Stack.Types.Compiler: compilerVersionString :: CompilerVersion -> String
+ Stack.Types.Compiler: compilerVersionText :: CompilerVersion -> Text
+ Stack.Types.Compiler: instance Data.Aeson.Types.Class.FromJSON a => Data.Aeson.Types.Class.FromJSON (Data.Map.Base.Map Stack.Types.Compiler.CompilerVersion a)
+ Stack.Types.Config: AGOEverything :: ApplyGhcOptions
+ Stack.Types.Config: AGOLocals :: ApplyGhcOptions
+ Stack.Types.Config: AGOTargets :: ApplyGhcOptions
+ Stack.Types.Config: EvalOpts :: !String -> !ExecOptsExtra -> EvalOpts
+ Stack.Types.Config: [bcExtraPackageDBs] :: BuildConfig -> ![Path Abs Dir]
+ Stack.Types.Config: [configApplyGhcOptions] :: Config -> !ApplyGhcOptions
+ Stack.Types.Config: [configExplicitSetupDeps] :: Config -> !(Map (Maybe PackageName) Bool)
+ Stack.Types.Config: [configLocalProgramsBase] :: Config -> !(Path Abs Dir)
+ Stack.Types.Config: [configModifyCodePage] :: Config -> !Bool
+ Stack.Types.Config: [configMonoidApplyGhcOptions] :: ConfigMonoid -> !(Maybe ApplyGhcOptions)
+ Stack.Types.Config: [configMonoidExplicitSetupDeps] :: ConfigMonoid -> !(Map (Maybe PackageName) Bool)
+ Stack.Types.Config: [configMonoidModifyCodePage] :: ConfigMonoid -> !(Maybe Bool)
+ Stack.Types.Config: [configMonoidRebuildGhcOptions] :: ConfigMonoid -> !(Maybe Bool)
+ Stack.Types.Config: [configRebuildGhcOptions] :: Config -> !Bool
+ Stack.Types.Config: [configUserConfigPath] :: Config -> !(Path Abs File)
+ Stack.Types.Config: [evalArg] :: EvalOpts -> !String
+ Stack.Types.Config: [evalExtra] :: EvalOpts -> !ExecOptsExtra
+ Stack.Types.Config: [globalReExecVersion] :: GlobalOpts -> !(Maybe String)
+ Stack.Types.Config: [projectExtraPackageDBs] :: Project -> ![FilePath]
+ Stack.Types.Config: [siGHCJSs] :: SetupInfo -> Map Text (Map CompilerVersion DownloadInfo)
+ Stack.Types.Config: [siStack] :: SetupInfo -> Map Text (Map Version DownloadInfo)
+ Stack.Types.Config: data ApplyGhcOptions
+ Stack.Types.Config: data EvalOpts
+ Stack.Types.Config: explicitSetupDeps :: (MonadReader env m, HasConfig env) => PackageName -> m Bool
+ Stack.Types.Config: hpcReportDir :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => m (Path Abs Dir)
+ Stack.Types.Config: instance Data.Aeson.Types.Class.FromJSON Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Classes.Eq Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Classes.Ord Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Enum.Bounded Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Enum.Enum Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Read.Read Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: instance GHC.Show.Show Stack.Types.Config.ApplyGhcOptions
+ Stack.Types.Config: packageDatabaseExtra :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => m [Path Abs Dir]
+ Stack.Types.Docker: DockerStackExeDownload :: DockerStackExe
+ Stack.Types.Docker: DockerStackExeHost :: DockerStackExe
+ Stack.Types.Docker: DockerStackExeImage :: DockerStackExe
+ Stack.Types.Docker: DockerStackExePath :: (Path Abs File) -> DockerStackExe
+ Stack.Types.Docker: [dockerMonoidDefaultEnable] :: DockerOptsMonoid -> !Bool
+ Stack.Types.Docker: [dockerMonoidSetUser] :: DockerOptsMonoid -> !(Maybe Bool)
+ Stack.Types.Docker: [dockerMonoidStackExe] :: DockerOptsMonoid -> !(Maybe String)
+ Stack.Types.Docker: [dockerSetUser] :: DockerOpts -> !(Maybe Bool)
+ Stack.Types.Docker: [dockerStackExe] :: DockerOpts -> !(Maybe DockerStackExe)
+ Stack.Types.Docker: data DockerStackExe
+ Stack.Types.Docker: dockerSetUserArgName :: Text
+ Stack.Types.Docker: dockerStackExeArgName :: Text
+ Stack.Types.Docker: dockerStackExeDownloadVal :: String
+ Stack.Types.Docker: dockerStackExeHostVal :: String
+ Stack.Types.Docker: dockerStackExeImageVal :: String
+ Stack.Types.Docker: instance GHC.Show.Show Stack.Types.Docker.DockerStackExe
+ Stack.Types.Docker: parseDockerStackExe :: (MonadThrow m) => String -> m DockerStackExe
+ Stack.Types.Package: Executable :: PackageIdentifier -> Installed
+ Stack.Types.Package: ExtraGlobal :: InstalledPackageLocation
+ Stack.Types.Package: InstalledTo :: InstallLocation -> InstalledPackageLocation
+ Stack.Types.Package: Library :: PackageIdentifier -> GhcPkgId -> Installed
+ Stack.Types.Package: data Installed
+ Stack.Types.Package: data InstalledPackageLocation
+ Stack.Types.Package: instance GHC.Classes.Eq Stack.Types.Package.Installed
+ Stack.Types.Package: instance GHC.Classes.Eq Stack.Types.Package.InstalledPackageLocation
+ Stack.Types.Package: instance GHC.Classes.Ord Stack.Types.Package.Installed
+ Stack.Types.Package: instance GHC.Show.Show Stack.Types.Package.Installed
+ Stack.Types.Package: instance GHC.Show.Show Stack.Types.Package.InstalledPackageLocation
+ Stack.Types.Package: type InstalledMap = Map PackageName (Version, InstallLocation, Installed)
+ System.Process.Read: [eoPlatform] :: EnvOverride -> Platform
+ System.Process.Read: modifyEnvOverride :: MonadIO m => EnvOverride -> (Map Text Text -> Map Text Text) -> m EnvOverride
+ System.Process.Read: sinkProcessStderrStdout :: (MonadIO m, MonadLogger m) => Maybe (Path Abs Dir) -> EnvOverride -> String -> [String] -> Sink ByteString IO e -> Sink ByteString IO o -> m (e, o)
- Stack.Build.Cache: readPrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m) => PackageIdentifier -> ConfigureOpts -> m (Maybe PrecompiledCache)
+ Stack.Build.Cache: readPrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m) => PackageIdentifier -> ConfigureOpts -> Set GhcPkgId -> m (Maybe PrecompiledCache)
- Stack.Build.Cache: writePrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m) => BaseConfigOpts -> PackageIdentifier -> ConfigureOpts -> Maybe GhcPkgId -> Set Text -> m ()
+ Stack.Build.Cache: writePrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m) => BaseConfigOpts -> PackageIdentifier -> ConfigureOpts -> Set GhcPkgId -> Maybe GhcPkgId -> Set Text -> m ()
- Stack.Build.Coverage: generateHpcReport :: (MonadIO m, MonadReader env m, HasConfig env, MonadLogger m, MonadBaseControl IO m, MonadCatch m, HasEnvConfig env) => Path Abs Dir -> Package -> [Text] -> (PackageName -> m (Maybe Text)) -> m ()
+ Stack.Build.Coverage: generateHpcReport :: (MonadIO m, MonadReader env m, HasConfig env, MonadLogger m, MonadBaseControl IO m, MonadCatch m, HasEnvConfig env) => Package -> [Text] -> (PackageName -> m (Maybe Text)) -> m ()
- Stack.Docker: execWithOptionalContainer :: M env m => Maybe (Path Abs Dir) -> IO (FilePath, [String], [(String, String)], Config -> Config) -> Maybe (m ()) -> IO () -> Maybe (m ()) -> Maybe (m ()) -> m ()
+ Stack.Docker: execWithOptionalContainer :: M env m => Maybe (Path Abs Dir) -> (EnvOverride -> Inspect -> m (FilePath, [String], [(String, String)], [Mount])) -> Maybe (m ()) -> IO () -> Maybe (m ()) -> Maybe (m ()) -> m ()
- Stack.Ghci: GhciPkgInfo :: PackageName -> [String] -> Path Abs Dir -> Set ModuleName -> Set (Path Abs File) -> Map NamedComponent (Set (Path Abs File)) -> GhciPkgInfo
+ Stack.Ghci: GhciPkgInfo :: PackageName -> [String] -> Path Abs Dir -> Set ModuleName -> Set (Path Abs File) -> Set (Path Abs File) -> Map NamedComponent (Set (Path Abs File)) -> GhciPkgInfo
- Stack.New: NewOpts :: PackageName -> TemplateName -> Map Text Text -> NewOpts
+ Stack.New: NewOpts :: PackageName -> Bool -> TemplateName -> Map Text Text -> NewOpts
- Stack.Package: GetPackageOpts :: (forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])) -> GetPackageOpts
+ Stack.Package: GetPackageOpts :: (forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> InstalledMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])) -> GetPackageOpts
- Stack.Package: [getPackageOpts] :: GetPackageOpts -> forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])
+ Stack.Package: [getPackageOpts] :: GetPackageOpts -> forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> InstalledMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])
- Stack.PackageDump: ghcPkgDump :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, MonadCatch m, MonadThrow m) => EnvOverride -> WhichCompiler -> Maybe (Path Abs Dir) -> Sink ByteString IO a -> m a
+ Stack.PackageDump: ghcPkgDump :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, MonadCatch m, MonadThrow m) => EnvOverride -> WhichCompiler -> [Path Abs Dir] -> Sink ByteString IO a -> m a
- Stack.Solver: cabalSolver :: (MonadIO m, MonadLogger m, MonadMask m, MonadBaseControl IO m, MonadReader env m, HasConfig env) => WhichCompiler -> [Path Abs Dir] -> Map PackageName Version -> [String] -> m (CompilerVersion, Map PackageName (Version, Map FlagName Bool))
+ Stack.Solver: cabalSolver :: (MonadIO m, MonadLogger m, MonadMask m, MonadBaseControl IO m, MonadReader env m, HasConfig env) => WhichCompiler -> [Path Abs Dir] -> Map PackageName Version -> Map PackageName (Map FlagName Bool) -> [String] -> m (CompilerVersion, Map PackageName (Version, Map FlagName Bool))
- Stack.Types.Build: BaseConfigOpts :: !(Path Abs Dir) -> !(Path Abs Dir) -> !(Path Abs Dir) -> !(Path Abs Dir) -> !BuildOpts -> BaseConfigOpts
+ Stack.Types.Build: BaseConfigOpts :: !(Path Abs Dir) -> !(Path Abs Dir) -> !(Path Abs Dir) -> !(Path Abs Dir) -> !BuildOpts -> ![(Path Abs Dir)] -> BaseConfigOpts
- Stack.Types.Build: LocalPackage :: !Package -> !(Map PackageName VersionRange) -> !(Map PackageName VersionRange) -> !(Maybe (Set Text)) -> !(Maybe LocalPackageTB) -> !(Path Abs Dir) -> !(Path Abs File) -> !Bool -> !(Map FilePath FileCacheInfo) -> !(Set (Path Abs File)) -> !(Set NamedComponent) -> LocalPackage
+ Stack.Types.Build: LocalPackage :: !Package -> !(Map PackageName VersionRange) -> !(Map PackageName VersionRange) -> !(Maybe (Set Text)) -> !(Maybe LocalPackageTB) -> !(Path Abs Dir) -> !(Path Abs File) -> !(Maybe (Set FilePath)) -> !(Map FilePath FileCacheInfo) -> !(Set (Path Abs File)) -> !(Set NamedComponent) -> LocalPackage
- Stack.Types.Build: [lpDirtyFiles] :: LocalPackage -> !Bool
+ Stack.Types.Build: [lpDirtyFiles] :: LocalPackage -> !(Maybe (Set FilePath))
- Stack.Types.Build: configureOpts :: EnvConfig -> BaseConfigOpts -> Map PackageIdentifier GhcPkgId -> Bool -> InstallLocation -> Package -> ConfigureOpts
+ Stack.Types.Build: configureOpts :: EnvConfig -> BaseConfigOpts -> Map PackageIdentifier GhcPkgId -> Bool -> Bool -> InstallLocation -> Package -> ConfigureOpts
- Stack.Types.Config: BuildConfig :: !Config -> !Resolver -> !CompilerVersion -> ![PackageEntry] -> !(Map PackageName Version) -> !(Path Abs File) -> !(Map PackageName (Map FlagName Bool)) -> !Bool -> !GHCVariant -> BuildConfig
+ Stack.Types.Config: BuildConfig :: !Config -> !Resolver -> !CompilerVersion -> ![PackageEntry] -> !(Map PackageName Version) -> ![Path Abs Dir] -> !(Path Abs File) -> !(Map PackageName (Map FlagName Bool)) -> !Bool -> !GHCVariant -> BuildConfig
- Stack.Types.Config: Config :: !(Path Abs Dir) -> !DockerOpts -> !(EnvSettings -> IO EnvOverride) -> !(Path Abs Dir) -> !Int -> !Bool -> !Platform -> !(Maybe GHCVariant) -> !Text -> ![PackageIndex] -> !Bool -> !Bool -> !Bool -> !Bool -> !VersionCheck -> !(Path Abs Dir) -> !VersionRange -> !Int -> !(Set Text) -> !(Set Text) -> !ConfigMonoid -> !Bool -> !ImageOpts -> !(Map Text Text) -> !(Maybe SCM) -> !(Map (Maybe PackageName) [Text]) -> ![SetupInfoLocation] -> !PvpBounds -> Config
+ Stack.Types.Config: Config :: !(Path Abs Dir) -> !(Path Abs File) -> !DockerOpts -> !(EnvSettings -> IO EnvOverride) -> !(Path Abs Dir) -> !(Path Abs Dir) -> !Int -> !Bool -> !Platform -> !(Maybe GHCVariant) -> !Text -> ![PackageIndex] -> !Bool -> !Bool -> !Bool -> !Bool -> !VersionCheck -> !(Path Abs Dir) -> !VersionRange -> !Int -> !(Set Text) -> !(Set Text) -> !ConfigMonoid -> !Bool -> !ImageOpts -> !(Map Text Text) -> !(Maybe SCM) -> !(Map (Maybe PackageName) [Text]) -> ![SetupInfoLocation] -> !PvpBounds -> !Bool -> !(Map (Maybe PackageName) Bool) -> !Bool -> !ApplyGhcOptions -> Config
- Stack.Types.Config: ConfigMonoid :: !DockerOptsMonoid -> !(Maybe Int) -> !(Maybe Bool) -> !(Maybe Text) -> !(Maybe [PackageIndex]) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe VersionCheck) -> !VersionRange -> !(Maybe String) -> !(Maybe String) -> !(Maybe GHCVariant) -> !(Maybe Int) -> !(Set Text) -> !(Set Text) -> !(Maybe Bool) -> !(Maybe FilePath) -> !ImageOptsMonoid -> !(Map Text Text) -> !(Maybe SCM) -> !(Map (Maybe PackageName) [Text]) -> ![Path Abs Dir] -> ![SetupInfoLocation] -> !(Maybe PvpBounds) -> ConfigMonoid
+ Stack.Types.Config: ConfigMonoid :: !DockerOptsMonoid -> !(Maybe Int) -> !(Maybe Bool) -> !(Maybe Text) -> !(Maybe [PackageIndex]) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe VersionCheck) -> !VersionRange -> !(Maybe String) -> !(Maybe String) -> !(Maybe GHCVariant) -> !(Maybe Int) -> !(Set Text) -> !(Set Text) -> !(Maybe Bool) -> !(Maybe FilePath) -> !ImageOptsMonoid -> !(Map Text Text) -> !(Maybe SCM) -> !(Map (Maybe PackageName) [Text]) -> ![Path Abs Dir] -> ![SetupInfoLocation] -> !(Maybe PvpBounds) -> !(Maybe Bool) -> !(Map (Maybe PackageName) Bool) -> !(Maybe Bool) -> !(Maybe ApplyGhcOptions) -> ConfigMonoid
- Stack.Types.Config: GlobalOpts :: !Bool -> !LogLevel -> !ConfigMonoid -> !(Maybe AbstractResolver) -> !Bool -> !(Maybe FilePath) -> !Bool -> GlobalOpts
+ Stack.Types.Config: GlobalOpts :: !(Maybe String) -> !LogLevel -> !ConfigMonoid -> !(Maybe AbstractResolver) -> !Bool -> !(Maybe FilePath) -> GlobalOpts
- Stack.Types.Config: Project :: ![PackageEntry] -> !(Map PackageName Version) -> !(Map PackageName (Map FlagName Bool)) -> !Resolver -> Project
+ Stack.Types.Config: Project :: ![PackageEntry] -> !(Map PackageName Version) -> !(Map PackageName (Map FlagName Bool)) -> !Resolver -> ![FilePath] -> Project
- Stack.Types.Config: SetupInfo :: Maybe DownloadInfo -> Maybe DownloadInfo -> Map Text VersionedDownloadInfo -> Map Text (Map Version DownloadInfo) -> SetupInfo
+ Stack.Types.Config: SetupInfo :: Maybe DownloadInfo -> Maybe DownloadInfo -> Map Text VersionedDownloadInfo -> Map Text (Map Version DownloadInfo) -> Map Text (Map CompilerVersion DownloadInfo) -> Map Text (Map Version DownloadInfo) -> SetupInfo
- Stack.Types.Docker: DockerOpts :: !Bool -> !String -> !Bool -> !(Maybe String) -> !(Maybe String) -> !Bool -> !Bool -> !Bool -> !(Maybe String) -> ![String] -> ![Mount] -> ![String] -> !(Path Abs File) -> DockerOpts
+ Stack.Types.Docker: DockerOpts :: !Bool -> !String -> !Bool -> !(Maybe String) -> !(Maybe String) -> !Bool -> !Bool -> !Bool -> !(Maybe String) -> ![String] -> ![Mount] -> ![String] -> !(Path Abs File) -> !(Maybe DockerStackExe) -> !(Maybe Bool) -> DockerOpts
- Stack.Types.Docker: DockerOptsMonoid :: !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe DockerMonoidRepoOrImage) -> !(Maybe Bool) -> !(Maybe String) -> !(Maybe String) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe String) -> ![String] -> ![Mount] -> ![String] -> !(Maybe String) -> DockerOptsMonoid
+ Stack.Types.Docker: DockerOptsMonoid :: !Bool -> !(Maybe Bool) -> !(Maybe DockerMonoidRepoOrImage) -> !(Maybe Bool) -> !(Maybe String) -> !(Maybe String) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe Bool) -> !(Maybe String) -> ![String] -> ![Mount] -> ![String] -> !(Maybe String) -> !(Maybe String) -> !(Maybe Bool) -> DockerOptsMonoid
- Stack.Types.Package: GetPackageOpts :: (forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])) -> GetPackageOpts
+ Stack.Types.Package: GetPackageOpts :: (forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> InstalledMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])) -> GetPackageOpts
- Stack.Types.Package: LocalPackage :: !Package -> !(Map PackageName VersionRange) -> !(Map PackageName VersionRange) -> !(Maybe (Set Text)) -> !(Maybe LocalPackageTB) -> !(Path Abs Dir) -> !(Path Abs File) -> !Bool -> !(Map FilePath FileCacheInfo) -> !(Set (Path Abs File)) -> !(Set NamedComponent) -> LocalPackage
+ Stack.Types.Package: LocalPackage :: !Package -> !(Map PackageName VersionRange) -> !(Map PackageName VersionRange) -> !(Maybe (Set Text)) -> !(Maybe LocalPackageTB) -> !(Path Abs Dir) -> !(Path Abs File) -> !(Maybe (Set FilePath)) -> !(Map FilePath FileCacheInfo) -> !(Set (Path Abs File)) -> !(Set NamedComponent) -> LocalPackage
- Stack.Types.Package: [getPackageOpts] :: GetPackageOpts -> forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])
+ Stack.Types.Package: [getPackageOpts] :: GetPackageOpts -> forall env m. (MonadIO m, HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m) => SourceMap -> InstalledMap -> [PackageName] -> Path Abs File -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Map NamedComponent [String], [String])
- Stack.Types.Package: [lpDirtyFiles] :: LocalPackage -> !Bool
+ Stack.Types.Package: [lpDirtyFiles] :: LocalPackage -> !(Maybe (Set FilePath))
- System.Process.Read: EnvOverride :: Map Text Text -> [(String, String)] -> [FilePath] -> IORef (Map FilePath (Either ReadProcessException (Path Abs File))) -> String -> EnvOverride
+ System.Process.Read: EnvOverride :: Map Text Text -> [(String, String)] -> [FilePath] -> IORef (Map FilePath (Either ReadProcessException (Path Abs File))) -> String -> Platform -> EnvOverride

Files

+ CONTRIBUTING.md view
@@ -0,0 +1,61 @@+## Bug Reports++When reporting a bug, please write in the following format:++> [Any general summary/comments if desired]++> **Steps to reproduce:**++> 1. _Remove directory *blah*._+> 2. _Run command `stack blah`._+> 3. _Edit file blah._+> 3. _Run command `stack blah`._++> **Expected:**++> _What I expected to see and happen._++> **Actual:**++> _What actually happened._+>+> Here is the `stack ---version` output:+>+> ```+> $ stack --version+> Version 0.0.2, Git revision 6a86ee32e5b869a877151f74064572225e1a0398+> ```+> Here is the command I ran **with `--verbose`**:+>+> ```+> $ stack <your command here> <args> --verbose+> <output>+> ```++With `--verbose` mode we can see what the tool is doing and when. Without this output it is much more difficult to surmise what's going on with your issue. If the above output is larger than a page, paste it in a private [Gist](https://gist.github.com/) instead.++Include any `.yaml` configuration if relevant.++The more detailed your report, the faster it can be resolved and will ensure it is resolved in the right way. Once your bug has been resolved, the responsible will tag the issue as _Needs confirmation_ and assign the issue back to you. Once you have tested and confirmed that the issue is resolved, close the issue. If you are not a member of the project, you will be asked for confirmation and we will close it.+++## Documentation+If you would like to help with documentation, please note that for most cases the Wiki has been deprecated in favor of markdown files placed in a new `/doc` subdirectory of the repository itself. Please submit a [pull request](https://help.github.com/articles/using-pull-requests/) with your changes/additions.++If your changes move or rename files, or subsume Wiki content, please continue to leave a file/page in the old location temporarily, in addition to the new location. This will allow users time to update any shared links to the old location. Please also update any links in other files, or on the Wiki, to point to the new file location.+++## Code++If you would like to contribute code to fix a bug, add a new feature, or+otherwise improve `stack`, pull requests are most welcome. It's a good idea to+[submit an issue](https://github.com/commercialhaskell/stack/issues/new) to+discuss the change before plowing into writing code.++If you'd like to help out but aren't sure what to work on, look for issues with+the+[awaiting pr](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3A%22awaiting+pr%22)+label. Issues that are suitable for newcomers to the codebase have the+[newcomer](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3A%22awaiting+pr%22+label%3Anewcomer)+label. Best to post a comment to the issue before you start work, in case anyone+has already started.
ChangeLog.md view
@@ -1,3 +1,54 @@+## Unreleased changes+++## v0.1.6.0++Major changes:++* "stack setup" now supports building and booting GHCJS from source tarball.+* On Windows, build directories no longer display "pretty" information+  (like x86_64-windows/Cabal-1.22.4.0), but rather a hash of that+  content. The reason is to avoid the 260 character path limitation on+  Windows. See+  [#1027](https://github.com/commercialhaskell/stack/pull/1027)+* Rename config files and clarify their purposes [#969](https://github.com/commercialhaskell/stack/issues/969)+    * `~/.stack/stack.yaml` --> `~/.stack/config.yaml`+    * `~/.stack/global` --> `~/.stack/global-project`+    * `/etc/stack/config` --> `/etc/stack/config.yaml`+    * Old locations still supported, with deprecation warnings+* New command "stack eval CODE", which evaluates to "stack exec ghc -- -e CODE".++Other enhancements:++* No longer install `git` on Windows+  [#1046](https://github.com/commercialhaskell/stack/issues/1046). You+  can still get this behavior by running the following yourself:+  `stack exec -- pacman -Sy --noconfirm git`.+* Typing enter during --file-watch triggers a rebuild [#1023](https://github.com/commercialhaskell/stack/pull/1023)+* Use Haddock's `--hyperlinked-source` (crosslinked source), if available [#1070](https://github.com/commercialhaskell/stack/pull/1070)+* Use Stack-installed GHCs for `stack init --solver` [#1072](https://github.com/commercialhaskell/stack/issues/1072)+* New experimental `stack query` command [#1087](https://github.com/commercialhaskell/stack/issues/1087)+* By default, stack no longer rebuilds a package due to GHC options changes. This behavior can be tweaked with the `rebuild-ghc-options` setting. [#1089](https://github.com/commercialhaskell/stack/issues/1089)+* By default, ghc-options are applied to all local packages, not just targets. This behavior can be tweaked with the `apply-ghc-options` setting. [#1089](https://github.com/commercialhaskell/stack/issues/1089)+* Docker: download or override location of stack executable to re-run in container [#974](https://github.com/commercialhaskell/stack/issues/974)+* Docker: when Docker Engine is remote, don't run containerized processes as host's UID/GID [#194](https://github.com/commercialhaskell/stack/issues/194)+* Docker: `set-user` option to enable/disable running containerized processes as host's UID/GID [#194](https://github.com/commercialhaskell/stack/issues/194)+* Custom Setup.hs files are now precompiled instead of interpreted. This should be a major performance win for certain edge cases (biggest example: [building Cabal itself](https://github.com/commercialhaskell/stack/issues/1041)) while being either neutral or a minor slowdown for more common cases.+* `stack test --coverage` now also generates a unified coverage report for multiple test-suites / packages.  In the unified report, test-suites can contribute to the coverage of other packages.++Bug fixes:++* Ignore stack-built executables named `ghc`+  [#1052](https://github.com/commercialhaskell/stack/issues/1052)+* Fix quoting of output failed command line arguments+* Mark executable-only packages as installed when copied from cache [#1043](https://github.com/commercialhaskell/stack/pull/1043)+* Canonicalize temporary directory paths [#1047](https://github.com/commercialhaskell/stack/pull/1047)+* Put code page fix inside the build function itself [#1066](https://github.com/commercialhaskell/stack/issues/1066)+* Add `explicit-setup-deps` option [#1110](https://github.com/commercialhaskell/stack/issues/1110), and change the default to the old behavior of using any package in the global and snapshot database [#1025](https://github.com/commercialhaskell/stack/issues/1025)+* Precompiled cache checks full package IDs on Cabal < 1.22 [#1103](https://github.com/commercialhaskell/stack/issues/1103)+* Pass -package-id to ghci [#867](https://github.com/commercialhaskell/stack/issues/867)+* Ignore global packages when copying precompiled packages [#1146](https://github.com/commercialhaskell/stack/issues/1146)+ ## 0.1.5.0  Major changes:
README.md view
@@ -1,7 +1,7 @@ ## The Haskell Tool Stack  [![Build Status](https://travis-ci.org/commercialhaskell/stack.svg?branch=master)](https://travis-ci.org/commercialhaskell/stack)-[![Windows build status](https://ci.appveyor.com/api/projects/status/05y9unqcdav7p9xt?svg=true)](https://ci.appveyor.com/project/snoyberg/stack)+[![Windows build status](https://ci.appveyor.com/api/projects/status/github/commercialhaskell/stack)](https://ci.appveyor.com/project/snoyberg/stack) [![Release](https://img.shields.io/github/release/commercialhaskell/stack.svg)](https://github.com/commercialhaskell/stack/releases)  `stack` is a cross-platform program for developing Haskell@@ -21,47 +21,96 @@  Downloads are available by operating system: -* [Windows](doc/install_and_upgrade.md#windows)-* [OS X](doc/install_and_upgrade.md#os-x)-* [Ubuntu](doc/install_and_upgrade.md#ubuntu)-* [Debian](doc/install_and_upgrade.md#debian)-* [CentOS / Red Hat / Amazon Linux](doc/install_and_upgrade.md#centos--red-hat--amazon-linux)-* [Fedora](doc/install_and_upgrade.md#fedora)-* [Arch Linux](doc/install_and_upgrade.md#arch-linux)-* [Linux (general)](doc/install_and_upgrade.md#linux)+* [Windows](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#windows)+* [OS X](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#os-x)+* [Ubuntu](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#ubuntu)+* [Debian](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#debian)+* [CentOS / Red Hat / Amazon Linux](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#centos--red-hat--amazon-linux)+* [Fedora](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#fedora)+* [Arch Linux](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#arch-linux)+* [NixOS](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#nixos)+* [Linux (general)](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#linux) -[Upgrade instructions](doc/install_and_upgrade.md#upgrade)+[Upgrade instructions](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#upgrade)  Note: if you are using cabal-install to install stack, you may need to pass a constraint to work around a [Cabal issue](https://github.com/haskell/cabal/issues/2759): `cabal install --constraint 'mono-traversable >= 0.9' stack`. -#### How to use+#### Quick Start Guide -Go into a Haskell project directory and run `stack build`. If everything is-already configured, this will:+First you need to [install it (see previous section)](#how-to-install). -* Download the package index.-* Download and install all necessary dependencies for the project.-* Build and install the project.+##### Start your new project: -You may be prompted to run some of the following along the way:+~~~ {.bash}+stack new my-project+cd my-project+stack setup+stack build+stack exec my-project-exe+~~~ -* `stack new` to create a brand new project.-* `stack init` to create a stack configuration file for an existing project.-  stack will figure out what Stackage release (LTS or nightly) is appropriate-  for the dependencies.-* `stack setup` to download and install the correct GHC version in an-  isolated location (default `~/.stack`) that won't interfere with any-  system-level installations. (For information on installation paths,-  please use the `stack path` command.)+- The `stack new` command will create a new directory containing all+the needed files to start a project correctly.+- The `stack setup` will download the compiler if necessary in an isolated+  location (default `~/.stack`) that won't interfere with any system-level+  installations. (For information on installation paths, please use the `stack+  path` command.).+- The `stack build` command will build the minimal project.+- `stack exec my-project-exe` will execute the command.+- If you just want to install an executable using stack, then all you have to do+is`stack install <package-name>`. -If you just want to install an executable using stack, then all you have-to do is `stack install <package-name>`.+If you want to launch a REPL: +~~~ {.bash}+stack ghci+~~~++ Run `stack` for a complete list of commands. +##### Workflow++The `stack new` command should have created the following files:++~~~+.+├── LICENSE+├── Setup.hs+├── app+│   └── Main.hs+├── my-project.cabal+├── src+│   └── Lib.hs+├── stack.yaml+└── test+    └── Spec.hs++    3 directories, 7 files+~~~++So to manage your library:++1. Edit files in the `src/` directory.++The `app` directory should preferably contains only files related to+executables.++2. If you need to include another library (for example the package [`text`](https://hackage.haskell.org/package/text):++   - Add the package `text` to the file `my-project.cabal`+     in the section `build-depends: ...`.+   - run `stack build` another time++3. If you get an error that tells you your package isn't in the LTS.+   Just try to add a new version in the `stack.yaml` file in the `extra-deps` section.++It was a really fast introduction on how to start to code in Haskell using `stack`.+If you want to go further, we highly recommend you to read the [`stack` guide](https://github.com/commercialhaskell/stack/blob/master/doc/GUIDE.md).+ #### How to contribute  This assumes that you have already installed a version of stack, and have `git`@@ -75,7 +124,7 @@ 4. Once `stack` finishes building, check the stack version with    `stack --version`. Make sure the version is the latest. 5. Look for issues tagged with-   [`newcomer` and `awaiting-pr` labels](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3Anewcomer+label%3Aawaiting-pr)+   [`newcomer` and `awaiting-pr` labels](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3Anewcomer+label%3A%22awaiting+pr%22)  Build from source as a one-liner: @@ -89,13 +138,13 @@ #### Complete guide to stack  This repository also contains a complete [user guide to using stack-](doc/GUIDE.md), covering all of the most common use cases.+](https://github.com/commercialhaskell/stack/blob/release/doc/GUIDE.md), covering all of the most common use cases.   #### Questions, Feedback, Discussion  * For frequently asked questions about detailed or specific use-cases, please-  see [the FAQ](doc/faq.md).+  see [the FAQ](https://github.com/commercialhaskell/stack/blob/release/doc/faq.md). * For general questions, comments, feedback and support please write   to [the stack mailing list](https://groups.google.com/d/forum/haskell-stack). * For bugs, issues, or requests please@@ -129,27 +178,27 @@ ## Documentation Table Of Contents  * Project Documentation-    * [Maintainer Guide](doc/MAINTAINER_GUIDE.md): includes releasing information-    * [Signing Key](doc/SIGNING_KEY.md): downloadable stack binaries are signed+    * [Maintainer Guide](https://github.com/commercialhaskell/stack/blob/release/doc/MAINTAINER_GUIDE.md): includes releasing information+    * [Signing Key](https://github.com/commercialhaskell/stack/blob/release/doc/SIGNING_KEY.md): downloadable stack binaries are signed       with this key * Tool Documentation-    * [Build Command](doc/build_command.md): reference for the syntax of the+    * [Build Command](https://github.com/commercialhaskell/stack/blob/release/doc/build_command.md): reference for the syntax of the       build command and the command line targets-    * [Dependency Visualization](doc/dependency_visualization.md): uses Graphviz-    * [Docker Integration](doc/docker_integration.md)-    * [FAQ](doc/faq.md): frequently asked questions about detailed or specific+    * [Dependency Visualization](https://github.com/commercialhaskell/stack/blob/release/doc/dependency_visualization.md): uses Graphviz+    * [Docker Integration](https://github.com/commercialhaskell/stack/blob/release/doc/docker_integration.md)+    * [FAQ](https://github.com/commercialhaskell/stack/blob/release/doc/faq.md): frequently asked questions about detailed or specific       use-cases-    * [Install/Upgrade](doc/install_and_upgrade.md): a list of downloads+    * [Install/Upgrade](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md): a list of downloads       available by operating system, installation instructions, and upgrade       instructions-    * [Nonstandard Project Initialization](doc/nonstandard_project_init.md)-    * [Shell Autocompletion](doc/shell_autocompletion.md)-    * [User Guide](doc/GUIDE.md): in-depth tutorial covering the most common use+    * [Nonstandard Project Initialization](https://github.com/commercialhaskell/stack/blob/release/doc/nonstandard_project_init.md)+    * [Shell Autocompletion](https://github.com/commercialhaskell/stack/blob/release/doc/shell_autocompletion.md)+    * [User Guide](https://github.com/commercialhaskell/stack/blob/release/doc/GUIDE.md): in-depth tutorial covering the most common use       cases and all major stack features (requires no prior Haskell tooling       experience)-    * [YAML Configuration](doc/yaml_configuration.md): reference for writing+    * [YAML Configuration](https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md): reference for writing       `stack.yaml` files * Advanced Documentation-    * [Architecture](doc/architecture.md): reference for people curious about+    * [Architecture](https://github.com/commercialhaskell/stack/blob/release/doc/architecture.md): reference for people curious about       stack internals, wanting to get involved deeply in the codebase, or       wanting to use stack in unusual ways
+ doc/GUIDE.md view
@@ -0,0 +1,1736 @@+stack is a modern, cross-platform build tool for Haskell code.++This guide takes a new stack user through the typical workflows. This guide+will not teach Haskell or involve much code, and it requires no prior experience+with the Haskell packaging system or other build tools.++## Stack's functions++stack handles the management of your toolchain (including GHC — the Glasgow+Haskell Compiler — and, for Windows users, MSYS), building and registering+libraries, building build tool dependencies, and more. While it can use existing+tools on your system, stack has the capacity to be your one-stop shop for all+Haskell tooling you need. This guide will follow that stack-centric approach.++### What makes stack special?++The primary stack design point is __reproducible builds__. If you run `stack+build` today, you should get the same result running `stack build` tomorrow.+There are some cases that can break that rule (changes in your operating system+configuration, for example), but, overall, stack follows this design philosophy+closely. To make this a simple process, stack uses curated package sets+called __snapshots__.++stack has also been designed from the ground up to be user friendly, with an+intuitive, discoverable command line interface. For many users, simply+downloading stack and reading `stack --help` will be enough to get up and+running. This guide provides a more gradual tour for users who prefer that+learning style.++To build your project, stack uses a `stack.yaml` file in the root directory of+your project as a sort of blueprint. That file contains a reference, called a+__resolver__, to the snapshot which your package will be built against.++Finally, stack is __isolated__: it will not make changes outside of specific+stack directories. stack-built files generally go in either the stack root+directory (default `~/.stack`) or `./.stack-work` directories local to each+project. The stack root directory holds packages belonging to snapshots and any+stack-installed versions of GHC. Stack will not tamper with any system version+of GHC or interfere with packages installed by `cabal` or any other build tools.++_NOTE_ In this guide, we'll use commands as run on a GNU/Linux system+(specifically Ubuntu 14.04, 64-bit) and share output from that. Output on other+systems — or with different versions of stack — will be slightly different, but+all commands work cross-platform, unless explicitly stated otherwise.++## Downloading and Installation++The [documentation dedicated to downloading+stack](install_and_upgrade.md) has the most+up-to-date information for a variety of operating systems, including multiple+GNU/Linux flavors. Instead of repeating that content here, please go check out+that page and come back here when you can successfully run `stack --version`.+The rest of this session will demonstrate the installation procedure on a+vanilla Ubuntu 14.04 machine.++```+# Starting with a *really* bare machine+michael@d30748af6d3d:~$ sudo apt-get install wget+# Demonstrate that stack really isn't available+michael@d30748af6d3d:~$ stack+-bash: stack: command not found+# Get the signing key for the package repo+michael@d30748af6d3d:~$ wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/ubuntu/fpco.key | sudo apt-key add -+OK+michael@d30748af6d3d:~$ echo 'deb http://download.fpcomplete.com/ubuntu/trusty stable main'|sudo tee /etc/apt/sources.list.d/fpco.list+deb http://download.fpcomplete.com/ubuntu/trusty stable main+michael@d30748af6d3d:~$ sudo apt-get update && sudo apt-get install stack -y+# downloading...+michael@d30748af6d3d:~$ stack --version+Version 0.1.3.1, Git revision 908b04205e6f436d4a5f420b1c6c646ed2b804d7+```++With stack now up and running, you're good to go. Though not required, we+recommend setting your PATH environment variable to include `$HOME/.local/bin`:++```+michael@d30748af6d3d:~$ echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc+```++## Hello World Example++With stack installed, let's create a new project from a template and walk+through the most common stack commands.++### stack new++We'll start off with the `stack new` command to create a new+*project*. We'll call our project `helloworld`, and we'll use the+`new-template` project template:++```+michael@d30748af6d3d:~$ stack new helloworld new-template+```++For this first stack command, there's quite a bit of initial setup it needs to+do (such as downloading the list of packages available upstream), so you'll see+a lot of output. Though your exact results may vary, below is an example of the+sort of output you will see. Over the course of this guide a lot of the content+will begin to make more sense:++```+Downloading template "new-template" to create project "helloworld" in helloworld/ ...+Using the following authorship configuration:+author-email: example@example.com+author-name: Example Author Name+Copy these to /home/michael/.stack/config.yaml and edit to use different values.+Writing default config file to: /home/michael/helloworld/stack.yaml+Basing on cabal files:+- /home/michael/helloworld/helloworld.cabal++Downloaded lts-3.2 build plan.+Caching build plan+Fetched package index.+Populated index cache.+Checking against build plan lts-3.2+Selected resolver: lts-3.2+Wrote project config to: /home/michael/helloworld/stack.yaml+```+We now have a project in the `helloworld` directory!++### stack setup++Instead of assuming you want stack to download and install+GHC for you, it asks you to do this as a separate command:+`setup`. If we don't run `stack setup` now, we'll later see a+message that we are missing the right GHC version.++Let's run stack setup:++```+michael@d30748af6d3d:~/helloworld$ stack setup+Downloaded ghc-7.10.2.+Installed GHC.+stack will use a locally installed GHC+For more information on paths, see 'stack path' and 'stack exec env'+To use this GHC and packages outside of a project, consider using:+stack ghc, stack ghci, stack runghc, or stack exec+```++It doesn't come through in the output here, but you'll get intermediate+download percentage statistics while the download is occurring. This command+may take some time, depending on download speeds.++__NOTE__: GHC will be installed to your global stack root directory, so+calling `ghc` on the command line won't work. See the `stack exec`,+`stack ghc`, and `stack runghc` commands below for more information.++### stack build++Next, we'll run the most important stack command: `stack build`.++__NOTE__: If you forgot to run `stack setup` in the previous step you'll get an+error:++```+michael@d30748af6d3d:~$ cd helloworld/+michael@d30748af6d3d:~/helloworld$ stack build+No GHC found, expected version 7.10.2 (x86_64) (based on resolver setting in /home/michael/helloworld/stack.yaml).+Try running stack setup+```++stack needs GHC in order to build your project, and `stack setup` must be run to+check whether GHC is available (and install it if not).++Having run `stack setup` successfully, `stack build` should build our project:++```+michael@d30748af6d3d:~/helloworld$ stack build+helloworld-0.1.0.0: configure+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build+Preprocessing library helloworld-0.1.0.0...+[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )+In-place registering helloworld-0.1.0.0...+Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...+[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe-tmp/Main.o )+Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...+helloworld-0.1.0.0: install+Installing library in+/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-6urpPe0MO7OHasGCFSyIAT+Installing executable(s) in+/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/bin+Registering helloworld-0.1.0.0...+```++### stack exec++Looking closely at the output of the previous command, you can see that it built+both a library called "helloworld" and an executable called "helloworld-exe".+We'll explain more in the next section, but, for now, just notice that the+executables are installed in our project's `./stack-work` directory.++Now, Let's use `stack exec` to run our executable (which just outputs the string+"someFunc"):++```+michael@d30748af6d3d:~/helloworld$ stack exec helloworld-exe+someFunc+```++`stack exec` works by providing the same reproducible environment that was used+to build your project to the command that you are running. Thus, it knew where+to find `helloworld-exe` even though it is hidden in the `./stack-work`+directory.++### stack test++Finally, like all good software, helloworld actually has a test suite.+Let's run it with `stack test`:++```+michael@d30748af6d3d:~/helloworld$ stack test+NOTE: the test command is functionally equivalent to 'build --test'+helloworld-0.1.0.0: configure (test)+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build (test)+Preprocessing library helloworld-0.1.0.0...+In-place registering helloworld-0.1.0.0...+Preprocessing test suite 'helloworld-test' for helloworld-0.1.0.0...+[1 of 1] Compiling Main             ( test/Spec.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test-tmp/Main.o )+Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test ...+helloworld-0.1.0.0: test (suite: helloworld-test)+Test suite not yet implemented+```++Reading the output, you'll see that stack first builds the test suite and then+automatically runs it for us. For both the `build` and `test` command, already+built components are not built again. You can see this by running `stack build`+and `stack test` a second time:++```+michael@d30748af6d3d:~/helloworld$ stack build+michael@d30748af6d3d:~/helloworld$ stack test+NOTE: the test command is functionally equivalent to 'build --test'+helloworld-0.1.0.0: test (suite: helloworld-test)+Test suite not yet implemented+```++## Inner Workings of stack++In this subsection, we'll dissect the helloworld example in more detail.++### Files in helloworld++Before studying stack more, let's understand our project a bit better.++```+michael@d30748af6d3d:~/helloworld$ find * -type f+LICENSE+Setup.hs+app/Main.hs+helloworld.cabal+src/Lib.hs+stack.yaml+test/Spec.hs+```++The `app/Main.hs`, `src/Lib.hs`, and `test/Spec.hs` files are all Haskell source+files that compose the actual functionality of our project (we won't dwell on+them here). The LICENSE file has no impact on the build, but is there for+informational/legal purposes only. The files of interest here are Setup.hs,+helloworld.cabal, and stack.yaml.++The Setup.hs file is a component of the Cabal build system which stack uses.+It's technically not needed by stack, but it is still considered good practice+in the Haskell world to include it. The file we're using is straight+boilerplate:++```haskell+import Distribution.Simple+main = defaultMain+```++Next, let's look at our stack.yaml file, which gives our project-level settings:++```yaml+flags: {}+packages:+- '.'+extra-deps: []+resolver: lts-3.2+```++If you're familiar with YAML, you may recognize that the `flags` and+`extra-deps` keys have empty values. We'll see more interesting usages for these+fields later.  Let's focus on the other two fields. `packages` tells stack which+local packages to build. In our simple example, we have only a single package in+our project, located in the same directory, so `'.'` suffices. However, stack+has powerful support for multi-package projects, which we'll elaborate on as+this guide progresses.++The final field is resolver. This tells stack *how* to build your package:+which GHC version to use, versions of package dependencies, and so on. Our+value here says to use [LTS Haskell version+3.2](https://www.stackage.org/lts-3.2), which implies GHC 7.10.2 (which is why+`stack setup` installs that version of GHC). There are a number of values you+can use for resolver, which we'll cover later.++The final file of import is helloworld.cabal. stack is built on top of the+Cabal build system. In Cabal, we have individual *packages*, each of which+contains a single .cabal file. The .cabal file can define 1 or more+*components*: a library, executables, test suites, and benchmarks. It also+specifies additional information such as library dependencies, default language+pragmas, and so on.++In this guide, we'll discuss the bare minimum necessary to understand how to+modify a .cabal file. Haskell.org has the definitive [reference for the .cabal+file format](https://www.haskell.org/cabal/users-guide/developing-packages.html).++### The setup command++As we saw above, the `setup` command installed GHC for us. Just for kicks,+let's run `setup` a second time:++```+michael@d30748af6d3d:~/helloworld$ stack setup+stack will use a locally installed GHC+For more information on paths, see 'stack path' and 'stack exec env'+To use this GHC and packages outside of a project, consider using:+stack ghc, stack ghci, stack runghc, or stack exec+```++Thankfully, the command is smart enough to know not to perform an installation+twice. `setup` will either use the first GHC it finds on your PATH, or a locally+installed version. As the command output above indicates, you can use `stack+path` for quite a bit of path information (which we'll play with more later).+For now, we'll just look at where GHC is installed:++```+michael@d30748af6d3d:~/helloworld$ stack exec which ghc+/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin/ghc+```++As you can see from that path (and as emphasized earlier), the installation is+placed to not interfere with any other GHC installation, whether system-wide or+even different GHC versions installed by stack.++### The build command++The build command is the heart and soul of stack. It is the engine that powers+building your code, testing it, getting dependencies, and more. Quite a bit of+the remainder of this guide will cover more advanced `build` functions and+features, such as building test and Haddocks at the same time, or constantly+rebuilding blocking on file changes.++*On a philosophical note:* Running the build command twice with the same+options and arguments should generally be a no-op (besides things like+rerunning test suites), and should, in general, produce a reproducible result+between different runs.++## Adding dependencies++Let's say we decide to modify our helloworld source a bit to use a new library,+perhaps the ubiquitous text package. For example:++```haskell+{-# LANGUAGE OverloadedStrings #-}+module Lib+    ( someFunc+    ) where++import qualified Data.Text.IO as T++someFunc :: IO ()+someFunc = T.putStrLn "someFunc"+```++When we try to build this, things don't go as expected:++```haskell+michael@d30748af6d3d:~/helloworld$ stack build+helloworld-0.1.0.0-c91e853ce4bfbf6d394f54b135573db8: unregistering (local file changes)+helloworld-0.1.0.0: configure+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build+Preprocessing library helloworld-0.1.0.0...++/home/michael/helloworld/src/Lib.hs:6:18:+    Could not find module `Data.Text.IO'+    Use -v to see a list of the files searched for.++--  While building package helloworld-0.1.0.0 using:+      /home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin/runhaskell -package=Cabal-1.22.4.0 -clear-package-db -global-package-db -package-db=/home/michael/.stack/snapshots/x86_64-linux/lts-3.2/7.10.2/pkgdb/ /tmp/stack5846/Setup.hs --builddir=.stack-work/dist/x86_64-linux/Cabal-1.22.4.0/ build exe:helloworld-exe --ghc-options -hpcdir .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/hpc/.hpc/ -ddump-hi -ddump-to-file+    Process exited with code: ExitFailure 1+```++Notice that it says "Could not find module." This means that the package+containing the module in question is not available. To tell stack to use text,+you need to add it to your .cabal file — specifically in your build-depends+section, like this:++```cabal+library+  hs-source-dirs:      src+  exposed-modules:     Lib+  build-depends:       base >= 4.7 && < 5+                       -- This next line is the new one+                     , text+  default-language:    Haskell2010+```++Now if we rerun `stack build`, we should get a successful result:++```+michael@d30748af6d3d:~/helloworld$ stack build+text-1.2.1.3: download+text-1.2.1.3: configure+text-1.2.1.3: build+text-1.2.1.3: install+helloworld-0.1.0.0: configure+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build+Preprocessing library helloworld-0.1.0.0...+[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )+In-place registering helloworld-0.1.0.0...+Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...+[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe-tmp/Main.o ) [Lib changed]+Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...+helloworld-0.1.0.0: install+Installing library in+/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-HI1deOtDlWiAIDtsSJiOtw+Installing executable(s) in+/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/bin+Registering helloworld-0.1.0.0...+Completed all 2 actions.+```++This output means that the text package was downloaded, configured, built, and+locally installed. Once that was done, we moved on to building our local package+(helloworld). At no point did we need to ask stack to build dependencies — it+does so automatically.++### extra-deps++Let's try a more off-the-beaten-track package: the joke+[acme-missiles](http://www.stackage.org/package/acme-missiles) package. Our+source code is simple:++```haskell+module Lib+    ( someFunc+    ) where++import Acme.Missiles++someFunc :: IO ()+someFunc = launchMissiles+```++In this case, we can add acme-missiles to the .cabal file, but we get a new type+of error message from `stack build`:++```+michael@d30748af6d3d:~/helloworld$ stack build+While constructing the BuildPlan the following exceptions were encountered:++--  While attempting to add dependency,+    Could not find package acme-missiles in known packages++--  Failure when adding dependencies:+      acme-missiles: needed (-any), latest is 0.3, but not present in build plan+    needed for package: helloworld-0.1.0.0++Recommended action: try adding the following to your extra-deps in /home/michael/helloworld/stack.yaml+- acme-missiles-0.3++You may also want to try the 'stack solver' command+```++It says acme-missiles is "not present in build plan." This brings us to the next+major topic in using stack.++## Curated package sets++Remember above when `stack new` selected the lts-3.2 resolver for us? That+defined our build plan and available packages. When we tried using the+text package, it just worked, because it was part of the lts-3.2 *package set*.+But acme-missiles is not part of that package set, so building failed.++To add this new dependency, we'll use the `extra-deps` field in stack.yaml to+define extra dependencies not present in the resolver. With that change, our+stack.yaml looks like:++```yaml+flags: {}+packages:+- '.'+extra-deps:+- acme-missiles-0.3 # not in lts-3.2+resolver: lts-3.2+```++Now `stack build` will succeed.++With that out of the way, let's dig a little bit more into these package sets,+also known as *snapshots*. We mentioned lts-3.2, and you can get quite a bit of+information about it at+[https://www.stackage.org/lts-3.2](https://www.stackage.org/lts-3.2), including:++* The appropriate resolver value (`resolver: lts-3.2`, as we used above)+* The GHC version used+* A full list of all packages available in this snapshot+* The ability to perform a Hoogle search on the packages in this snapshot+* A [list of all modules](https://www.stackage.org/lts-3.2/docs) in a snapshot,+  which an be useful when trying to determine which package to add to your+  .cabal file++You can also see a [list of all available+snapshots](https://www.stackage.org/snapshots). You'll notice two flavors: LTS+(for "Long Term Support") and Nightly. You can read more about them on the+[LTS Haskell Github page](https://github.com/fpco/lts-haskell#readme). If you're+not sure which to use, start with LTS Haskell (which stack will lean towards by+default as well).++## Resolvers and changing your compiler version++Let's explore package sets a bit further. Instead of lts-3.2, let's change our+stack.yaml file to use+[nightly-2015-08-26](https://www.stackage.org/nightly-2015-08-26). Rerunning+`stack build` will produce:++```+michael@d30748af6d3d:~/helloworld$ stack build+Downloaded nightly-2015-08-26 build plan.+Caching build plan+stm-2.4.4: configure+stm-2.4.4: build+stm-2.4.4: install+acme-missiles-0.3: configure+acme-missiles-0.3: build+acme-missiles-0.3: install+helloworld-0.1.0.0: configure+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build+Preprocessing library helloworld-0.1.0.0...+In-place registering helloworld-0.1.0.0...+Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...+Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...+helloworld-0.1.0.0: install+Installing library in+/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-6cKaFKQBPsi7wB4XdqRv8w+Installing executable(s) in+/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/bin+Registering helloworld-0.1.0.0...+Completed all 3 actions.+```++We can also change resolvers on the command line, which can be useful in a+Continuous Integration (CI) setting, like on Travis. For example:++```+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-3.1 build+Downloaded lts-3.1 build plan.+Caching build plan+stm-2.4.4: configure+# Rest is the same, no point copying it+```++When passed on the command line, you also get some additional "short-cut"+versions of resolvers: `--resolver nightly` will use the newest Nightly resolver+available, `--resolver lts` will use the newest LTS, and `--resolver lts-2` will+use the newest LTS in the 2.X series. The reason these are only available on the+command line and not in your stack.yaml file is that using them:++1. Will slow down your build (since stack then needs to download information on+   the latest available LTS each time it builds)+2. Produces unreliable results (since a build run today may proceed differently+   tomorrow because of changes outside of your control)++### Changing GHC versions++Finally, let's try using an older LTS snapshot. We'll use the newest 2.X+snapshot:++```+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-2 build+Selected resolver: lts-2.22+Downloaded lts-2.22 build plan.+Caching build plan+No GHC found, expected version 7.8.4 (x86_64) (based on resolver setting in /home/michael/helloworld/stack.yaml). Try running stack setup+```++This fails, because GHC 7.8.4 (which lts-2.22 uses) is not available on our+system. So, we see that different LTS versions (2 vs 3 in this case) use+different GHC versions. Now, how do we get the right GHC version after changing+the LTS version?  One answer is to use `stack setup` like we did above, this+time with the `--resolver lts-2` option. However, there's another method worth+mentioning: the `--install-ghc` flag.++```+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-2 --install-ghc build+Selected resolver: lts-2.22+Downloaded ghc-7.8.4.+Installed GHC.+stm-2.4.4: configure+# Mostly same as before, nothing interesting to see+```++What's nice about `--install-ghc` is:++1. You don't need to have an extra step in your build script+2. It only requires downloading the information on latest snapshots once++As mentioned above, the default behavior of stack is to *not* install new+versions of GHC automatically. We want to avoid surprising users with large+downloads/installs. The `--install-ghc` flag simply changes that default+behavior.++### Other resolver values++We've mentioned `nightly-YYYY-MM-DD` and `lts-X.Y` values for the resolver.+There are actually other options available, and the list will grow over time.+At the time of writing:++* `ghc-X.Y.Z`, for requiring a specific GHC version but no additional packages+* Experimental GHCJS support+* Experimental custom snapshot support++The most up-to-date information can always be found in the+[stack.yaml documentation](yaml_configuration.md#resolver).++## Existing projects++Alright, enough playing around with simple projects. Let's take an open source+package and try to build it. We'll be ambitious and use+[yackage](https://www.stackage.org/package/yackage), a local package server+using [Yesod](http://www.yesodweb.com/). To get the code, we'll use the `stack+unpack` command:++```+michael@d30748af6d3d:~$ stack unpack yackage-0.8.0+yackage-0.8.0: download+Unpacked yackage-0.8.0 to /home/michael/yackage-0.8.0/+michael@d30748af6d3d:~$ cd yackage-0.8.0/+```++This new directory does not have a stack.yaml file, so we need to make one+first. We could do it by hand, but let's be lazy instead with the `stack init`+command:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack init+Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml+Basing on cabal files:+- /home/michael/yackage-0.8.0/yackage.cabal++Checking against build plan lts-3.2+Selected resolver: lts-3.2+Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml+michael@d30748af6d3d:~/yackage-0.8.0$ cat stack.yaml+flags:+  yackage:+    upload: true+packages:+- '.'+extra-deps: []+resolver: lts-3.2+```++stack init does quite a few things for you behind the scenes:++* Creates a list of snapshots that would be good candidates.+    * The basic algorithm here is to prefer options in this order:+        * Snapshots for which you've already built some packages (to+          increase sharing of binary package databases, as we'll discuss later)+        * Recent snapshots+        * LTS+    * These preferences can be tweaked with command line flags (see `stack init+      --help`).+* Finds all of the .cabal files in your current directory and subdirectories+  (unless you use `--ignore-subdirs`) and determines the packages and versions+  they require+* Finds a combination of snapshot and package flags that allows everything to+  compile++Assuming it finds a match, it will write your stack.yaml file, and everything+will work. Given that LTS Haskell and Stackage Nightly have ~1400 of the most+common Haskell packages, this will often be enough. However, let's simulate a+failure by adding acme-missiles to our build-depends and re-initing:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack init --force+Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml+Basing on cabal files:+- /home/michael/yackage-0.8.0/yackage.cabal++Checking against build plan lts-3.2++* Build plan did not match your requirements:+    acme-missiles not found+    - yackage requires -any++Checking against build plan lts-3.1++* Build plan did not match your requirements:+    acme-missiles not found+    - yackage requires -any+++Checking against build plan nightly-2015-08-26++* Build plan did not match your requirements:+    acme-missiles not found+    - yackage requires -any+++Checking against build plan lts-2.22++* Build plan did not match your requirements:+    acme-missiles not found+    - yackage requires -any++    warp version 3.0.13.1 found+    - yackage requires >=3.1+++There was no snapshot found that matched the package bounds in your .cabal files.+Please choose one of the following commands to get started.++    stack init --resolver lts-3.2+    stack init --resolver lts-3.1+    stack init --resolver nightly-2015-08-26+    stack init --resolver lts-2.22++You'll then need to add some extra-deps. See the+[stack.yaml documentation](yaml_configuration.md#extra-deps).++You can also try falling back to a dependency solver with:++    stack init --solver+```++stack has tested four different snapshots, and in every case discovered that+acme-missiles is not available. Also, when testing lts-2.22, it found that the+warp version provided was too old for yackage. So, what do we do?++The recommended approach is: pick a resolver, and fix the problem. Again,+following the advice mentioned above, default to LTS if you don't have a+preference. In this case, the newest LTS listed is lts-3.2. Let's pick that.+stack has told us the correct command to do this. We'll just remove our old+stack.yaml first and then run it:++```+michael@d30748af6d3d:~/yackage-0.8.0$ rm stack.yaml+michael@d30748af6d3d:~/yackage-0.8.0$ stack init --resolver lts-3.2+Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml+Basing on cabal files:+- /home/michael/yackage-0.8.0/yackage.cabal++Checking against build plan lts-3.2++* Build plan did not match your requirements:+    acme-missiles not found+    - yackage requires -any+++Selected resolver: lts-3.2+Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml+```++As you may guess, `stack build` will now fail due to the missing acme-missiles.+Toward the end of the error message, it says the familiar:++```+Recommended action: try adding the following to your extra-deps in /home/michael/yackage-0.8.0/stack.yaml+- acme-missiles-0.3+```++If you're following along at home, try making the necessary stack.yaml+modification to get things building.++### Alternative solution: dependency solving++There's another solution to consider for missing dependencies. At the end+of the previous error message, it said:++```+You may also want to try the 'stack solver' command+```++This approach uses a full-blown dependency solver to look at all upstream+package versions available and compare them to your snapshot selection and+version ranges in your .cabal file. In order to use this feature, you'll need+the cabal executable available. Let's build that with:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack build cabal-install+random-1.1: download+mtl-2.2.1: download+network-2.6.2.1: download+old-locale-1.0.0.7: download+random-1.1: configure+random-1.1: build+# ...+cabal-install-1.22.6.0: download+cabal-install-1.22.6.0: configure+cabal-install-1.22.6.0: build+cabal-install-1.22.6.0: install+Completed all 10 actions.+```++Now we can use `stack solver`:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack solver+This command is not guaranteed to give you a perfect build plan+It's possible that even with the changes generated below, you will still need to do some manual tweaking+Asking cabal to calculate a build plan, please wait+extra-deps:+- acme-missiles-0.3+```++And if we're exceptionally lazy, we can ask stack to modify our stack.yaml file+for us:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack solver --modify-stack-yaml+This command is not guaranteed to give you a perfect build plan+It's possible that even with the changes generated below, you will still need to do some manual tweaking+Asking cabal to calculate a build plan, please wait+extra-deps:+- acme-missiles-0.3+Updated /home/michael/yackage-0.8.0/stack.yaml+```++With that change, `stack build` will now run.++NOTE: You should probably back up your stack.yaml before doing this, such as+committing to Git/Mercurial/Darcs.++There's one final approach to mention: skipping the snapshot entirely and just+using dependency solving. You can do this with the `--solver` flag to `init`.+This is not a commonly used workflow with stack, as you end up with a large+number of extra-deps and no guarantee that the packages will compile together.+For those interested, however, the option is available. You need to make sure+you have both the ghc and cabal commands on your PATH. An easy way to do this+is to use the `stack exec` command:++```+michael@d30748af6d3d:~/yackage-0.8.0$ stack exec -- stack init --solver --force+Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml+Basing on cabal files:+- /home/michael/yackage-0.8.0/yackage.cabal++Asking cabal to calculate a build plan, please wait+Selected resolver: ghc-7.10+Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml+```++## Different databases++Time to take a short break from hands-on examples and discuss a little+architecture. stack has the concept of multiple *databases*. A database+consists of a GHC package database (which contains the compiled version of a+library), executables, and a few other things as well. To give you an idea:++```+michael@d30748af6d3d:~/helloworld$ ls .stack-work/install/x86_64-linux/lts-3.2/7.10.2/+bin  doc  flag-cache  lib  pkgdb+```++Databases in stack are *layered*. For example, the database listing we just gave+is called a *local* database. That is layered on top of a *snapshot* database,+which contains the libraries and executables specified in the snapshot itself.+Finally, GHC itself ships with a number of libraries and executables, which+forms the *global* database. To get a quick idea of this, we can look at the+output of the `ghc-pkg list` command in our helloworld project:++```+/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/lib/ghc-7.10.2/package.conf.d+   Cabal-1.22.4.0+   array-0.5.1.0+   base-4.8.1.0+   bin-package-db-0.0.0.0+   binary-0.7.5.0+   bytestring-0.10.6.0+   containers-0.5.6.2+   deepseq-1.4.1.1+   directory-1.2.2.0+   filepath-1.4.0.0+   ghc-7.10.2+   ghc-prim-0.4.0.0+   haskeline-0.7.2.1+   hoopl-3.10.0.2+   hpc-0.6.0.2+   integer-gmp-1.0.0.0+   pretty-1.1.2.0+   process-1.2.3.0+   rts-1.0+   template-haskell-2.10.0.0+   terminfo-0.4.0.1+   time-1.5.0.1+   transformers-0.4.2.0+   unix-2.7.1.0+   xhtml-3000.2.1+/home/michael/.stack/snapshots/x86_64-linux/nightly-2015-08-26/7.10.2/pkgdb+   stm-2.4.4+/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/pkgdb+   acme-missiles-0.3+   helloworld-0.1.0.0+```++Notice that acme-missiles ends up in the *local* database. Anything which is+not installed from a snapshot ends up in the local database. This includes:+your own code, extra-deps, and in some cases even snapshot packages, if you+modify them in some way. The reason we have this structure is that:++* it lets multiple projects reuse the same binary builds of many snapshot+  packages,+* but doesn't allow different projects to "contaminate" each other by putting+  non-standard content into the shared snapshot database++Typically, the process by which a snapshot package is marked as modified is+referred to as "promoting to an extra-dep," meaning we treat it just like a+package in the extra-deps section. This happens for a variety of reasons,+including:++* changing the version of the snapshot package+* changing build flags+* one of the packages that the package depends on has been promoted to an+  extra-dep++As you probably guessed, there are multiple snapshot databases available, e.g.:++```+michael@d30748af6d3d:~/helloworld$ ls ~/.stack/snapshots/x86_64-linux/+lts-2.22  lts-3.1  lts-3.2  nightly-2015-08-26+```++These databases don't get layered on top of each other; they are each used+separately.++In reality, you'll rarely — if ever — interact directly with these databases,+but it's good to have a basic understanding of how they work so you can+understand why rebuilding may occur at different points.++## The build synonyms++Let's look at a subset of the `stack --help` output:++```+build    Build the project(s) in this directory/configuration+install  Shortcut for 'build --copy-bins'+test     Shortcut for 'build --test'+bench    Shortcut for 'build --bench'+haddock  Shortcut for 'build --haddock'+```++Note that four of these commands are just synonyms for the `build` command. They+are provided for convenience for common cases (e.g., `stack test` instead of+`stack build --test`) and so that commonly expected commands just work.++What's so special about these commands being synonyms? It allows us to make+much more composable command lines. For example, we can have a command that+builds executables, generates Haddock documentation (Haskell API-level docs),+and builds and runs your test suites, with:++```+stack build --haddock --test+```++You can even get more inventive as you learn about other flags. For example,+take the following:++```+stack build --pedantic --haddock --test --exec "echo Yay, it succeeded" --file-watch+```++This will:++* turn on all warnings and errors+* build your library and executables+* generate Haddocks+* build and run your test suite+* run the command `echo Yay, it succeeded` when that completes+* after building, watch for changes in the files used to build the project, and+  kick off a new build when done++### install and copy-bins++It's worth calling out the behavior of the install command and `--copy-bins`+option, since this has confused a number of users (especially when compared to+behavior of other tools like cabal-install). The `install` command does+precisely one thing in addition to the build command: it copies any generated+executables to the local bin path. You may recognize the default value for that+path:++```+michael@d30748af6d3d:~/helloworld$ stack path --local-bin-path+/home/michael/.local/bin+```++That's why the download page recommends adding that directory to your `PATH`+environment variable. This feature is convenient, because now you can simply+run `executable-name` in your shell instead of having to run `stack exec+executable-name` from inside your project directory.++Since it's such a point of confusion, let me list a number of things stack does+*not* do specially for the install command:++* stack will always build any necessary dependencies for your code. The install+  command is not necessary to trigger this behavior. If you just want to build a+  project, run `stack build`.+* stack will *not* track which files it's copied to your local bin path nor+  provide a way to automatically delete them. There are many great tools out+  there for managing installation of binaries, and stack does not attempt to+  replace those.+* stack will not necessarily be creating a relocatable executable. If your+  executables hard-codes paths, copying the executable will not change those+  hard-coded paths.+    * At the time of writing, there's no way to change those kinds of paths with+      stack, but see [issue #848 about+      --prefix](https://github.com/commercialhaskell/stack/issues/848) for+      future plans.++That's really all there is to the install command: for the simplicity of what+it does, it occupies a much larger mental space than is warranted.++## Targets, locals, and extra-deps++We haven't discussed this too much yet, but, in addition to having a number of+synonyms *and* taking a number of options on the command line, the build command+*also* takes many arguments. These are parsed in different ways, and can be used+to achieve a high level of flexibility in telling stack exactly what you want+to build.++We're not going to cover the full generality of these arguments here; instead,+there's [documentation covering the full build command+syntax](build_command.md).+Here, we'll just point out a few different types of arguments:++* You can specify a *package name*, e.g. `stack build vector`.+    * This will attempt to build the vector package, whether it's a local+      package, in your extra-deps, in your snapshot, or just available upstream.+      If it's just available upstream but not included in your locals,+      extra-deps, or snapshot, the newest version is automatically promoted to+      an extra-dep.+* You can also give a *package identifier*, which is a package name plus+  version, e.g. `stack build yesod-bin-1.4.14`.+    * This is almost identical to specifying a package name, except it will (1)+      choose the given version instead of latest, and (2) error out if the given+      version conflicts with the version of a local package.+* The most flexibility comes from specifying individual *components*, e.g.+  `stack build helloworld:test:helloworld-test` says "build the test suite+  component named helloworld-test from the helloworld package."+    * In addition to this long form, you can also shorten it by skipping what+      type of component it is, e.g. `stack build helloworld:helloworld-test`, or+      even skip the package name entirely, e.g. `stack build :helloworld-test`.+* Finally, you can specify individual *directories* to build to trigger building+  of any local packages included in those directories or subdirectories.++When you give no specific arguments on the command line (e.g., `stack build`),+it's the same as specifying the names of all of your local packages. If you+just want to build the package for the directory you're currently in, you can+use `stack build .`.++### Components, --test, and --bench++Here's one final important yet subtle point. Consider our helloworld package:+it has a library component, an executable helloworld-exe, and a test suite+helloworld-test. When you run `stack build helloworld`, how does it know which+ones to build? By default, it will build the library (if any) and all of the+executables but ignore the test suites and benchmarks.++This is where the `--test` and `--bench` flags come into play. If you use them,+those components will also be included. So `stack build --test helloworld` will+end up including the helloworld-test component as well.++You can bypass this implicit adding of components by being much more explicit,+and stating the components directly. For example, the following will not build+the helloworld-exe executable:++```+michael@d30748af6d3d:~/helloworld$ stack clean+michael@d30748af6d3d:~/helloworld$ stack build :helloworld-test+helloworld-0.1.0.0: configure (test)+Configuring helloworld-0.1.0.0...+helloworld-0.1.0.0: build (test)+Preprocessing library helloworld-0.1.0.0...+[1 of 1] Compiling Lib              ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )+In-place registering helloworld-0.1.0.0...+Preprocessing test suite 'helloworld-test' for helloworld-0.1.0.0...+[1 of 1] Compiling Main             ( test/Spec.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test-tmp/Main.o )+Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test ...+helloworld-0.1.0.0: test (suite: helloworld-test)+Test suite not yet implemented+```++We first cleaned our project to clear old results so we know exactly what stack+is trying to do. Notice that it builds the helloworld-test test suite, and the+helloworld library (since it's used by the test suite), but it does not build+the helloworld-exe executable.++And now the final point: the last line shows that our command also *runs* the+test suite it just built. This may surprise some people who would expect tests+to only be run when using `stack test`, but this design decision is what allows+the `stack build` command to be as composable as it is (as described+previously). The same rule applies to benchmarks. To spell it out completely:++* The --test and --bench flags simply state which components of a package should+  be built, if no explicit set of components is given+* The default behavior for any test suite or benchmark component which has been+  built is to also run it++You can use the `--no-run-tests` and `--no-run-benchmarks` (from stack-0.1.4.0+and on) flags to disable running of these components. You can also use+`--no-rerun-tests` to prevent running a test suite which has already passed and+has not changed.++NOTE: stack doesn't build or run test suites and benchmarks for non-local+packages. This is done so that running a command like `stack test` doesn't need+to run 200 test suites!++## Multi-package projects++Until now, everything we've done with stack has used a single-package project.+However, stack's power truly shines when you're working on multi-package+projects. All the functionality you'd expect to work just does: dependencies+between packages are detected and respected, dependencies of all packages are+just as one cohesive whole, and if anything fails to build, the build commands+exits appropriately.++Let's demonstrate this with the wai-app-static and yackage packages:++```+michael@d30748af6d3d:~$ mkdir multi+michael@d30748af6d3d:~$ cd multi/+michael@d30748af6d3d:~/multi$ stack unpack wai-app-static-3.1.1 yackage-0.8.0+wai-app-static-3.1.1: download+Unpacked wai-app-static-3.1.1 to /home/michael/multi/wai-app-static-3.1.1/+Unpacked yackage-0.8.0 to /home/michael/multi/yackage-0.8.0/+michael@d30748af6d3d:~/multi$ stack init+Writing default config file to: /home/michael/multi/stack.yaml+Basing on cabal files:+- /home/michael/multi/yackage-0.8.0/yackage.cabal+- /home/michael/multi/wai-app-static-3.1.1/wai-app-static.cabal++Checking against build plan lts-3.2+Selected resolver: lts-3.2+Wrote project config to: /home/michael/multi/stack.yaml+michael@d30748af6d3d:~/multi$ stack build --haddock --test+# Goes off to build a whole bunch of packages+```++If you look at the stack.yaml, you'll see exactly what you'd expect:++```yaml+flags:+  yackage:+    upload: true+  wai-app-static:+    print: false+packages:+- yackage-0.8.0/+- wai-app-static-3.1.1/+extra-deps: []+resolver: lts-3.2+```++Notice that multiple directories are listed in the `packages` key.++In addition to local directories, you can also refer to packages available in a+Git repository or in a tarball over HTTP/HTTPS. This can be useful for using a+modified version of a dependency that hasn't yet been released upstream. This is+a slightly more advanced usage that we won't go into detail with here, but it's+covered in the [stack.yaml documentation](yaml_configuration.md#packages).++## Flags and GHC options++There are two common ways to alter how a package will install: with Cabal flags+and with GHC options.++### Cabal flag management++In the stack.yaml file above, you can see that `stack init` has detected that —+for the yackage package — the upload flag can be set to true, and for+wai-app-static, the print flag to false (it's chosen those values because+they're the default flag values, and their dependencies are compatible with the+snapshot we're using.) To change a flag setting, we can use the command+line `--flag` option:++    stack build --flag yackage:-upload++This means: when compiling the yackage package, turn off the upload flag (thus+the `-`). Unlike other tools, stack is explicit about which package's flag you+want to change. It does this for two reasons:++1. There's no global meaning for Cabal flags, and therefore two packages can+   use the same flag name for completely different things.+2. By following this approach, we can avoid unnecessarily recompiling snapshot+   packages that happen to use a flag that we're using.++You can also change flag values on the command line for extra-dep and snapshot+packages. If you do this, that package will automatically be promoted to an+extra-dep, since the build plan is different than what the plan snapshot+definition would entail.++### GHC options++GHC options follow a similar logic as in managing Cabal flags, with a few+nuances to adjust for common use cases. Let's consider:++    stack build --ghc-options="-Wall -Werror"++This will set the `-Wall -Werror` options for all *local targets*. Note that+this will not affect extra-dep and snapshot packages at all. This design+provides us with reproducible and fast builds.++(By the way: the above GHC options have a special convenience flag:+`--pedantic`.)++There's one extra nuance about command line GHC options: Since they only apply+to local targets, if you change your local targets, they will no longer apply+to other packages. Let's play around with an example from the wai repository,+which includes the wai and warp packages, the latter depending on the former.+If we run:++    stack build --ghc-options=-O0 wai++It will build all of the dependencies of wai, and then build wai with all+optimizations disabled. Now let's add in warp as well:++    stack build --ghc-options=-O0 wai warp++This builds the additional dependencies for warp, and then builds warp with+optimizations disabled. Importantly: it does not rebuild wai, since wai's+configuration has not been altered. Now the surprising case:++```+michael@d30748af6d3d:~/wai$ stack build --ghc-options=-O0 warp+wai-3.0.3.0-5a49351d03cba6cbaf906972d788e65d: unregistering (flags changed from ["--ghc-options","-O0"] to [])+warp-3.1.3-a91c7c3108f63376877cb3cd5dbe8a7a: unregistering (missing dependencies: wai)+wai-3.0.3.0: configure+```++You may expect this to be a no-op: neither wai nor warp has changed. However,+stack will instead recompile wai with optimizations enabled again, and then+rebuild warp (with optimizations disabled) against this newly built wai. The+reason: reproducible builds. If we'd never built wai or warp before, trying to+build warp would necessitate building all of its dependencies, and it would do+so with default GHC options (optimizations enabled). This dependency would+include wai. So when we run:++    stack build --ghc-options=-O0 warp++We want its behavior to be unaffected by any previous build steps we took.+While this specific corner case does catch people by surprise, the overall goal+of reproducible builds is- in the stack maintainers' views- worth the+confusion.++Final point: if you have GHC options that you'll be regularly passing to your+packages, you can add them to your stack.yaml file (starting with+stack-0.1.4.0). See [the documentation section on+ghc-options](yaml_configuration.md#ghc-options)+for more information.++## path++NOTE: That's it, the heavy content of this guide is done! Everything from here+on out is simple explanations of commands. Congratulations!++Generally, you don't need to worry about where stack stores various files. But+some people like to know this stuff. That's when the `stack path` command is+useful.++```+michael@d30748af6d3d:~/wai$ stack path+global-stack-root: /home/michael/.stack+project-root: /home/michael/wai+config-location: /home/michael/wai/stack.yaml+bin-path: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/bin:/home/michael/.stack/programs/x86_64-linux/ghc-7.8.4/bin:/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin+ghc-paths: /home/michael/.stack/programs/x86_64-linux+local-bin-path: /home/michael/.local/bin+extra-include-dirs:+extra-library-dirs:+snapshot-pkg-db: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/pkgdb+local-pkg-db: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4/pkgdb+snapshot-install-root: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4+local-install-root: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4+snapshot-doc-root: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/doc+local-doc-root: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4/doc+dist-dir: .stack-work/dist/x86_64-linux/Cabal-1.18.1.5+```++In addition, `stack path` accepts command line arguments to state which of+these keys you're interested in, which can be convenient for scripting. As a+simple example, let's find out which versions of GHC are installed locally:++```+michael@d30748af6d3d:~/wai$ ls $(stack path --ghc-paths)/*.installed+/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2.installed+/home/michael/.stack/programs/x86_64-linux/ghc-7.8.4.installed+```++(Yes, that command requires a \*nix shell, and likely won't run on Windows.)++While we're talking about paths, to wipe our stack install completely, here's+what needs to be removed:++1. The stack executable itself+2. The stack root, e.g. `$HOME/.stack` on non-Windows systems.+    * See `stack path --global-stack-root`+    * On Windows, you will also need to delete `stack path --ghc-paths`+3. Any local `.stack-work` directories inside a project++## exec++We've already used `stack exec` used multiple times in this guide. As you've+likely already guessed, it allows you to run executables, but with a slightly+modified environment. In particular: `stack exec` looks for executables on+stack's bin paths, and sets a few additional environment variables (like+`GHC_PACKAGE_PATH`, which tells GHC which package databases to use).++If you want to see exactly what the modified environment looks like, try:++    stack exec env++The only issue is how to distinguish flags to be passed to stack versus those+for the underlying program. Thanks to the optparse-applicative library, stack+follows the Unix convention of `--` to separate these, e.g.:++```+michael@d30748af6d3d:~$ stack exec --package stm -- echo I installed the stm package via --package stm+Run from outside a project, using implicit global project config+Using latest snapshot resolver: lts-3.2+Writing global (non-project-specific) config file to: /home/michael/.stack/global/stack.yaml+Note: You can change the snapshot via the resolver field there.+I installed the stm package via --package stm+```++Flags worth mentioning:++* `--package foo` can be used to force a package to be installed before running+  the given command.+* `--no-ghc-package-path` can be used to stop the `GHC_PACKAGE_PATH` environment+  variable from being set. Some tools — notably cabal-install — do not behave+  well with that variable set.++## ghci (the repl)++GHCi is the interactive GHC environment, a.k.a. the REPL. You *could* access it+with:++    stack exec ghci++But that won't load up locally written modules for access. For that, use the+`stack ghci` command. To then load modules from your project, use the `:m`+command (for "module") followed by the module name.++## ghc/runghc++You'll sometimes want to just compile (or run) a single Haskell source file,+instead of creating an entire Cabal package for it. You can use `stack exec+ghc` or `stack exec runghc` for that. As simple helpers, we also provide the+`stack ghc` and `stack runghc` commands, for these common cases.++stack also offers a very useful feature for running files: a script+interpreter. For too long have Haskellers felt shackled to bash or Python+because it's just too hard to create reusable source-only Haskell scripts.+stack attempts to solve that. An example will be easiest to understand:++```+michael@d30748af6d3d:~$ cat turtle.hs+#!/usr/bin/env stack+-- stack --resolver lts-3.2 --install-ghc runghc --package turtle+{-# LANGUAGE OverloadedStrings #-}+import Turtle+main = echo "Hello World!"+michael@d30748af6d3d:~$ chmod +x turtle.hs+michael@d30748af6d3d:~$ ./turtle.hs+Run from outside a project, using implicit global project config+Using resolver: lts-3.2 specified on command line+hashable-1.2.3.3: configure+# installs some more dependencies+Completed all 22 actions.+Hello World!+michael@d30748af6d3d:~$ ./turtle.hs+Run from outside a project, using implicit global project config+Using resolver: lts-3.2 specified on command line+Hello World!+```++If you're on Windows: you can run `stack turtle.hs` instead of `./turtle.hs`.++The first line is the usual "shebang" to use stack as a script interpreter. The+second line, which is required, provides additional options to stack (due to+the common limitation of the "shebang" line only being allowed a single+argument). In this case, the options tell stack to use the lts-3.2 resolver,+automatically install GHC if it is not already installed, and ensure the turtle+package is available.++The first run can take a while (as it has to download GHC if necessary and build+dependencies), but subsequent runs are able to reuse everything already built,+and are therefore quite fast.++## Finding project configs, and the implicit global++Whenever you run something with stack, it needs a stack.yaml project file. The+algorithm stack uses to find this is:++1. Check for a `--stack-yaml` option on the command line+2. Check for a `STACK_YAML` environment variable+3. Check the current directory and all ancestor directories for a `stack.yaml`++The first two provide a convenient method for using an alternate configuration.+For example: `stack build --stack-yaml stack-7.8.yaml` can be used by your CI+system to check your code against GHC 7.8. Setting the `STACK_YAML` environment+variable can be convenient if you're going to be running commands like `stack+ghc` in other directories, but you want to use the configuration you defined in+a specific project.++If stack does not find a stack.yaml in any of the three specified locations,+the *implicit global* logic kicks in. You've probably noticed that phrase a few+times in the output from commands above. Implicit global is essentially a hack+to allow stack to be useful in a non-project setting. When no implicit global+config file exists, stack creates one for you with the latest LTS snapshot as+the resolver. This allows you to do things like:++* compile individual files easily with `stack ghc`+* build executables without starting a project, e.g. `stack install pandoc`++Keep in mind that there's nothing magical about this implicit global+configuration. It has no impact on projects at all. Every package you install+with it is put into isolated databases just like everywhere else. The only magic+is that it's the catch-all project whenever you're running stack somewhere else.++## stack.yaml vs .cabal files++Now that we've covered a lot of stack use cases, this quick summary of+stack.yaml vs .cabal files will hopefully make sense and be a good reminder for+future uses of stack:++* A project can have multiple packages.+* Each project has a stack.yaml.+* Each package has a .cabal file.+* The .cabal file specifies which packages are dependencies.+* The stack.yaml file specifies which packages are available to be used.+* .cabal specifies the components, modules, and build flags provided by a package+* stack.yaml can override the flag settings for individual packages+* stack.yaml specifies which packages to include++## Comparison to other tools++stack is not the only tool around for building Haskell code. stack came into+existence due to limitations with some of the existing tools. If you're+unaffected by those limitations and are happily building Haskell code, you may+not need stack. If you're suffering from some of the common problems in other+tools, give stack a try instead.++If you're a new user who has no experience with other tools, we recommend going+with stack. The defaults match modern best practices in Haskell development, and+there are less corner cases you need to be aware of. You *can* develop Haskell+code with other tools, but you probably want to spend your time writing code,+not convincing a tool to do what you want.++Before jumping into the differences, let me clarify an important similarity:++__Same package format.__ stack, cabal-install, and presumably all other tools+share the same underlying Cabal package format, consisting of a .cabal file,+modules, etc. This is a Good Thing: we can share the same set of upstream+libraries, and collaboratively work on the same project with stack,+cabal-install, and NixOS. In that sense, we're sharing the same ecosystem.++Now the differences:++* __Curation vs dependency solving as a default__.+    * stack defaults to using curation (Stackage snapshots, LTS Haskell,+      Nightly, etc) as a default instead of defaulting to dependency solving, as+      cabal-install does. This is just a default: as described above, stack can+      use dependency solving if desired, and cabal-install can use curation.+      However, most users will stick to the defaults. The stack team firmly+      believes that the majority of users want to simply ignore dependency+      resolution nightmares and get a valid build plan from day 1, which is why+      we've made this selection of default behavior.+* __Reproducible__.+    * stack goes to great lengths to ensure that `stack build` today does the+      same thing tomorrow. cabal-install does not: build plans can be affected+      by the presence of preinstalled packages, and running `cabal update` can+      cause a previously successful build to fail. With stack, changing the+      build plan is always an explicit decision.+* __Automatically building dependencies__.+    * In cabal-install, you need to use `cabal install` to trigger dependency+      building. This is somewhat necessary due to the previous point, since+      building dependencies can, in some cases, break existing installed+      packages. So for example, in stack, `stack test` does the same job as+      `cabal install --run-tests`, though the latter *additionally* performs an+      installation that you may not want. The closer command equivalent is+      `cabal install --enable-tests --only-dependencies && cabal configure+      --enable-tests && cabal build && cabal test` (newer versions of+      cabal-install may make this command shorter).+* __Isolated by default__.+    * This has been a pain point for new stack users. In cabal, the+      default behavior is a non-isolated build where working on two projects can+      cause the user package database to become corrupted. The cabal solution to+      this is sandboxes. stack, however, provides this behavior by default via+      its databases. In other words: when you use stack, there's __no need for+      sandboxes__, everything is (essentially) sandboxed by default.++__Other tools for comparison (including active and historical)__+* [cabal-dev](https://hackage.haskell.org/package/cabal-dev) (deprecated in favor of cabal-install)+* [cabal-meta](https://hackage.haskell.org/package/cabal-meta) inspired a lot of the multi-package functionality of stack. If you're still using cabal-install, cabal-meta is relevant. For stack work, the feature set is fully subsumed by stack.+* [cabal-src](https://hackage.haskell.org/package/cabal-src) is mostly irrelevant in the presence of both stack and cabal sandboxes, both of which make it easier to add additional package sources easily. The mega-sdist executable that ships with cabal-src is, however, still relevant. Its functionality may some day be folded into stack+* [stackage-cli](https://hackage.haskell.org/package/stackage-cli) was an initial attempt to make cabal-install work more easily with curated snapshots, but due to a slight impedance mismatch between cabal.config constraints and snapshots, it did not work as well as hoped. It is deprecated in favor of stack.++## More resources++There are lots of resources available for learning more about stack:++* `stack --help`+* `stack --version` — identify the version and Git hash of the stack executable+* `--verbose` (or `-v`) — much more info about internal operations (useful for bug reports)+* The [README](https://github.com/commercialhaskell/stack#readme)+* The [stack mailing list](https://groups.google.com/d/forum/haskell-stack)+* The [the FAQ](faq.md)+* The [stack wiki](https://github.com/commercialhaskell/stack/wiki)+* The [haskell-stack tag on Stack Overflow](http://stackoverflow.com/questions/tagged/haskell-stack)+* [Another getting started with stack tutorial](http://seanhess.github.io/2015/08/04/practical-haskell-getting-started.html)+* [Why is stack not cabal?](https://www.fpcomplete.com/blog/2015/06/why-is-stack-not-cabal)+++## Fun features++This is just a quick collection of fun and useful feature stack supports.++### Templates++We started off using the `new` command to create a project. stack provides+multiple templates to start a new project from:++```+michael@d30748af6d3d:~$ stack templates+chrisdone+hakyll-template+new-template+simple+yesod-minimal+yesod-mongo+yesod-mysql+yesod-postgres+yesod-postgres-fay+yesod-simple+yesod-sqlite+michael@d30748af6d3d:~$ stack new my-yesod-project yesod-simple+Downloading template "yesod-simple" to create project "my-yesod-project" in my-yesod-project/ ...+Using the following authorship configuration:+author-email: example@example.com+author-name: Example Author Name+Copy these to /home/michael/.stack/config.yaml and edit to use different values.+Writing default config file to: /home/michael/my-yesod-project/stack.yaml+Basing on cabal files:+- /home/michael/my-yesod-project/my-yesod-project.cabal++Checking against build plan lts-3.2+Selected resolver: lts-3.2+Wrote project config to: /home/michael/my-yesod-project/stack.yaml+```++To add more templates, see [the stack-templates+repository](https://github.com/commercialhaskell/stack-templates#readme).++### IDE++stack has a work-in-progress suite of editor integrations, to do things like+getting type information in Emacs. For more information, see+[stack-ide](https://github.com/commercialhaskell/stack-ide#readme).++### Visualizing dependencies++If you'd like to get some insight into the dependency tree of your packages, you+can use the `stack dot` command and Graphviz. More information is+[available in the Dependency visualization documentation](dependency_visualization.md).++### Travis with caching++Many people use Travis CI to test out a project for every Git push. We have [a+Wiki page devoted to+Travis](https://github.com/commercialhaskell/stack/wiki/Travis). However, for+most people, the following example will be sufficient to get started:++```yaml+# Use new container infrastructure to enable caching+sudo: false++# Choose a lightweight base image; we provide our own build tools.+language: c++# GHC depends on GMP. You can add other dependencies here as well.+addons:+  apt:+    packages:+    - libgmp-dev++# The different configurations we want to test. You could also do things like+# change flags or use --stack-yaml to point to a different file.+env:+- ARGS=""+- ARGS="--resolver lts-2"+- ARGS="--resolver lts-3"+- ARGS="--resolver lts"+- ARGS="--resolver nightly"++before_install:+# Download and unpack the stack executable+- mkdir -p ~/.local/bin+- export PATH=$HOME/.local/bin:$PATH+- travis_retry curl -L https://github.com/commercialhaskell/stack/releases/download/v0.1.6.0/stack-0.1.6.0-linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'++# This line does all of the work: installs GHC if necessary, build the library,+# executables, and test suites, and runs the test suites. --no-terminal works+# around some quirks in Travis's terminal implementation.+script: stack $ARGS --no-terminal --install-ghc test --haddock++# Caching so the next build will be fast too.+cache:+  directories:+  - $HOME/.stack+```++Not only will this build and test your project against multiple GHC versions+and snapshots, but it will cache your snapshot built packages, meaning that+subsequent builds will be much faster.++Once Travis whitelists the stack .deb files, we'll be able to simply include+stack in the `addons` section, and automatically use the newest version of+stack, avoiding that complicated `before_install` section This is being+tracked in the+[apt-source-whitelist](https://github.com/travis-ci/apt-source-whitelist/pull/7)+and+[apt-package-whitelist](https://github.com/travis-ci/apt-package-whitelist/issues/379)+issue trackers.++In case you're wondering: we need `--no-terminal` because stack does some fancy+sticky display on smart terminals to give nicer status and progress messages,+and the terminal detection is broken on Travis.++### Shell autocompletion++Love tab-completion of commands? You're not alone. If you're on bash, just run+the following (or add it to `.bashrc`):++    eval "$(stack --bash-completion-script "$(which stack)")"++For more information and other shells, see [the Shell autocompletion wiki+page](https://github.com/commercialhaskell/stack/wiki/Shell-autocompletion)++### Docker++stack provides two built-in Docker integrations. Firstly, you can build your+code inside a Docker image, which means:++* even more reproducibility to your builds, since you and the rest of your team+  will always have the same system libraries+* the Docker images ship with entire precompiled snapshots. That means you have+  a large initial download, but much faster builds++For more information, see+[the Docker-integration documentation](docker_integration.md).++stack can also generate Docker images for you containing your built executables.+This feature is great for automating deployments from CI. This feature is not+yet well-documented, but the basics are to add a section like the following+to stack.yaml:++```yaml+image:+  # YOU NEED A `container` YAML SECTION FOR `stack image container`+  container:+    # YOU NEED A BASE IMAGE NAME. STACK LAYERS EXES ON TOP OF+    # THE BASE IMAGE. PREPARE YOUR PROJECT IMAGE IN ADVANCE. PUT+    # ALL YOUR RUNTIME DEPENDENCIES IN THE IMAGE.+    base: "fpco/ubuntu-with-libgmp:14.04"+    # YOU CAN OPTIONALY NAME THE IMAGE. STACK WILL USE THE PROJECT+    # DIRECTORY NAME IF YOU LEAVE OUT THIS OPTION.+    name: "fpco/hello-world"+    # OPTIONALLY ADD A HASH OF LOCAL PROJECT DIRECTORIES AND THEIR+    # DESTINATIONS INSIDE THE DOCKER IMAGE.+    add:+      man/: /usr/local/share/man/+    # OPTIONALLY SPECIFY A LIST OF EXECUTABLES. STACK WILL CREATE+    # A TAGGED IMAGE FOR EACH IN THE LIST. THESE IMAGES WILL HAVE+    # THEIR RESPECTIVE "ENTRYPOINT" SET.+    entrypoints:+      - stack+```++and then run `stack image container` and then `docker images` to list+the images.++## Power user commands++The following commands are a little more powerful, and won't be needed by all+users. Here's a quick rundown:++* `stack update` will download the most recent set of packages from your package+  indices (e.g. Hackage). Generally, stack runs this for you automatically+  when necessary, but it can be useful to do this manually sometimes (e.g.,+  before running `stack solver`, to guarantee you have the most recent+  upstream packages available).+* `stack unpack` is a command we've already used quite a bit for examples, but+  most users won't use it regularly. It does what you'd expect: downloads a+  tarball and unpacks it.+* `stack sdist` generates an uploading tarball containing your package code+* `stack upload` uploads an sdist to Hackage. In the future, it will also+  perform automatic GPG signing of your packages for additional security, when+  configured.+* `stack upgrade` will build a new version of stack from source.+    * `--git` is a convenient way to get the most recent version from master for+      those testing and living on the bleeding edge.+* `stack setup --upgrade-cabal` can install a newer version of the Cabal+  library, used for performing actual builds. You shouldn't generally do this,+  since new Cabal versions may introduce incompatibilities with package sets,+  but it can be useful if you're trying to test a specific bugfix.+* `stack list-dependencies` lists all of the packages and versions used for a+  project++## Debugging++The following command installs with profiling enabled:++`stack install --enable-executable-profiling --enable-library-profiling+--ghc-options="-rtsopts"`++This command will allow you to use various tools to profile the time,+allocation, heap, and more of a program. The `-prof` GHC option is unnecessary+and will result in a warning. Additional compilation options can be added to+`--ghc-options` if needed. To see a general overview of the time and allocation+of a program called `main` compiled with the above command, you can run++`./main +RTS -p`++to generate a `main.prof` file containing the requested profiling information.+For more commands and uses, see [the official GHC chapter on+profiling](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html),+[the Haskell wiki](https://wiki.haskell.org/How_to_profile_a_Haskell_program),+and [the chapter on profiling in Real World+Haskell](http://book.realworldhaskell.org/read/profiling-and-optimization.html).
+ doc/MAINTAINER_GUIDE.md view
@@ -0,0 +1,38 @@+The following should be tested minimally before a release is considered good+to go. This list will likely expand over time:++* Run `etc/scripts/release.hs check` on Linux (32-bit and 64-bit), Windows (`--arch=i386` and `--arch=x86_64`), and OS X. See its+  [README](../etc/scripts/README.md#release.hs) for build and invocation instructions.+  This performs the following checks automatically:+    * `stack install && stack clean && stack install --pedantic && stack test --flag stack:integration-tests` on Linux, Windows, and OS X, which covers:+        * Self-hosting+        * Unit tests+        * Integration tests+        * stack can install GHC+    * Working tree is clean.+* Ensure that `stack --version` gives the correct version number and Git hash, and does not have a dirty tree+* stack can build the wai repo+* Running `stack build` a second time on either stack or wai is a no-op+* Build something that depends on `happy` (suggestion: `hlint`), since `happy` has special logic for moving around the `dist` directory+* Make sure to bump the version number in the .cabal file and the ChangeLog appropriately+* Review man page and other documentation for any changes that need to be made.++Release checklist after testing:++* Create a draft Github release with tag `vX.Y.Z` (where X.Y.Z is the stack package's version).+* Run `etc/scripts/release.hs release` on Linux (Debian 7 32-bit [Vagrantfile](https://github.com/commercialhaskell/stack/tree/master/etc/vagrant/debian-7-i386)/64-bit [Vagrantfile](https://github.com/commercialhaskell/stack/tree/master/etc/vagrant/debian-7-amd64)), Windows (`--arch=i386` and `--arch=x86_64`), and OS X.  This performs the following tasks automatically:+    * Binaries for Linux, Windows, and OS X uploaded to draft Github release.+* Run `etc/scripts/release.hs --binary-variant=gmp4 release` on CentOS 6 32-bit [Vagrantfile](https://github.com/commercialhaskell/stack/tree/master/etc/vagrant/centos-6-i386)/64-bit [Vagrantfile](centos-6-x86_64)).+* Run `etc/scripts/release.hs ubuntu-upload debian-upload` in Linux (Ubuntu or Debian - [Vagrantfile](https://github.com/commercialhaskell/stack/tree/master/etc/vagrant/debian-7-amd64))+* Run `etc/scripts/release.hs centos-upload fedora-upload` on Linux (CentOS or Fedora - [Vagrantfile](https://github.com/commercialhaskell/stack/tree/master/etc/vagrant/centos-7-x86_64))+* Upload Arch Linux packages (manual process)+* Build new MinGHC distribution (See https://github.com/fpco/minghc/commit/51490f398e6722672364548a3855a0bfcba48ffe)++After binaries uploaded:++* Push signed Git tag (matching Github release tag name).+* Publish Github release.+* Upload package to Hackage.+* Announce to haskell-cafe, commercialhaskell, and haskell-stack mailing lists.++For more information, see: https://github.com/commercialhaskell/stack/issues/324
+ doc/SIGNING_KEY.md view
@@ -0,0 +1,34 @@+Releases are signed with this key:++```+-----BEGIN PGP PUBLIC KEY BLOCK-----+Version: GnuPG v1++mQENBFVs+cMBCAC5IsLWTikd1V70Ur1FPJMn14Sc/C2fbXc0zRcPuWX+JaXgrIJQ+74A3UGBpa07wJDZiQLLz4AasDQj++9gXdiM9MlK/xWt8BQpgQqSMgkktFVajSWX2+rSXPjqLtsl5dLsc8ziBkd/AARXoeITmXX+n6oRTy6QfdMv2Tacnq7r9M9J6bAz6/+7UsKkyZVwsbUPea4SuD/s7jkXAuly15APaYDmF5mMlpoRWp442lJFpA0h52mREX1+s5FDbuKRQW7OpZdLcmOgoknJBDSpKHuHEoUhdG7Y3WDUGYFZcTtta1qSVHrm3nYa+7q5yOzPW4/VpftkBs1KzIxx0nQ5INT5W5+oTABEBAAG0H0ZQQ29tcGxldGUgPGRl+dkBmcGNvbXBsZXRlLmNvbT6JATcEEwEKACEFAlVs+cMCGwMFCwkIBwMFFQoJCAsF+FgMCAQACHgECF4AACgkQV1FZaJvvtEIP8gf/S/k4C3lp/BFb0K9DHHSt6EaGQPwy+g+O8d+JvL7ghkvMjlQ+UxDw+LfRKANTpl8a4vHtEQLHEy1tPJfrnMA8DNci8HLVx+rK3lIqMfv5t85VST9rz3X8huSw7qwFyxsmIqFtJC/BBQfsOXC+Q5Z2nbResXHMeA+5ZvDopZnqKPdmMOngabPGZd89hOKn6r8k7+yvZ/mXmrGOB8q5ZGbOXUbCshst7lc+yZWmoK3VJdErQjGHCdF4MC9KFBQsYYUy9b1q0OUv9QLtq/TeKxfpvYk9zMWAoafk+M8QBE/qqOpqkBRoKbQHCDQgx7AXJMKnOA0jPx1At57hWl7PuEH4rK38UtLkBDQRV+bPnDAQgAx1+4ENyaMk8XznQQ4l+nl8qw4UedZhnR5Xxr6z2kcMO/0VdwmIDCpxaM+spurOF+yExfY/Chbex7fThWTwVgfsItUc/QLLv9jkvpveMUDuPyh/4QrAQBYoW09+jMJcOTFQU+f4CtKaN/1PNoTSU2YkVpbhvtV3Jn2LPFjUSPb7z2NZ9NKe10M0/yN++l0CuPlqu6GZR5L3pA5i8PZ0Nh47j0Ux5KIjrjCGne4p+J8qqeRhUf04yHAYfDLgE+aLAG4v4pYbb1jNPUm1Kbk0lo2c3dxx0IU201uAQ6LNLdF/WW/ZF7w3iHn7kbbzXO+jhbq2rvZEn3K9xDr7homVnnj21/LSQARAQABiQEfBBgBCgAJBQJVbPnDAhsMAAoJ+EFdRWWib77RC3ukH/R9jQ4q6LpXynQPJJ9QKwstglKfoKNpGeAYVTEn0e7NB0HV5+BC+Da5SzBowboxC2YCD1wTAjBjLLQfAYNyR+tHpJBaBmruafj87nBCDhSWwWDXwx+OUDpNOwKUkrwZDRlM7n4byoMRl7Vh/7CXxaTqkyao1c5v3mHh/DremiTvOJ4OXgJ+77NHaPXezHkCFZC8/sX6aY0DJxF+LIE84CoLI1LYBatH+NKxoICKA+yeF3RIVw0/+F3mtEFEtmJ6ljSks5tECxfJFvQlkpILBbGvHfuljKMeaj+iN+bsHmV4em/ELB1ku+N9Obs/bFDBMmQklIdLP7dOunDjY4FwwcFcXdNyg=+=YUsC+-----END PGP PUBLIC KEY BLOCK-----+```
+ doc/architecture.md view
@@ -0,0 +1,131 @@+## Terminology++* Package identifier: a package name and version, e.g. text-1.2.1.0+* GhcPkgId: a package identifier plus the unique hash for the generated binary, e.g. text-1.2.1.0-bb83023b42179dd898ebe815ada112c2+* Package index: a collection of packages available for download. This is a combination of an index containing all of the .cabal files (either a tarball downloaded via HTTP(S) or a Git repository) and some way to download package tarballs.+    * By default, stack uses a single package index (the Github/S3 mirrors of Hackage), but supports customization and adding more than one index+* Package database: a collection of metadata about built libraries+* Install root: a destination for installing packages into. Contains a bin path (for generated executables), lib (for the compiled libraries), pkgdb (for the package database), and a few other things+* Snapshot: an LTS Haskell or Stackage Nightly, which gives information on a complete set of packages. This contains a lot of metadata, but importantly it can be converted into a mini build plan...+* Mini build plan: a collection of package identifiers and their build flags that are known to build together+* Resolver: the means by which stack resolves dependencies for your packages. The two currently supported options are snapshot (using LTS or Nightly), and GHC (which installs no extra dependencies). Others may be added in the future (such as a SAT-based dependency solver). These packages are always taken from a package index+* extra-deps: additional packages to be taken from the package index for dependencies. This list will *shadow* packages provided by the resolver+* Local packages: source code actually present on your file system, and referred to by the `packages` field in your stack.yaml file. Each local package has exactly one .cabal file+* Project: a stack.yaml config file and all of the local packages it refers to. ++## Databases++Every build uses three distinct install roots, which means three separate package databases and bin paths. These are:++* Global: the packages that ship with GHC. We never install anything into this database+* Snapshot: a database shared by all projects using the same snapshot. Packages installed in this database must use the exact same dependencies and build flags as specified in the snapshot, and cannot be affected by user flags, ensuring that one project cannot corrupt another. There are two caveats to this:+    * If different projects use different package indices, then their definitions of what package foo-1.2.3 are may be different, in which case they *can* corrupt each other's shared databases. This is warned about in the FAQ+    * Turning on profiling may cause a package to be recompiled, which will result in a different GhcPkgId+* Local: extra-deps, local packages, and snapshot packages which depend on them (more on that in shadowing)++## Building++### Shadowing++Every project must have precisely one version of a package. If one of your+local packages or extra dependencies conflicts with a package in the snapshot,+the local/extradep *shadows* the snapshot version. The way this works is:++* The package is removed from the list of packages in the snapshot+* Any package that depends on that package (directly or indirectly) is moved from the snapshot to extra-deps, so that it is available to your packages as dependencies.+    * Note that there is no longer any guarantee that this package will build, since you're using an untested dependency++After shadowing, you end up with what is called internally a `SourceMap`, which+is `Map PackageName PackageSource`, where a `PackageSource` can be either a+local package, or a package taken from a package index (specified as a version+number and the build flags).++### Installed packages++Once you have a `SourceMap`, you can inspect your three available databases and+decide which of the installed packages you wish to use from them. We move from+the global, to snapshot, and finally local, with the following rules:++* If we require profiling, and the library does not provide profiling, do not use it+* If the package is in the `SourceMap`, but belongs to a difference database, or has a different version, do not use it+* If after the above two steps, any of the dependencies are unavailable, do not use it+* Otherwise: include the package in the list of installed packages++We do something similar for executables, but maintain our own database of+installed executables, since GHC does not track them for us.++### Plan construction++When running a build, we know which packages we want installed (inventively+called "wanteds"), which packages are available to install, and which are+already installed. In plan construction, we put them information together to+decide which packages must be built. The code in Stack.Build.ConstructPlan is+authoritative on this and should be consulted. The basic idea though is:++* If any of the dependencies have changed, reconfigure and rebuild+* If a local package has any files changed, rebuild (but don't bother reconfiguring)+* If a local package is wanted and we're running tests or benchmarks, run the test or benchmark even if the code and dependencies haven't changed++### Plan execution++Once we have the plan, execution is a relatively simple process of calling+`runghc Setup.hs` in the correct order with the correct parameters. See+Stack.Build.Execute for more information.++## Configuration++stack has two layers of configuration: project and non-project. All of these+are stored in stack.yaml files, but the former has extra fields (resolver,+packages, extra-deps, and flags). The latter can be monoidally combined so that+a system config file provides defaults, which a user can override with+`~/.stack/config.yaml`, and a project can further customize. In addition,+environment variables STACK\_ROOT and STACK\_YAML can be used to tweak where+stack gets its configuration from.++stack follows a simple algorithm for finding your project configuration file:+start in the current directory, and keep going to the parent until it finds a+`stack.yaml`. When using `stack ghc` or `stack exec` as mentioned above, you'll+sometimes want to override that behavior and point to a specific project in+order to use its databases and bin directories. To do so, simply set the+`STACK_YAML` environment variable to point to the relevant `stack.yaml` file.++## Snapshot auto-detection++When you run `stack build` with no stack.yaml, it will create a basic+configuration with a single package (the current directory) and an+auto-detected snapshot. The algorithm it uses for selecting this snapshot is:++* Try the latest two LTS major versions at their most recent minor version release, and the most recent Stackage Nightly. For example, at the time of writing, this would be lts-2.10, lts-1.15, and nightly-2015-05-26+* For each of these, test the version bounds in the package's .cabal file to see if they are compatible with the snapshot, choosing the first one that matches+* If no snapshot matches, uses the most recent LTS snapshot, even though it will not compile++If you end up in the no compatible snapshot case, you typically have three options to fix things:++* Manually specify a different snapshot that you know to be compatible. If you can do that, great, but typically if the auto-detection fails, it means that there's no compatible snapshot+* Modify version bounds in your .cabal file to be compatible with the selected snapshot+* Add `extra-deps` to your stack.yaml file to fix compatibility problems++Remember that running `stack build` will give you information on why your build+cannot occur, which should help guide you through the steps necessary for the+second and third option above. Also, note that those options can be+mixed-and-matched, e.g. you may decide to relax some version bounds in your+.cabal file, while also adding some extra-deps.++## Explicit breakage++As mentioned above, updating your package indices will not cause stack to+invalidate any existing package databases. That's because stack is always+explicit about build plans, via:++1. the selected snapshot+2. the extra-deps+3. local packages++The only way to change a plan for packages to be installed is by modifying one+of the above. This means that breakage of a set of installed packages is an+*explicit* and *contained* activity. Specifically, you get the following+guarantees:++* Since snapshots are immutable, the snapshot package database will not be invalidated by any action. If you change the snapshot you're using, however, you may need to build those packages from scratch.+* If you modify your extra-deps, stack may need to unregister and reinstall them.+* Any changes to your local packages trigger a rebuild of that package and its dependencies.
+ doc/build_command.md view
@@ -0,0 +1,114 @@+## Overview++The primary command you use in stack is build. This page describes the details+of build's command line interface. The goal of the interface is to do the right+thing for simple input, and allow a lot of flexibility for more complicated+goals.++## Synonyms++One potential point of confusion is the synonym commands for `build`. These are+provided to match commonly expected command line interfaces, and to make common+workflows shorter. The important thing to note is that all of these are just+the `build` command in disguise. Each of these commands are called out as+synonyms in the `--help` output. These commands are:++* `stack test` is the same as `stack build --test`+* `stack bench` is the same as `stack build --bench`+* `stack haddock` is the same as `stack build --haddock`+* `stack install` is the same as `stack build --copy-bins`++The advantage of the synonym commands is that they're convenient and short. The+advantage of the options is that they compose. For example, `stack build --test+--copy-bins` will build libraries, executables, and test suites, run the test+suites, and then copy the executables to your local bin path (more on this+below).++## Components++Components are a subtle yet important point to how build operates under the+surface. Every cabal package is made up of one or more components. It can have+0 or 1 libraries, and then 0 or more of executable, test, and benchmark+components. stack allows you to call out a specific component to be built, e.g.+`stack build mypackage:test:mytests` will build the `mytests` component of the+`mypackage` package. `mytests` must be a test suite component.++We'll get into the details of the target syntax for how to select components in+the next section. In this section, the important point is: whenever you target+a test suite or a benchmark, it's built __and also run__, unless you explicitly+disable running via `--no-run-tests` or `--no-run-benchmarks`. Case in point:+the previous command will in fact build the `mytests` test suite *and* run it,+even though you haven't used the `stack test` command or the `--test` option.+(We'll get to what exactly `--test` does below.)++This gives you a lot of flexibility in choosing what you want stack to do. You+can run a single test component from a package, run a test component from one+package and a benchmark from another package, etc.++One final note on components: you can only control components for local+packages, not dependencies. With dependencies, stack will *always* build the+library (if present) and all executables, and ignore test suites and+benchmarks. If you want more control over a package, you must add it to your+`packages` setting in your stack.yaml file.++## Target syntax++In addition to a number of options (like the aforementioned `--test`), `stack+build` takes a list of zero or more *targets* to be built. There are a number+of different syntaxes supported for this list:++*   *package*, e.g. `stack build foobar`, is the most commonly used target. It will try to find the package in the following locations: local packages, extra dependencies, snapshots, and package index (e.g. Hackage). If it's found in the package index, then the latest version of that package from the index is implicitly added to your extra dependencies.++    This is where the `--test` and `--bench` flags come into play. If the package is a local package, then all of the test suite and benchmark components are selected to be built, respectively. In any event, the library and executable components are also selected to be built.++*   *package identifier*, e.g. `stack build foobar-1.2.3`, is usually used to include specific package versions from the index. If the version selected conflicts with an existing local package or extra dep, then stack fails with an error. Otherwise, this is the same as calling `stack build foobar`, except instead of using the latest version from the index, the version specified is used.++*   *component*. Instead of referring to an entire package and letting stack decide which components to build, you select individual components from inside a package. This can be done for more fine-grained control over which test suites to run, or to have a faster compilation cycle. There are multiple ways to refer to a specific component (provided for convenience):++    * `packagename:comptype:compname` is the most explicit. The available comptypes are `exe`, `test`, and `bench`.+    * `packagename:compname` allows you to leave off the component type, as that will (almost?) always be redundant with the component name. For example, `stack build mypackage:mytestsuite`.+    * `:compname` is a useful shortcut, saying "find the component in all of the local packages." This will result in an error if multiple packages have a component with the same name. To continue the above example, `stack build :mytestsuite`.+        * Side note: the commonly requested `run` command is not available because it's a simple combination of `stack build :exename && stack exec exename`++* *directory*, e.g. `stack build foo/bar`, will find all local packages that exist in the given directory hierarchy and then follow the same procedure as passing in package names as mentioned above. There's an important caveat here: if your directory name is parsed as one of the above target types, it will be treated as that. Explicitly starting your target with `./` can be a good way to avoid that, e.g. `stack build ./foo`++Finally: if you provide no targets (e.g., running `stack build`), stack will+implicitly pass in all of your local packages. If you only want to target+packages in the current directory or deeper, you can pass in `.`, e.g. `stack+build .`.++### Examples++FIXME: what examples would be helpful? Need feedback on what's confusing above++## Dependencies++stack will always automatically build all dependencies necessary for its targets.++## Other flags++There are a number of other flags accepted by `stack build`. Instead of listing+all of them, please use `stack build --help`. Some particularly convenient ones+worth mentioning here since they compose well with the rest of the build system+as described:++* `--file-watch` will rebuild your project every time a file changes+* `--exec "cmd [args]"` will run a command after a successful build++To come back to the composable approach described above, consider this final+example (which uses the [wai repository](https://github.com/yesodweb/wai/):++```+stack build --file-watch --test --copy-bins --haddock wai-extra :warp warp:doctest --exec 'echo Yay, it worked!'+```++This command will:++* Start stack up in file watch mode, waiting for files in your project to change. When first starting, and each time a file changes, it will do all of the following.+* Build the wai-extra package and its test suites+* Build the `warp` executable+* Build the warp package's doctest component (which, as you may guess, is a test site)+* Run all of the wai-extra package's test suite components and the doctest test suite component+* If all of that succeeds:+    * Copy generated executables to the local bin path+    * Run the command `echo Yay, it worked!`
+ doc/dependency_visualization.md view
@@ -0,0 +1,43 @@+You can use stack to visualize the dependencies between your projects and optionally also external dependencies.++As an example, let's look at `wreq`:++```+$ stack dot | dot -Tpng -o wreq.png+```+[![wreq](https://cloud.githubusercontent.com/assets/591567/8478591/ae10a418-20d2-11e5-8945-55246dcfac62.png)](https://cloud.githubusercontent.com/assets/591567/8478591/ae10a418-20d2-11e5-8945-55246dcfac62.png)++Okay that is a little boring, let's also look at external dependencies:+```+$ stack dot --external | dot -Tpng -o wreq.png+```+[![wreq_ext](https://cloud.githubusercontent.com/assets/591567/8478621/d247247e-20d2-11e5-993d-79096e382abd.png)](https://cloud.githubusercontent.com/assets/591567/8478621/d247247e-20d2-11e5-993d-79096e382abd.png)++Well that is certainly a lot.  As a start we can exclude `base` and then depending on our needs we can either limit the depth:++```+$ stack dot --no-include-base --external --depth 1 | dot -Tpng -o wreq.png+```+[![wreq_depth](https://cloud.githubusercontent.com/assets/591567/8484310/45b399a0-20f7-11e5-8068-031c2b352961.png)](https://cloud.githubusercontent.com/assets/591567/8484310/45b399a0-20f7-11e5-8068-031c2b352961.png)++or prune packages explicitly:++```+$ stack dot --external --prune base,lens,wreq-examples,http-client,aeson,tls,http-client-tls,exceptions | dot -Tpng -o wreq_pruned.png+```+[![wreq_pruned](https://cloud.githubusercontent.com/assets/591567/8478768/adbad280-20d3-11e5-9992-914dc24fe569.png)](https://cloud.githubusercontent.com/assets/591567/8478768/adbad280-20d3-11e5-9992-914dc24fe569.png)++Keep in mind that you can also save the dot file:+```+$ stack dot --external --depth 1 > wreq.dot+$ dot -Tpng -o wreq.png wreq.dot+```++and pass in options to `dot` or use another graph layout engine like `twopi`:++```+$ stack dot --external --prune base,lens,wreq-examples,http-client,aeson,tls,http-client-tls,exceptions | twopi -Groot=wreq -Goverlap=false -Tpng -o wreq_pruned.png+```+[![wreq_pruned](https://cloud.githubusercontent.com/assets/591567/8495538/9fae1184-216e-11e5-9931-99e6147f8aed.png)](https://cloud.githubusercontent.com/assets/591567/8495538/9fae1184-216e-11e5-9931-99e6147f8aed.png)++
+ doc/docker_integration.md view
@@ -0,0 +1,448 @@+Using Docker with Stack+===============================================================================++`stack` has support for automatically performing builds inside a Docker+container, using volume mounts and user ID switching to make it mostly seamless.+FP Complete provides images for use with stack that include GHC, tools, and+optionally have all of the Stackage LTS packages pre-installed in in the global+package database.++The primary purpose for using stack/docker this way is for teams to ensure all+developers are building in an exactly consistent environment without team+members needing to deal with Docker themselves.++See the+[how stack can use Docker under the hood](https://www.fpcomplete.com/blog/2015/08/stack-docker)+blog post for more information about the motivation and implementation of stack's+Docker support.++Usage+-------------------------------------------------------------------------------++This section assumes that you already have Docker installed and working. If+not, see the [prerequisites](#prerequisites) section. If you run into any+trouble, see the [troubleshooting](#troubleshooting) section.++### Enable in stack.yaml++The most basic configuration is to add this to your project's `stack.yaml`:++    docker:+        enable: true++See [configuration](#configuration) for additional options.++### Use stack as normal++With Docker enabled, most stack sub-commands will automatically launch+themselves in an ephemeral Docker container (the container is deleted as soon as+the command completes). The project directory and `~/.stack` are volume-mounted+into the container, so any build artifacts are "permanent" (not deleted with the+container).++The first time you run a command with a new image, you will be prompted to run+`stack docker pull` to pull the image first. This will pull a Docker+image with a tag that matches your resolver. Only LTS resolvers are supported+(we do not generate images for nightly snapshots).  Not every LTS version is+guaranteed to have an image existing, and new LTS images tend to lag behind+the LTS snapshot being published on stackage.org.  Be warned: these images are+rather large!++Docker sub-commands+-------------------------------------------------------------------------------++These `stack docker` sub-commands have Docker-specific functionality. Most other+`stack` commands will also use a Docker container under the surface if Docker is+enabled.++### pull - Pull latest version of image++`stack docker pull` pulls an image from the Docker registry for the first time,+or updates the image by pulling the latest version.++### cleanup - Clean up old images and containers++Docker images can take up quite a lot of disk space, and it's easy for them to+build up if you switch between projects or your projects update their images.+This sub-command will help to remove old images and containers.++By default, `stack docker cleanup` will bring up an editor showing the images+and containers on your system, with any stack images that haven't been used+in the last seven days marked for removal.  You can add or remove the `R` in+the left-most column to flag or unflag an image/container for removal.  When+you save the file and quit the text editor, those images marked for removal+will be deleted from your system.  If you wish to abort the cleanup, delete+all all the lines from your editor.++If you use Docker for purposes other than stack, you may have other images on+your system as well.  These will also appear in in a separate section, but they+will not be marked for removal by default.++Run `stack docker cleanup --help` to see additional options to customize its+behaviour.++### reset - Reset the Docker "sandbox"++In order to preserve the contents of the in-container home directory between+runs, a special "sandbox" directory is volume-mounted into the container. `stack+docker reset` will reset that sandbox to its defaults.++Note: this leaves of `~/.stack` (which is separately volume-mounted) alone.++Command-line options+-------------------------------------------------------------------------------++The default Docker configuration can be overridden on the command-line. See+`stack --docker-help` for a list of all Docker options, and consult+[configuration](#configuration) section below for more information about+their meanings. These are global options, and apply to all commands (not just+`stack docker` sub-commands).++Configuration+-------------------------------------------------------------------------------++`stack.yaml` contains a `docker:` section with Docker settings.  If this+section is omitted, Docker containers will not be used.  These settings can+be included in project, user, or global configuration.++Here is an annotated configuration file.  The default values are shown unless+otherwise noted.++    docker:++      # Set to false to disable using Docker.  In the project configuration,+      # the presence of a `docker:` section implies docker is enabled unless+      # `enable: false` is set.  In user and global configuration, this is not+      # the case.+      enable: true++      # The name of the repository to pull the image from.  See the "reposities"+      # section of this document for more information about available repositories.+      # If this includes a tag (e.g. "my/image:tag"), that tagged image will be+      # used.  Without a tag specified, the LTS version slug is added automatically.+      # Either `repo` or `image` may be specified, but not both.+      repo: "fpco/stack-build"++      # Exact Docker image name or ID.  Overrides `repo`. Either `repo` or `image`+      # may be specified, but not both.  (default none)+      image: "5c624ec1d63f"++      # Registry requires login.  A login will be requested before attempting to+      # pull.+      registry-login: false++      # Username to log into the registry.  (default none)+      registry-username: "myuser"++      # Password to log into the registry.  (default none)+      registry-password: "SETME"++      # If true, the image will be pulled from the registry automatically, without+      # needing to run `stack docker pull`.  See the "security" section of this+      # document for implications of enabling this.+      auto-pull: false++      # If true, the container will be run "detached" (in the background).  Refer+      # to the Docker users guide for information about how to manage containers.+      # This option would rarely make sense in the configuration file, but can be+      # useful on the command-line.  When true, implies `persistent`.`+      detach: false++      # If true, the container will not be deleted after it terminates.  Refer to+      # the Docker users guide for information about how to manage containers. This+      # option would rarely make sense in the configuration file, but can be+      # useful on the command-line.  `detach` implies `persistent`.+      persistent: false++      # What to name the Docker container.  Only useful with `detach` or+      # `persistent` true.  (default none)+      container-name: "example-name"++      # Additional arguments to pass to `docker run`.  (default none)+      run-args: ["--net=bridge"]++      # Directories from the host to volume-mount into the container.  If it+      # contains a `:`, the part before the `:` is the directory on the host and+      # the part after the `:` is where it should be mounted in the container.+      # (default none, aside from the project and stack root directories which are+      # always mounted)+      mount:+        - "/foo/bar"+        - "/baz:/tmp/quux"++      # Environment variables to set in the container.  Environment variables+      # are not automatically inherited from the host, so if you need any specific+      # variables, use the '--docker-env` command-line argument version of this to+      # pass them in.  (default none)+      env:+        - "FOO=BAR"+        - "BAR=BAZ QUUX"++      # Location of database used to track image usage, which `stack docker cleanup`+      # uses to determine which images should be kept.  On shared systems, it may+      # be useful to override this in the global configuration file so that+      # all users share a single database.+      database-path: "~/.stack/docker.db"++      # Location of a Docker container-compatible 'stack' executable with the+      # matching version. This executable must be built on linux-x86_64 and+      # statically linked.+      # Valid values are:+      #   host: use the host's executable.  This is the default when the host's+      #     executable is known to work (e.g., from official linux-x86_64 bindist)+      #   download: download a compatible executable matching the host's version.+      #     This is the default when the host's executable is not known to work+      #   image: use the 'stack' executable baked into the image.  The version+      #     must match the host's version+      #   /path/to/stack: path on the host's local filesystem+      stack-exe: host++      # If true (the default when using the local Docker Engine), run processes+      # in the Docker container as the same UID/GID as the host.  The ensures+      # that files written by the container are owned by you on the host.+      # When the Docker Engine is remote (accessed by tcp), defaults to false.+      set-user: true++Image Repositories+-------------------------------------------------------------------------------++FP Complete provides the following public image repositories on Docker Hub:++- [fpco/stack-build](https://registry.hub.docker.com/u/fpco/stack-build/) (the+  default) - GHC (patched), tools (stack, cabal-install, happy, alex, etc.), and+  system developer libraries required to build all Stackage packages.+- [fpco/stack-ghcjs-build](https://registry.hub.docker.com/u/fpco/stack-ghcjs-build/) -+  Like `stack-build`, but adds GHCJS.+- [fpco/stack-full](https://registry.hub.docker.com/u/fpco/stack-full/) -+  Includes all Stackage packages pre-installed in GHC's global package database.+  These images are over 10 GB!+- [fpco/stack-ghcjs-full](https://registry.hub.docker.com/u/fpco/stack-ghcjs-full/) -+  Like `stack-full`, but adds GHCJS.+- [fpco/stack-run](https://registry.hub.docker.com/u/fpco/stack-run/) -+  Runtime environment for binaries built with Stackage. Includes system shared+  libraries required by all Stackage packages. Does not necessarily include all+  data required for every use (e.g. has texlive-binaries for HaTeX, but does not+  include LaTeX fonts), as that would be prohibitively large. Based on+  [phusion/baseimage](https://registry.hub.docker.com/u/phusion/baseimage/).++FP Complete also builds custom variants of these images for their clients.++These images can also be used directory with `docker run` and provide a complete+Haskell build environment.++Prerequisites+-------------------------------------------------------------------------------++### Linux 64-bit++Docker use requires machine (virtual or metal) running a Linux distribution+[that Docker supports](https://docs.docker.com/installation/#installation), with+a 64-bit kernel. If you do not already have one, we suggest Ubuntu 14.04+("trusty") since this is what we test with.++While Docker does support non-Linux operating systems through the `boot2docker`+VM, there are issues with host volume mounting that prevent stack from being+usable in this configuration. See+[#194](https://github.com/commercialhaskell/stack/issues/194) for details and+workarounds.++### Docker++Install the latest version of Docker by following the+[instructions for your operating system](http://docs.docker.com/installation/).++The Docker client should be able to connect to the Docker daemon as a non-root+user. For example (from+[here](http://docs.docker.com/installation/ubuntulinux/#ubuntu-raring-1304-and-saucy-1310-64-bit)):++    # Add the connected user "${USER}" to the docker group.+    # Change the user name to match your preferred user.+    sudo gpasswd -a ${USER} docker++    # Restart the Docker daemon.+    sudo service docker restart++You will now need to log out and log in again for the the group addition+to take effect.++Note the above has security implications.  See [security](#security) for more.++Security+-------------------------------------------------------------------------------++Having `docker` usable as a non-root user is always a security risk, and will+allow root access to your system. It is also possible to craft a `stack.yaml`+that will run arbitrary commands in an arbirary docker container through that+vector, thus a `stack.yaml` could cause stack to run arbitrary commands as root.+While this is a risk, it is not really a greater risk than is posed by the+docker permissions in the first place (for example, if you ever run an unknown+shell script or executable, or ever compile an unknown Haskell package that uses+Template Haskell, you are at equal risk). Nevertheless, there are+[plans to close the stack.yaml loophole](https://github.com/commercialhaskell/stack/issues/260).++One way to mitigate this risk is, instead of allowing `docker` to run as+non-root, replace `docker` with a wrapper script that uses `sudo` to run the+real Docker client as root. This way you will at least be prompted for your root+password. As [@gregwebs](https://github.com/gregwebs) pointed out, put this+script named `docker` in your PATH (and make sure you remove your user from the+`docker` group as well, if you added it earlier):++    #!/bin/bash -e+    # The goal of this script is to maintain the security privileges of sudo+    # Without having to constantly type "sudo"+    exec sudo /usr/bin/docker "$@"++Additional notes+-------------------------------------------------------------------------------++### Volume-mounts and ephemeral containers++Since filesystem changes outside of the volume-mounted project directory are not+persisted across runs, this means that if you `stack exec sudo apt-get install+some-ubuntu-package`, that package will be installed but then the container it's+installed in will disappear, thus causing it to have no effect. If you wish to+make this kind of change permanent, see later instructions for how to create a+[derivative Docker image](#derivativeimage).++Inside the container, your home directory is a special location that volume-+mounted from within your project directory's `.stack-work` in such a+way as that installed GHC/cabal packages are not shared between different+Stackage snapshots.  In addition, `~/.stack` is volume-mounted from the host.++### Network++stack containers use use the host's network stack within the container+by default, meaning a process running in the container can connect to+services running on the host, and a server process run within the container+can be accessed from the host without needing to explicitly publish its port.+To run the container with an isolated network, use `--docker-run-args` to pass+a the `--net` argument to `docker-run`.  For example:++    stack --docker-run-args='--net=bridge --publish=3000:3000' \+          exec some-server++will run the container's network in "bridge" mode (which is Docker's default)+and publish port 3000.++### Persistent container++If you do want to do all your work, including editing, in the container, it+might be better to use a persistent container in which you can install Ubuntu+packages. You could get that by running something like `stack+--docker-container-name=NAME --docker-persist docker exec bash`. This+means when the container exits, it won't be deleted. You can then restart it+using `docker start -a -i NAME`. It's also possible to detach from a container+while it continues running in the background using by pressing Ctrl-P Ctrl-Q,+and then reattach to it using `docker attach NAME`.++Note that each time you run `stack --docker-persist`, a _new_ persistent+container is created (it will not automatically reuse the previous one).+See the [Docker user guide](https://docs.docker.com/userguide/) for more+information about managing Docker containers.++### Derivative image++Creating your own custom derivative image can be useful if you need to install+additional Ubuntu packages or make other changes to the operating system. Here+is an example (replace `custom` if you prefer a different name for your derived+container):++    # On host+    $ stack  --docker-persist --docker-container-name=temp docker exec bash++    # In container, make changes to OS+    $ sudo apt-get install r-cran-numderiv+    [...]+    $ exit++    # On host again+    $ docker commit temp custom+    $ docker rm temp++Now you have a new Docker image named `custom`. To use the new image, run+a command such as the following or update the corresponding values in your+`stack.yaml`:++    stack --docker-image=custom <COMMAND>++Note, however, that any time a new image is used, you will have to re-do this+process. You could also use a Dockerfile to make this reusable. Consult the+[Docker user guide](https://docs.docker.com/userguide/) for more+on creating Docker images.++Troubleshooting+-------------------------------------------------------------------------------++### "No Space Left on Device", but 'df' shows plenty of disk space++This is likely due to the storage driver Docker is using, in combination with+the large size and number of files in these images. Use `docker info|grep+'Storage Driver'` to determine the current storage driver.++We recommend using either the `overlay` or `aufs` storage driver for stack, as+they are least likely to give you trouble.  On Ubuntu, `aufs` is the default for+new installations, but older installations sometimes used `devicemapper`.++The `devicemapper` storage driver's default configuration limits it to a 10 GB+file system, which the "full" images exceed. We have experienced other+instabilities with it as well on Ubuntu, and recommend against its use for this+purpose.++The `btrfs` storage driver has problems running out of metadata space long+before running out of actual disk space, which requires rebalancing or adding+more metadata space. See+[CoreOS's btrfs troubleshooting page](https://coreos.com/docs/cluster-management/debugging/btrfs-troubleshooting/)+for details about how to do this.++Pass the `-s <driver>` argument to the Docker daemon to set the storage driver+(in `/etc/default/docker` on Ubuntu). See+[Docker daemon storage-driver option](https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option)+for more details.++You may also be running out of inodes on your filesystem.  Use `df -i` to check+for this condition.  Unfortunately, the number of inodes is set when creating+the filesystem, so fixing this requires reformatting and passing the `-N`+argument to mkfs.ext4.++### Name resolution doesn't work from within container++On Ubuntu 12.04, by default `NetworkManager` runs `dnsmasq` service, which sets+`127.0.0.1` as your DNS server. Since Docker containers cannot access this+dnsmasq, Docker falls back to using Google DNS (8.8.8.8/8.8.4.4). This causes+problems if you are forced to use internal DNS server. This can be fixed by+executing:++    sudo sed 's@dns=dnsmasq@#dns=dnsmasq@' -i \+        /etc/NetworkManager/NetworkManager.conf && \+    sudo service network-manager restart++If you have already installed Docker, you must restart the daemon for this+change to take effect:++    sudo service docker restart++<small>+The above commands turn off `dnsmasq` usage in NetworkManager+configuration and restart network manager.  They can be reversed by executing+`sudo sed 's@#dns=dnsmasq@dns=dnsmasq@' -i+/etc/NetworkManager/NetworkManager.conf && sudo service network-manager+restart`.  These instructions are adapted from+[the Shipyard Project's QuickStart guide](https://github.com/shipyard/shipyard/wiki/QuickStart#127011-dns-server-problem-on-ubuntu).+</small>++### Cannot pull images from behind firewall that blocks TLS/SSL++If you are behind a firewall that blocks TLS/SSL and pulling images from a+private Docker registry, you must edit the system configuration so that the+`--insecure-registry <registry-hostname>` option is passed to the Docker daemon.+For example, on Ubuntu:++    echo 'DOCKER_OPTS="--insecure-registry registry.example.com"' \+        |sudo tee -a /etc/default/docker+    sudo service docker restart++This does require the private registry to be available over plaintext HTTP.++See+[Docker daemon insecure registries documentation](https://docs.docker.com/reference/commandline/cli/#insecure-registries)+for details.
+ doc/faq.md view
@@ -0,0 +1,277 @@+So that this doesn't become repetitive: for the reasons behind the answers+below, see the [Architecture](architecture.md) page. The goal of the answers here is to be as+helpful and concise as possible.++#### Where is stack installed and will it interfere with `ghc` (etc) I already have installed?++Stack itself is installed in normal system locations based on the mechanism you used (see the [Install and upgrade](install_and_upgrade.md) page). Stack installs the Stackage libraries in `~/.stack` and any project libraries or extra dependencies in a `.stack-work` directory within each project's directory. None of this should affect any existing Haskell tools at all.++#### What is the relationship between stack and cabal?++* Cabal-the-library is used by stack to build your Haskell code.+* cabal-install (the executable) is used by stack for its dependency solver functionality.+* A .cabal file is provided for each package, and defines all package-level metadata just like it does in the cabal-install world: modules, executables, test suites, etc. No change at all on this front.+* A stack.yaml file references 1 or more packages, and provides information on where dependencies come from.+* `stack build` currently initializes a stack.yaml from the existing .cabal file. Project initialization is something that is still being discussed and there may be more options here for new projects in the future (see issue [253](https://github.com/commercialhaskell/stack/issues/253))++#### I need to use a different version of a package than what is provided by the LTS Haskell snapshot I'm using, what should I do?++You can make tweaks to a snapshot by modifying the `extra-deps` configuration value in your `stack.yaml` file, e.g.:++```yaml+resolver: lts-2.9+packages:+- '.'+extra-deps:+- text-1.2.1.1+```++#### I need to use a package (or version of a package) that is not available on hackage, what should I do?++Add it to the `packages` list in your project's `stack.yaml`, specifying the package's source code location relative to the directory where your `stack.yaml` file lives, e.g.++```yaml+resolver: lts-2.10+packages:+- '.'+- third-party/proprietary-dep+- github-version-of/conduit+- patched/diagrams+extra-deps: []+```++The above example specifies that the `proprietary-dep` package is found in the project's `third-party` folder, that the `conduit` package is found in the project's `github-version-of` folder, and that the `diagrams` package is found in the project's `patched` folder. This autodetects changes and reinstalls the package.++#### What is the meaning of the arguments given to stack build, test, etc?++Those are the targets of the build, and can have one of three formats:++* A package name (e.g., `my-package`) will mean that the `my-package` package must be built+* A package identifier (e.g., `my-package-1.2.3`), which includes a specific version. This is useful for passing to `stack install` for getting a specific version from upstream+* A directory (e.g., `./my-package`) for including a local directory's package, including any packages in subdirectories++#### I need to modify an upstream package, how should I do it?++Typically, you will want to get the source for the package and then add it to+your `packages` list in stack.yaml. (See the previous question.)+`stack unpack` is one approach for getting the source.+Another would be to add the upstream package as a submodule to your+project.++#### Am I required to use a Stackage snapshot to use stack?++No, not at all. If you prefer dependency solving to curation, you can continue with that workflow. Instead of describing the details of how that works here, it's probably easiest to just say: run `stack init --solver` and look at the generated stack.yaml.++#### How do I use this with sandboxes?++Explicit sandboxing on the part of the user is not required by stack. All+builds are automatically isolated into separate package databases without any+user interaction. This ensures that you won't accidentally corrupt your+installed packages with actions taken in other projects.++#### Can I run `cabal` commands inside `stack exec`?++With a recent enough version of cabal-install (>= 1.22), you can. For older versions, due to [haskell/cabal#1800](https://github.com/haskell/cabal/issues/1800), this does not work. Note that even with recent versions, for some commands you may need this extra level of indirection:+```+$ stack exec -- cabal exec -- cabal <command>+```++However, virtually all `cabal` commands have an equivalent in stack, so this should not be necessary. In particular, `cabal` users may be accustomed to the `cabal run` command. In stack:+```+$ stack build && stack exec <program-name>+````+Or, if you want to install the binaries in a shared location:+```+$ stack install+$ <program-name>+```+assuming your `$PATH` has been set appropriately.++#### Using custom preprocessors++If you have a custom preprocessor, for example, Ruby, you may have a+file like:++***B.erb***++``` haskell+module B where++<% (1..5).each do |i| %>+test<%= i %> :: Int+test<%= i %> = <%= i %>+<% end %>+```++To ensure that Stack picks up changes to this file for rebuilds, add+the following line to your .cabal file:++    extra-source-files:   B.erb++#### I already have GHC installed, can I still use stack?++Yes. stack will default to using whatever GHC is on your `PATH`. If that GHC is a+compatible version with the snapshot you're using, it will simply use it.+Otherwise, it will prompt you to run `stack setup`. Note that `stack setup` installs GHC into `~/.stack/programs/$platform/ghc-$version/` and not a global location.++Note that GHC installation doesn't work for all OSes, so in some cases the+first option will need to install GHC yourself.++#### How does stack determine what GHC to use?++It uses the first GHC that it finds on the `PATH`. If that GHC does not comply with the various requirements (version, architecture) that your project needs, it will prompt you to run `stack setup` to get it. `stack` is fully aware of all GHCs that it has installed itself.++See [this issue](https://github.com/commercialhaskell/stack/issues/420) for a detailed discussion.++#### How do I upgrade to GHC 7.10.2 with stack?++If you already have a prior version of GHC use `stack --resolver ghc-7.10 setup --reinstall`. If you don't have any GHC installed, you can skip the `--reinstall`. ++#### How do I get extra build tools?++stack will automatically install build tools required by your packages or their+dependencies, in particular alex and happy.++__NOTE__: This works when using lts or nightly resolvers, not with ghc or custom resolvers. You can manually install build tools by running, e.g., `stack build alex happy`.++#### How does stack choose which snapshot to use when creating a new config file?++It checks the two most recent LTS Haskell major versions and the most recent+Stackage Nightly for a snapshot that is compatible with all of the version+bounds in your .cabal file, favoring the most recent LTS. For more information,+see the snapshot auto-detection section in the architecture document.++#### I'd like to use my installed packages in a different directory. How do I tell stack where to find my packages?++Set the `STACK_YAML` environment variable to point to the `stack.yaml` config+file for your project. Then you can run `stack exec`, `stack ghc`, etc., from+any directory and still use your packages.++#### My tests are failing. What should I do?++Like all other targets, `stack test` runs test suites in parallel by default. This can cause problems with test suites that depend on global resources such as a database or binding to a fixed port number. A quick hack is to force stack to run all test suites in sequence, using `stack test --jobs=1`. For test suites to run in parallel developers should ensure that their test suites do not depend on global resources (e.g. by asking the OS for a random port to bind to) and where unavoidable, add a lock in order to serialize access to shared resources.++#### Can I get bash autocompletion?++Yes, see the [shell-autocompletion documentation](shell_autocompletion.md)++#### How do I update my package index?++Users of cabal are used to running `cabal update` regularly. You can do the+same with stack by running `stack update`. But generally, it's not necessary:+if the package index is missing, or if a snapshot refers to package/version+that isn't available, stack will automatically update and then try again. If+you run into a situation where stack doesn't automatically do the update for+you, please report it as a bug.++#### Isn't it dangerous to automatically update the index? Can't that corrupt build plans?++No, stack is very explicit about which packages it's going to build for you.+There are three sources of information to tell it which packages to install:+the selected snapshot, the `extra-deps` configuration value, and your local+packages. The only way to get stack to change its build plan is to modify one+of those three. Updating the index will have no impact on stack's behavior.++#### I have a custom package index I'd like to use, how do I do so?++You can configure this in your stack.yaml. See [YAML configuration](yaml_configuration.md).++#### How can I make sure my project builds against multiple ghc versions?++You can create multiple yaml files for your project,+one for each build plan. For example, you might set up your project directory like so:++```+myproject/+  stack-7.8.yaml+  stack-7.10.yaml+  stack.yaml --> symlink to stack-7.8.yaml+  myproject.cabal+  src/+    ...+```++When you run `stack build`, you can set the+`STACK_YAML` environment variable to indicate which build plan to use.++```+$ stack build                             # builds using the default stack.yaml+$ STACK_YAML=stack-7.10.yaml stack build  # builds using the given yaml file+```++#### I heard you can use this with Docker?++Yes, stack supports using Docker with images that contain preinstalled Stackage+packages and the tools. See [Docker integration](docker_integration.md) for details.++#### How do I use this with Travis CI?++See the [Travis section in the GUIDE](GUIDE.md#travis-with-caching)++#### What is licensing restrictions on Windows?++Currently on Windows GHC produces binaries linked statically with [GNU Multiple Precision Arithmetic Library](https://gmplib.org/) (GMP), which is used by [integer-gmp](https://hackage.haskell.org/package/integer-gmp) library to provide big integer implementation for Haskell. Contrary to the majority of Haskell code licensed under permissive BSD3 license, GMP library is licensed under LGPL, which means resulting binaries [have to be provided with source code or object files](http://www.gnu.org/licenses/gpl-faq.html#LGPLStaticVsDynamic). That may or may not be acceptable for your situation. Current workaround is to use GHC built with alternative big integer implementation called integer-simple, which is free from LGPL limitations as it's pure Haskell and does not use GMP. Unfortunately it has yet to be available out of the box with stack. See [issue #399](https://github.com/commercialhaskell/stack/issues/399) for the ongoing effort and information on workarounds.++#### How to get a working executable on Windows?++When executing a binary after building with `stack build` (e.g. for target "foo"), the command `foo.exe` might complain about missing runtime libraries (whereas `stack exec foo` works).++Windows is not able to find the necessary C++ libraries from the standard prompt because they're not in the PATH environment variable. `stack exec` works because it's modifying PATH to include extra things.++Those libraries are shipped with GHC (and, theoretically in some cases, MSYS). The easiest way to find them is `stack exec which`. E.g.++    >stack exec which libstdc++-6.dll+    /c/Users/Michael/AppData/Local/Programs/stack/i386-windows/ghc-7.8.4/mingw/bin/libstdc++-6.dll++A quick workaround is adding this path to the PATH environment variable or copying the files somewhere Windows finds them (cf. https://msdn.microsoft.com/de-de/library/7d83bc18.aspx).++Cf. issue [#425](https://github.com/commercialhaskell/stack/issues/425).++#### Can I change stack's default temporary directory?++Stack makes use of a temporary directory for some commands (/tmp by default on linux). If there is not enough free space in this directory, stack may fail (see issue [#429](https://github.com/commercialhaskell/stack/issues/429) ). For instance `stack setup` with a GHC installation requires roughly 1GB free.++A custom temporary directory can be forced:+* on Linux by setting the environment variable TMPDIR (eg `$ TMPDIR=path-to-tmp stack setup`)+* on Windows by setting one of the environment variable (given in priority order), TMP, TEMP, USERPROFILE++#### stack sometimes rebuilds based on flag changes when I wouldn't expect it to. How come?++stack tries to give you reproducibility whenever possible. In some cases, this means that you get a recompile when one may not seem necessary. The most common example is running something like this in a multi-package project:++    stack build --ghc-options -O0 && stack build --ghc-options -O0 one-of-the-packages++This may end up recompiling local dependencies of `one-of-the-packages` without optimizations on. Whether stack should or shouldn't do this depends on the needs of the user at the time, and unfortunately we can't make a solution that will make everyone happy in all cases. If you're curious for details, there's [a long discussion about it](https://github.com/commercialhaskell/stack/issues/382) on the issue tracker.++#### stack setup on a windows system only tells me to add certain paths to the PATH variable instead of doing it++If you are using a powershell session, it is easy to automate even that step:++    $env:Path = ( stack setup | %{ $_ -replace '[^ ]+ ', ''} ), $env:Path -join ";"++#### How do I reset / remove Stack (such as to to do a completely fresh build)?++The first thing to remove is project-specific `.stack-work` directory within the project's directory. Next, remove `~/.stack` directory overall. You may have errors if you remove the latter but leave the former. Removing Stack itself will relate to how it was installed, and if you used GHC installed outside of Stack, that would need to be removed separately.++#### How does stack handle parallel builds? What exactly does it run in parallel?++See [issue #644](https://github.com/commercialhaskell/stack/issues/644) for more details.++#### I get strange `ld` errors about recompiling with "-fPIC"++Some users (myself included!) have come across a linker errors (example below) that seem to be dependent on the local environment, i.e. the package may compile on a different machine. There is no known workaround (if you come across one please include details), however the issue has been reported to be [non-deterministic]+(https://github.com/commercialhaskell/stack/issues/614) in some cases. I've had success using the docker functionality to build the project on a machine that would not compile it otherwise.++```+tmp-0.1.0.0: build+Building tmp-0.1.0.0...+Preprocessing executable 'tmp' for tmp-0.1.0.0...+Linking dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp ...+/usr/bin/ld: dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp-tmp/Main.o: relocation R_X86_64_32S against `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC+dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp-tmp/Main.o: error adding symbols: Bad value+collect2: error: ld returned 1 exit status++--  While building package tmp-0.1.0.0 using:+      /home/philip/.stack/programs/x86_64-linux/ghc-7.10.1/bin/runghc-7.10.1 -package=Cabal-1.22.2.0 -clear-package-db -global-package-db /home/philip/tmp/Setup.hs --builddir=dist-stack/x86_64-linux/Cabal-1.22.2.0/ build+    Process exited with code: ExitFailure 1+```
+ doc/install_and_upgrade.md view
@@ -0,0 +1,186 @@+Distribution packages are available for [Ubuntu](#ubuntu), [Debian](#debian), [CentOS / Red Hat](#centos--red-hat), [Fedora](#fedora) and [Arch Linux](#arch-linux). Binaries for other operating systems are available on [the releases page](https://github.com/fpco/stack/releases). For the future, we have plans to support more OSes.++Binary packages are signed with this [signing key](SIGNING_KEY.md).++## Windows++*Note*: Due to specific Windows limitations, [some temporary workarounds](https://www.fpcomplete.com/blog/2015/08/stack-ghc-windows) may be required. It is strongly advised to set your `STACK_ROOT` environment variable similarly to your root (e.g., `set STACK_ROOT=c:\stack_root`) *before* running `stack`.++* Download [the latest release](https://github.com/commercialhaskell/stack/releases/latest). Note: while generally i386/32-bit GHC is better tested on Windows, there are reports that recent versions of Windows only work with the 64-bit version of stack (see [issue #393](https://github.com/commercialhaskell/stack/issues/393)).+* Unpack the archive and place `stack.exe` somewhere on your `%PATH%` (see [Path section below](#path)) and you can then run `stack` on the command line.+* Now you can run `stack` from the terminal.++NOTE: These executables have been built and tested on a Windows 7, 8.1, and 10 64-bit machines. They should run on older Windows installs as well, but have not been tested. If you do test, please edit and update this page to indicate as such.++## OS X++* Download [the latest release](https://github.com/commercialhaskell/stack/releases/latest)+* Extract the archive and place `stack` somewhere on your `$PATH` (see [Path section below](#path))+* Now you can run `stack` from the terminal.++We generally test on the current version of OS X, but stack is known to work on Mavericks as well, and may also work on older versions (YMMV).++## Ubuntu++*note*: for 32-bit, use the [generic Linux option](#linux)++1. Get the FP Complete key:++        wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/ubuntu/fpco.key | sudo apt-key add -++2. Add the appropriate source repository:++    * Ubuntu 15.10 (amd64):++            echo 'deb http://download.fpcomplete.com/ubuntu/wily stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++    * Ubuntu 15.04 (amd64):++            echo 'deb http://download.fpcomplete.com/ubuntu/vivid stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++    * Ubuntu 14.10 (amd64)++            echo 'deb http://download.fpcomplete.com/ubuntu/utopic stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++    * Ubuntu 14.04 (amd64)++            echo 'deb http://download.fpcomplete.com/ubuntu/trusty stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++    * Ubuntu 12.04 (amd64)++            echo 'deb http://download.fpcomplete.com/ubuntu/precise stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++3. Update apt and install++        sudo apt-get update && sudo apt-get install stack -y++## Debian++*note*: for 32-bit, use the [generic Linux option](#linux)++1. Get the FP Complete key:++        wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/debian/fpco.key | sudo apt-key add -++2. Add the appropriate source repository:++    * Debian 8 (amd64):++            echo 'deb http://download.fpcomplete.com/debian/jessie stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++    * Debian 7 (amd64)++            echo 'deb http://download.fpcomplete.com/debian/wheezy stable main'|sudo tee /etc/apt/sources.list.d/fpco.list++3. Update apt and install++        sudo apt-get update && sudo apt-get install stack -y++## CentOS / Red Hat / Amazon Linux++*note*: for 32-bit, use the [generic Linux option](#linux)++1. Add the appropriate source repository:++    * CentOS 7 / RHEL 7 (x86_64)++            curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/centos/7/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo++    * CentOS 6 / RHEL 6 (x86_64)++            curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/centos/6/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo++2. Install:++        sudo yum -y install stack++## Fedora++*note*: for 32-bit, you can use this [Fedora Copr repo](https://copr.fedoraproject.org/coprs/petersen/stack/) which can be enabled with:++        sudo dnf copr enable petersen/stack++1. Add the appropriate source repository:++    * Fedora 22 (x86_64)++            curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/fedora/22/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo++    * Fedora 21 (x86_64)++            curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/fedora/21/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo++2. Install:++    * Fedora 22+++            sudo dnf -y install stack++    * Fedora < 22++            sudo yum -y install stack++## Arch Linux++*note*: for 32-bit, use the [generic Linux option](#linux). (You will need to ensure libtinfo is installed, see below.)++stack can be found in the AUR:+  - [haskell-stack](https://aur.archlinux.org/packages/haskell-stack/) _latest stable version_+  - [haskell-stack-git](https://aur.archlinux.org/packages/haskell-stack-git/) _git version_++In order to install stack from Hackage or from source, you will need the [libtinfo](https://aur.archlinux.org/packages/libtinfo/) Arch Linux package installed.  If this package is not installed, stack will not be able to install GHC.  ++If you use the [ArchHaskell repository](https://wiki.archlinux.org/index.php/ArchHaskell), you can also get the `haskell-stack` package from there.++## NixOS++Users who follow the `nixos-unstable` channel or the Nixpkgs `master` branch can install the latest `stack` release into their profile by running:++         nix-env -f "<nixpkgs>" -iA haskellPackages.stack++Alternatively, the package can be built from source as follows.++1. Clone the git repo:++         git clone https://github.com/commercialhaskell/stack.git++2. Create a `shell.nix` file:++         cabal2nix --shell ./. --no-check --no-haddock > shell.nix++   Note that the tests fail on NixOS, so disable them with `--no-check`. Also, haddock currently doesn't work for stack, so `--no-haddock` disables it.++3. Install stack to your user profile:++         nix-env -i -f shell.nix++For more information on using Stack together with Nix, please see [the NixOS+manual section on+Stack](http://nixos.org/nixpkgs/manual/#using-stack-together-with-nix).++## Linux++(64-bit and 32-bit options available)++* Download [the latest release](https://github.com/commercialhaskell/stack/releases/latest).  Note: the `-gmp4` variants are for older distributions (such as CentOS 6.x) that only include libgmp4 (libgmp.so.3).+* Extract the archive and place `stack` somewhere on your `$PATH` (see [Path section below](#path))+* Now you can run `stack` from the terminal.++Tested on Fedora 20: make sure to install the following packages `sudo yum install perl make automake gcc gmp-devel`.+For Gentoo users, make sure to have the `ncurses` package with `USE=tinfo` (without it, stack will not be able to install GHC).++## Path++You can install stack by copying it anywhere on your PATH environment variable. We recommend installing in the same directory where stack itself will install executables (that way stack is able to upgrade itself!). On Windows, that directory is `%APPDATA%\local\bin`, e.g. "c:\Users\Michael\AppData\Roaming\local\bin". For other systems, use `$HOME/.local/bin`.++If you don't have that directory in your PATH, you may need to update your PATH (such as by editing .bashrc).++If you're curious about the choice of these paths, see [issue #153](https://github.com/commercialhaskell/stack/issues/153)++## Upgrade++There are essentially three different approaches to upgrade:++* If you're using a package manager (e.g., the Ubuntu debs listed above) and are happy with sticking with the officially released binaries, simply follow your normal package manager strategies for upgrading (e.g. `apt-get update && apt-get upgrade`).+* If you're not using a package manager but want to stick with the official binaries (such as on Windows or Mac), you'll need to manually follow the steps above to download the newest binaries from the release page and replace the old binary.+* The `stack` tool itself ships with an `upgrade` command, which will build `stack` from source and install it to the default install path (see the previous section). You can use `stack upgrade` to get the latest official release, and `stack upgrade --git` to install from Git and live on the bleeding edge. If you follow this, make sure that this directory is on your `PATH` and takes precedence over the system installed `stack`. For more information, see [this discussion](https://github.com/commercialhaskell/stack/issues/237#issuecomment-126793301).
+ doc/nonstandard_project_init.md view
@@ -0,0 +1,101 @@+# Introduction+The purpose of this page is to collect information about issues that arise when users either have an existing cabal project or another nonstandard setup such as a private hackage database. ++# Using a Cabal File+New users may be confused by the fact that you must add dependencies to the projects cabal file, even in the case when you have already listed the package in the `stack.yaml`. In most cases, dependencies for your project that are in the Stackage snapshot need *only* be added to the cabal file. stack makes heavy use of Cabal the library under the hood. In general, your stack packages should also end up being valid cabal-install packages.++## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/105++# Passing Flags to Cabal++Any build command, `bench`, `install`, `haddock`, `test`, etc. takes a `--flag` option which passes flags to cabal. Another way to do this is using the flags field in a `stack.yaml`, with the option to specify flags on a per project basis. ++As an example, in a `stack.yaml` for multi-package project with packages `foo`, `bar`, `baz`:++```+flags:+  foo:+    release: true+  bar:+    default: true+  baz:+    manual: true+```++It is also possible to pass the same flag to multiple packages, i.e. `stack build --flag *:necessary`++Currently one needs to list all of your modules that interpret flags in the `other-modules` section of a cabal file. `cabal-install` has a different behavior currently and doesn't require that the modules be listed. This may change in a future release. +++## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/191+  - https://github.com/commercialhaskell/stack/issues/417+  - https://github.com/commercialhaskell/stack/issues/335+  - https://github.com/commercialhaskell/stack/issues/301+  - https://github.com/commercialhaskell/stack/issues/365+  - https://github.com/commercialhaskell/stack/issues/105++# Selecting a Resolver++`stack init` or `stack new` will try to default to the current Haskell LTS present on `https://www.stackage.org/snapshots` if no snapshot has been previously used locally, and to the latest LTS snapshot locally used for a build otherwise. Using an incorrect resolver can cause a build to fail if the version of GHC it requires is not present.++In order to override the resolver entry at project initialization one can pass `--prefer-lts` or `--prefer-nightly`. These options will choose the latest LTS or nightly versions locally used.+Alternatively the `--resolver` option can be used with the name of any snapshots on Stackage, or with `lts` or `nightly` to select the latest versions, disregarding previously used ones. This is not the default so as to avoid unnecessary recompilation time.++:TODO: Document `--solver`++## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/468+  - https://github.com/commercialhaskell/stack/issues/464++# Using git Repositories+stack has support for packages that reside in remote git locations.++Example:++```+packages:+- '.'+- location:+    git: https://github.com/kolmodin/binary+    commit: 8debedd3fcb6525ac0d7de2dd49217dce2abc0d9+```++## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/254+  - https://github.com/commercialhaskell/stack/issues/199++# Private Hackage+Working with a private Hackage is currently supported in certain situations.+There exist special entries in `stack.yaml` that may help you. In a `stack.yaml` file, it is possible+to add lines for packages in your database referencing the sdist locations via an `http` entry, or to use a `Hackage` entry.++The recommended stack workflow is to use git submodules instead of a private Hackage. Either by using git submodules and listing the directories in the packages section of `stack.yaml`, or by adding the private dependencies as git URIs with a commit SHA to the `stack.yaml`. This has the large benefit of eliminating the need to manage a Hackage database and pointless version bumps.++For further information see [YAML configuration](yaml_configuration.md)++## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/445+  - https://github.com/commercialhaskell/stack/issues/565++# Custom Snapshots+Currently WIP?+## Issues Referenced+  - https://github.com/commercialhaskell/stack/issues/111+  - https://github.com/commercialhaskell/stack/issues/253+  - https://github.com/commercialhaskell/stack/issues/137++# Intra-package Targets+stack supports intra-package targets, similar to `cabal build COMPONENTS` for situations when you don't want to build every target inside your package. ++Example:+```+stack build stack:lib:stack+stack test stack:test:stack-integration-test+```++Note: this does require prefixing the component name with the package name.++## Issues referenced+  - https://github.com/commercialhaskell/stack/issues/201
+ doc/shell_autocompletion.md view
@@ -0,0 +1,35 @@+## Shell Autocompletion:++Note: if you installed a package for you Linux distribution, the bash completion+file was automatically installed (you may need the `bash-completion` package to+have it take effect).++The following adds support for shell tab completion for standard Stack arguments, although completion for filenames and executables etc. within stack is still lacking (see [issue 82](https://github.com/commercialhaskell/stack/issues/832)).++### for bash users++you need to run following command+```+eval "$(stack --bash-completion-script "$(which stack)")"+```+You can also add it to your `.bashrc` file if you want.++### for ZSH users:++documentation says:+> Zsh can handle bash completions functions. The latest development version of zsh has a function bashcompinit, that when run will allow zsh to read bash completion specifications and functions. This is documented in the zshcompsys man page. To use it all **you need to do is run bashcompinit at any time after compinit**. It will define complete and compgen functions corresponding to the bash builtins.++You must so:+  1. launch compinint+  2. launch bashcompinit+  3. eval stack bash completion script++```shell+autoload -U +X compinit && compinit+autoload -U +X bashcompinit && bashcompinit+eval "$(stack --bash-completion-script "$(which stack)")"+```++:information_source: If you already have quite a large zshrc, or if you use oh-my-zsh, **compinit** will probably already be loaded. If you have a blank zsh config, all of the 3 lines above are necessary.++:gem: tip: instead of running those 3 lines from your shell every time you want to use stack, you can add those 3 lines in your $HOME/.zshrc file
+ doc/yaml_configuration.md view
@@ -0,0 +1,348 @@+This page is intended to fully document all configuration options available in the stack.yaml file. Note that this page is likely to be both *incomplete* and sometimes *inaccurate*. If you see such cases, please update the page, and if you're not sure how, open an issue labeled "question".++The stack.yaml configuration options break down into [project specific](#project-config) options in:++- `<project dir>/stack.yaml`++and [non-project specific](#non-project-config) options in:++- `/etc/stack/config.yaml` -- for system global non-project default options+-  `~/.stack/config.yaml` -- for user non-project default options+- The project file itself may also contain non-project specific options++*Note:* When stack is invoked outside a stack project it will source project specific options from `~/.stack/global/stack.yaml`.  Options in this file will be ignored for a project with its own `<project dir>/stack.yaml`.++## Project config++Project specific options are only valid in the `stack.yaml` file local to a project, not in the user or global config files.++### packages++This lists all local packages. In the simplest usage, it will be a list of directories, e.g.:++```yaml+packages:+- dir1+- dir2+- dir3+```++However, it supports two other location types: an HTTP URL referring to a tarball that can be downloaded, and information on a Git repo to clone, together with this SHA1 commit. For example:++```yaml+packages:+- some-directory+- https://example.com/foo/bar/baz-0.0.2.tar.gz+- location:+    git: git@github.com:commercialhaskell/stack+    commit: 6a86ee32e5b869a877151f74064572225e1a0398+```++Note: it is highly recommended that you only use SHA1 values for a Git commit. Other values may work, but they are not officially supported, and may result in unexpected behavior (namely, stack will not automatically pull to update to new versions).++stack further allows you to tweak your packages by specifying two additional+settings:++* A list of subdirectories to build (useful for mega-repos like+[wai](https://github.com/yesodweb/wai/) or+[digestive-functors](https://github.com/jaspervdj/digestive-functors))+* Whether a package should be treated as a dependency: a package marked `extra-dep: true` will only be built if demanded by a non-dependency, and its test suites and benchmarks will not be run. This is useful for tweaking upstream packages.++To tie this all together, here's an example of the different settings:++```yaml+packages:+- local-package+- location: vendor/binary+  extra-dep: true+- location:+    git: git@github.com:yesodweb/wai+    commit: 2f8a8e1b771829f4a8a77c0111352ce45a14c30f+  subdirs:+  - auto-update+  - wai+```++### extra-deps++This is a list of package identifiers for additional packages from upstream to+be included. This is usually used to augment an LTS Haskell or Stackage Nightly+snapshot with a package that is not present or is at an older version than you+wish to use.++```yaml+extra-deps:+- acme-missiles-0.3+```++### resolver++Specifies how dependencies are resolved. There are currently four resolver types:++* LTS Haskell snapshots, e.g. `resolver: lts-2.14`+* Stackage Nightly snapshot, e.g. `resolver: nightly-2015-06-16`+* No snapshot, just use packages shipped with the compiler+    * For GHC this looks like `resolver: ghc-7.10.2`+    * For GHCJS this looks like `resolver: ghcjs-0.1.0_ghc-7.10.2`.+* [Custom snapshot](https://github.com/commercialhaskell/stack/wiki/Custom-Snapshot)++Each of these resolvers will also determine what constraints are placed on the compiler version. See the [compiler-check](#compiler-check) option for some additional control over compiler version.++### flags++Flags can be set for each package separately, e.g.++```yaml+flags:+  package-name:+    flag-name: true+```++Flags will only affect packages in your `packages` and `extra-deps` settings.+Packages that come from the snapshot global database or are not affected.++### image+The image settings are used for the creation of container images using `stack container image`, e.g.+```yaml+image:+  container:+    base: "fpco/stack-build"+    add:+      static: /data/static+```+`base` is the docker image that will be used to built upon. The `add` lines allow you to add additional directories to your image. You can also specify `entrypoints`. Your executables are placed in `/usr/local/bin`.++## Non-project config++Non-project config options may go in the global config (`/etc/stack/config.yaml`) or the user config (`~/.stack/config.yaml`).++### docker++See [Docker configuration](Docker#configuration).++### connection-count++Integer indicating how many simultaneous downloads are allowed to happen++Default: `8`++### hide-th-loading++Strip out the "Loading ..." lines from GHC build output, produced when using Template Haskell++Default: `true`++### latest-snapshot-url++URL providing a JSON with information on the latest LTS and Nightly snapshots, used for automatic project configuration.++Default: `https://www.stackage.org/download/snapshots.json`++### local-bin-path++Target directory for `stack install` and `stack build --copy-bins`.++Default: `~/.local/bin`++### package-indices++```yaml+package-indices:+- name: Hackage+  download-prefix: https://s3.amazonaws.com/hackage.fpcomplete.com/package/++  # at least one of the following must be present+  git: https://github.com/commercialhaskell/all-cabal-hashes.git+  http: https://s3.amazonaws.com/hackage.fpcomplete.com/00-index.tar.gz++  # optional fields, both default to false+  gpg-verify: false+  require-hashes: false+```++One thing you should be aware of: if you change the contents of package-version+combination by setting a different package index, this *can* have an effect on+other projects by installing into your shared snapshot database.++### system-ghc++Enables or disables using the GHC available on the PATH. Useful to disable if+you want to force stack to use its own installed GHC (via `stack setup`), in+cases where your system GHC my be incomplete for some reason. Default is `true`.++```yaml+# Turn off system GHC+system-ghc: false+```++### install-ghc++Whether or not to automatically install GHC when necessary. Default is `false`,+which means stack will prompt you to run `stack setup` as needed.++### skip-ghc-check++Should we skip the check to confirm that your system GHC version (on the PATH) matches what your project expects? Default is `false`.++### require-stack-version++Require a version of stack within the specified range+([cabal-style](https://www.haskell.org/cabal/users-guide/developing-packages.html#build-information))+to be used for this project. Example: `require-stack-version: "== 0.1.*"`++Default: `"-any"`++### arch/os++Set the architecture and operating system for GHC, build directories, etc. Values are those recognized by Cabal, e.g.:++    arch: i386, x86_64+    os: windows, linux++You likely only ever want to change the arch value. This can also be set via the command line.++### extra-include-dirs/extra-lib-dirs++A list of extra paths to be searched for header files and libraries, respectively. Paths should be absolute++```yaml+extra-include-dirs:+- /opt/foo/include+extra-lib-dirs:+- /opt/foo/lib+```++### compiler-check++(Since 0.1.4)++Specifies how the compiler version in the resolver is matched against concrete versions. Valid values:++* `match-minor`: make sure that the first three components match, but allow patch-level differences. For example< 7.8.4.1 and 7.8.4.2 would both match 7.8.4. This is useful to allow for custom patch levels of a compiler. This is the default+* `match-exact`: the entire version number must match precisely+* `newer-minor`: the third component can be increased, e.g. if your resolver is `ghc-7.10.1`, then 7.10.2 will also be allowed. This was the default up through stack 0.1.3++### ghc-options++(Since 0.1.4)++Allows specifying per-package and global GHC options:++```yaml+ghc-options:+    # All packages+    "*": -Wall+    some-package: -DSOME_CPP_FLAG+```++Caveat emptor: setting options like this will affect your snapshot packages,+which can lead to unpredictable behavior versus official Stackage snapshots.+This is in contrast to the `ghc-options` command line flag, which will only+affect local targets.++### ghc-variant++(Since 0.1.5)++Specify a variant binary distribution of GHC to use.  Known values:++* `standard`: This is the default, uses the standard GHC binary distribution+* `gmp4`: Use the "centos6" GHC bindist, for Linux systems with libgmp4 (aka+  `libgmp.so.3`), such as CentOS 6. This variant will be used automatically on such systems; you should not need to specify it in the configuration+* `integersimple`: Use a GHC bindist that uses+  [integer-simple instead of GMP](https://ghc.haskell.org/trac/ghc/wiki/ReplacingGMPNotes)+* any other value: Use a custom GHC bindist. You should specify+  [setup-info](#setup-info) so `stack setup` knows where to download it, or+  pass the `stack setup --ghc-bindist` argument on the command-line++### setup-info++(Since 0.1.5)++Allows overriding from where tools like GHC and msys2 (on Windows) are+downloaded. Most useful for specifying locations of custom GHC binary+distributions (for use with the [ghc-variant](#ghc-variant) option):++```yaml+setup-info:+  ghc:+    windows32-custom-foo:+      7.10.2:+        url: "https://example.com/ghc-7.10.2-i386-unknown-mingw32-foo.tar.xz"+```++### pvp-bounds++(Since 0.1.5)++When using the `sdist` and `upload` commands, this setting determines whether+the cabal file's dependencies should be modified to reflect PVP lower and upper+bounds. Values are `none` (unchanged), `upper` (add upper bounds), `lower` (add+lower bounds), and both (and upper and lower bounds). The algorithm it follows+is:++* If an upper or lower bound already exists on a dependency, it's left alone+* When adding a lower bound, we look at the current version specified by stack.yaml, and set it as the lower bound (e.g., `foo >= 1.2.3`)+* When adding an upper bound, we require less than the next major version (e.g., `foo < 1.3`)++```yaml+pvp-bounds: none+```++For more information, see [the announcement blog post](https://www.fpcomplete.com/blog/2015/09/stack-pvp).++### modify-code-page++(Since 0.1.6)++Modify the code page for UTF-8 output when running on Windows. Default behavior+is to modify.++```yaml+modify-code-page: false+```++### explicit-setup-deps++(Since 0.1.6)++Decide whether a custom `Setup.hs` script should be run with an explicit list+of dependencies based on the dependencies of the package itself, or simply+provided the global package database. This option is most often needed when+overriding packages in the global database, see [issue #1110](https://github.com/commercialhaskell/stack/issues/1110).++Setting the list explicitly can help when a Setup.hs depends on packages in the+local package database. For more information on that case, see [issue #897](https://github.com/commercialhaskell/stack/issues/897).++Note that in the future, this should all disappear once Cabal provides full+support for explicit Setup.hs dependencies.++```yaml+explicit-setup-deps:+    "*": true # change the default+    entropy: false # override the new default for one package+```++### rebuild-ghc-options++(Since 0.1.6)++Should we rebuild a package when its GHC options change? Before 0.1.6, this was a non-configurable true. However, in most cases, the flag is used to affect optimization levels and warning behavior, for which GHC itself doesn't actually recompile the modules anyway. Therefore, the new behavior is to not recompile on an options change, but this behavior can be changed back with the following:++```yaml+rebuild-ghc-options: true+```++### apply-ghc-options++(Since 0.1.6)++Which packages do ghc-options on the command line get applied to? Before 0.1.6, the default value was `targets`++```yaml+apply-ghc-options: locals # all local packages, the default+# apply-ghc-options: targets # all local packages that are targets+# apply-ghc-options: everything # applied even to snapshot and extra-deps+```++Note that `everything` is a slightly dangerous value, as it can break invariants about your snapshot database.
src/Options/Applicative/Builder/Extra.hs view
@@ -80,9 +80,9 @@ -- To actually show have that help appear, use 'execExtraHelp' before executing the main parser. extraHelpOption :: String -> String -> String -> Parser (a -> a) extraHelpOption progName fakeName helpName =-    infoOption (optDesc ++ ".") (long helpName <> hidden <> internal) <*>-    infoOption (optDesc ++ ".") (long fakeName <> help optDesc)-  where optDesc = concat ["Run '", takeBaseName progName, " --", helpName, "' for details"]+    infoOption (optDesc' ++ ".") (long helpName <> hidden <> internal) <*>+    infoOption (optDesc' ++ ".") (long fakeName <> help optDesc')+  where optDesc' = concat ["Run '", takeBaseName progName, " --", helpName, "' for details"]  -- | Display extra help if extea help option passed in arguments. -- Since optparse-applicative doesn't allow an arbirary IO action for an 'abortOption', this
src/Path/IO.hs view
@@ -33,7 +33,9 @@   ,createTree   ,dropRoot   ,parseCollapsedAbsFile-  ,parseCollapsedAbsDir)+  ,parseCollapsedAbsDir+  ,withCanonicalizedSystemTempDirectory+  ,withCanonicalizedTempDirectory)   where  import           Control.Exception hiding (catch)@@ -48,6 +50,7 @@ import qualified System.Directory as D import qualified System.FilePath as FP import           System.IO.Error+import           System.IO.Temp  data ResolveException     = ResolveDirFailed (Path Abs Dir) FilePath FilePath@@ -289,3 +292,18 @@ ignoreDoesNotExist :: MonadIO m => IO () -> m () ignoreDoesNotExist f =     liftIO $ catch f $ \e -> unless (isDoesNotExistError e) (throwIO e)++withCanonicalizedSystemTempDirectory :: (MonadMask m, MonadIO m)+    => String                -- ^ Directory name template.+    -> (Path Abs Dir -> m a) -- ^ Callback that can use the canonicalized directory+    -> m a+withCanonicalizedSystemTempDirectory template action =+  withSystemTempDirectory template (parseRelAsAbsDir >=> action)++withCanonicalizedTempDirectory :: (MonadMask m, MonadIO m)+    => FilePath              -- ^ Temp directory to create the directory in+    -> String                -- ^ Directory name template.+    -> (Path Abs Dir -> m a) -- ^ Callback that can use the canonicalized directory+    -> m a+withCanonicalizedTempDirectory targetDir template action =+  withTempDirectory targetDir template (parseRelAsAbsDir >=> action)
src/Stack/Build.hs view
@@ -16,7 +16,8 @@   (build   ,clean   ,withLoadPackage-  ,mkBaseConfigOpts)+  ,mkBaseConfigOpts+  ,queryBuildInfo)   where  import           Control.Monad@@ -25,11 +26,20 @@ import           Control.Monad.Logger import           Control.Monad.Reader (MonadReader, asks) import           Control.Monad.Trans.Resource+import           Data.Aeson (Value (Object, Array), (.=), object) import           Data.Function+import qualified Data.HashMap.Strict as HM import qualified Data.Map as Map import           Data.Map.Strict (Map) import           Data.Set (Set) import qualified Data.Set as Set+import           Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import           Data.Text.Encoding (decodeUtf8)+import           Data.Text.Read (decimal)+import qualified Data.Vector as V+import qualified Data.Yaml as Yaml import           Network.HTTP.Client.Conduit (HasHttpManager) import           Path import           Path.IO@@ -48,6 +58,11 @@ import           Stack.Types.Internal import           System.FileLock (FileLock, unlockFile) +#ifdef WINDOWS+import System.Win32.Console (setConsoleCP, setConsoleOutputCP, getConsoleCP, getConsoleOutputCP)+import qualified Control.Monad.Catch as Catch+#endif+ type M env m = (MonadIO m,MonadReader env m,HasHttpManager env,HasBuildConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,MonadMask m,HasLogLevel env,HasEnvConfig env,HasTerminal env)  -- | Build.@@ -60,7 +75,7 @@       -> Maybe FileLock       -> BuildOpts       -> m ()-build setLocalFiles mbuildLk bopts = do+build setLocalFiles mbuildLk bopts = fixCodePage' $ do     menv <- getMinimalEnvOverride      (_, mbp, locals, extraToBuild, sourceMap) <- loadSourceMap NeedTargets bopts@@ -122,12 +137,14 @@     localDBPath <- packageDatabaseLocal     snapInstallRoot <- installationRootDeps     localInstallRoot <- installationRootLocal+    packageExtraDBs <- packageDatabaseExtra     return BaseConfigOpts         { bcoSnapDB = snapDBPath         , bcoLocalDB = localDBPath         , bcoSnapInstallRoot = snapInstallRoot         , bcoLocalInstallRoot = localInstallRoot         , bcoBuildOpts = bopts+        , bcoExtraDBs = packageExtraDBs         }  -- | Provide a function for loading package information from the package index@@ -170,3 +187,97 @@     forM_         (Map.keys (envConfigPackages econfig))         (distDirFromDir >=> removeTreeIfExists)++-- | Set the code page for this process as necessary. Only applies to Windows.+-- See: https://github.com/commercialhaskell/stack/issues/738+fixCodePage :: (MonadIO m, MonadMask m, MonadLogger m) => m a -> m a+#ifdef WINDOWS+fixCodePage inner = do+    origCPI <- liftIO getConsoleCP+    origCPO <- liftIO getConsoleOutputCP++    let setInput = origCPI /= expected+        setOutput = origCPO /= expected+        fixInput+            | setInput = Catch.bracket_+                (liftIO $ do+                    setConsoleCP expected)+                (liftIO $ setConsoleCP origCPI)+            | otherwise = id+        fixOutput+            | setInput = Catch.bracket_+                (liftIO $ do+                    setConsoleOutputCP expected)+                (liftIO $ setConsoleOutputCP origCPO)+            | otherwise = id++    case (setInput, setOutput) of+        (False, False) -> return ()+        (True, True) -> warn ""+        (True, False) -> warn " input"+        (False, True) -> warn " output"++    fixInput $ fixOutput inner+  where+    expected = 65001 -- UTF-8+    warn typ = $logInfo $ T.concat+        [ "Setting"+        , typ+        , " codepage to UTF-8 (65001) to ensure correct output from GHC"+        ]+#else+fixCodePage = id+#endif++fixCodePage' :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env)+             => m a+             -> m a+fixCodePage' inner = do+    mcp <- asks $ configModifyCodePage . getConfig+    if mcp+        then fixCodePage inner+        else inner++-- | Query information about the build and print the result to stdout in YAML format.+queryBuildInfo :: M env m+               => [Text] -- ^ selectors+               -> m ()+queryBuildInfo selectors0 = do+        rawBuildInfo+    >>= select id selectors0+    >>= liftIO . TIO.putStrLn . decodeUtf8 . Yaml.encode+  where+    select _ [] value = return value+    select front (sel:sels) value =+        case value of+            Object o ->+                case HM.lookup sel o of+                    Nothing -> err "Selector not found"+                    Just value' -> cont value'+            Array v ->+                case decimal sel of+                    Right (i, "")+                        | i >= 0 && i < V.length v -> cont $ v V.! i+                        | otherwise -> err "Index out of range"+                    _ -> err "Encountered array and needed numeric selector"+            _ -> err $ "Cannot apply selector to " ++ show value+      where+        cont = select (front . (sel:)) sels+        err msg = error $ msg ++ ": " ++ show (front [sel])++-- | Get the raw build information object+rawBuildInfo :: M env m => m Value+rawBuildInfo = do+    (_, _mbp, locals, _extraToBuild, _sourceMap) <- loadSourceMap NeedTargets defaultBuildOpts+    return $ object+        [ "locals" .= Object (HM.fromList $ map localToPair locals)+        ]+  where+    localToPair lp =+        (T.pack $ packageNameString $ packageName p, value)+      where+        p = lpPackage lp+        value = object+            [ "version" .= packageVersion p+            , "path" .= toFilePath (lpDir lp)+            ]
src/Stack/Build/Cache.hs view
@@ -298,17 +298,36 @@ precompiledCacheFile :: (MonadThrow m, MonadReader env m, HasEnvConfig env)                      => PackageIdentifier                      -> ConfigureOpts+                     -> Set GhcPkgId -- ^ dependencies                      -> m (Path Abs File)-precompiledCacheFile pkgident copts = do+precompiledCacheFile pkgident copts installedPackageIDs = do     ec <- asks getEnvConfig -    compiler <- parseRelDir $ T.unpack $ compilerVersionName $ envConfigCompilerVersion ec+    compiler <- parseRelDir $ compilerVersionString $ envConfigCompilerVersion ec     cabal <- parseRelDir $ versionString $ envConfigCabalVersion ec     pkg <- parseRelDir $ packageIdentifierString pkgident +    -- In Cabal versions 1.22 and later, the configure options contain the+    -- installed package IDs, which is what we need for a unique hash.+    -- Unfortunately, earlier Cabals don't have the information, so we must+    -- supplement it with the installed package IDs directly. In 20/20+    -- hindsight, we would simply always do that, but previous Stack releases+    -- used only the options, and we don't want to invalidate old caches+    -- unnecessarily.+    --+    -- See issue: https://github.com/commercialhaskell/stack/issues/1103+    let cacheInput+            | envConfigCabalVersion ec >= $(mkVersion "1.22") =+                Binary.encode $ coNoDirs copts+            | otherwise =+                Binary.encode+                    ( coNoDirs copts+                    , installedPackageIDs+                    )+     -- We only pay attention to non-directory options. We don't want to avoid a     -- cache hit just because it was installed in a different directory.-    copts' <- parseRelFile $ S8.unpack $ B16.encode $ SHA256.hashlazy $ Binary.encode $ coNoDirs copts+    copts' <- parseRelFile $ S8.unpack $ B16.encode $ SHA256.hashlazy cacheInput      return $ getStackRoot ec          </> $(mkRelDir "precompiled")@@ -322,11 +341,12 @@                       => BaseConfigOpts                       -> PackageIdentifier                       -> ConfigureOpts+                      -> Set GhcPkgId -- ^ dependencies                       -> Maybe GhcPkgId -- ^ library                       -> Set Text -- ^ executables                       -> m ()-writePrecompiledCache baseConfigOpts pkgident copts mghcPkgId exes = do-    file <- precompiledCacheFile pkgident copts+writePrecompiledCache baseConfigOpts pkgident copts depIDs mghcPkgId exes = do+    file <- precompiledCacheFile pkgident copts depIDs     createTree $ parent file     mlibpath <-         case mghcPkgId of@@ -347,7 +367,8 @@ readPrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m)                      => PackageIdentifier -- ^ target package                      -> ConfigureOpts+                     -> Set GhcPkgId -- ^ dependencies                      -> m (Maybe PrecompiledCache)-readPrecompiledCache pkgident copts = do-    file <- precompiledCacheFile pkgident copts+readPrecompiledCache pkgident copts depIDs = do+    file <- precompiledCacheFile pkgident copts depIDs     decodeFileOrFailDeep $ toFilePath file
src/Stack/Build/ConstructPlan.hs view
@@ -33,7 +33,7 @@ import           Distribution.Package (Dependency (..)) import           Distribution.Version         (anyVersion) import           Network.HTTP.Client.Conduit (HasHttpManager)-import           Prelude hiding (FilePath, pi, writeFile)+import           Prelude hiding (pi, writeFile) import           Stack.Build.Cache import           Stack.Build.Haddock import           Stack.Build.Installed@@ -233,6 +233,7 @@                             (baseConfigOpts ctx)                             allDeps                             True -- wanted+                            True -- local                             Local                             package                 , taskPresent = present@@ -350,6 +351,7 @@                             (baseConfigOpts ctx)                             allDeps                             (psWanted ps)+                            (psLocal ps)                             -- An assertion to check for a recurrence of                             -- https://github.com/commercialhaskell/stack/issues/345                             (assert (destLoc == piiLocation ps) destLoc)@@ -373,12 +375,14 @@             | otherwise -> do                 tell mempty { wDirty = Map.singleton name $                     let t = T.intercalate ", " $ map (T.pack . packageNameString . packageIdentifierName) (Set.toList missing)-                     in T.append "missing dependencies: " $-                            if T.length t < 100-                                then t-                                else T.take 97 t <> "..." }+                     in T.append "missing dependencies: " $ addEllipsis t }                 return True +addEllipsis :: Text -> Text+addEllipsis t+    | T.length t < 100 = t+    | otherwise = T.take 97 t <> "..."+ addPackageDeps :: Bool -- ^ is this being used by a dependency?                -> Package -> M (Either ConstructPlanException (Set PackageIdentifier, Map PackageIdentifier GhcPkgId, InstallLocation)) addPackageDeps treatAsDep package = do@@ -427,6 +431,7 @@             (baseConfigOpts ctx)             present             (psWanted ps)+            (psLocal ps)             (piiLocation ps) -- should be Local always             package         buildOpts = bcoBuildOpts (baseConfigOpts ctx)@@ -446,19 +451,21 @@             case moldOpts of                 Nothing -> Just "old configure information not found"                 Just oldOpts-                    | Just reason <- describeConfigDiff oldOpts wantConfigCache -> Just reason-                    | psDirty ps -> Just "local file changes"+                    | Just reason <- describeConfigDiff config oldOpts wantConfigCache -> Just reason+                    | Just files <- psDirty ps -> Just $ "local file changes: " <>+                                                         addEllipsis (T.pack $ unwords $ Set.toList files)                     | otherwise -> Nothing+        config = getConfig ctx     case mreason of         Nothing -> return False         Just reason -> do             tell mempty { wDirty = Map.singleton (packageName package) reason }             return True -describeConfigDiff :: ConfigCache -> ConfigCache -> Maybe Text-describeConfigDiff old new+describeConfigDiff :: Config -> ConfigCache -> ConfigCache -> Maybe Text+describeConfigDiff config old new     | configCacheDeps old /= configCacheDeps new = Just "dependencies changed"-    | not $ Set.null newComponents =+    | not $ Set.null $ Set.filter isLibExe newComponents =         Just $ "components added: " `T.append` T.intercalate ", "             (map (decodeUtf8With lenientDecode) (Set.toList newComponents))     | not (configCacheHaddock old) && configCacheHaddock new = Just "rebuilding with haddocks"@@ -470,6 +477,11 @@         ]     | otherwise = Nothing   where+    isLibExe t = not $ any (`S8.isPrefixOf` t)+        [ "test:"+        , "bench:"+        ]+     -- options set by stack     isStackOpt t = any (`T.isPrefixOf` t)         [ "--dependency="@@ -481,7 +493,25 @@         , "--enable-benchmarks"         ] +    stripGhcOptions =+        go+      where+        go [] = []+        go ("--ghc-option":_:xs) = go xs+        go ("--ghc-options":_:xs) = go xs+        go (x:xs)+          | isPrefixed x = go xs+          | otherwise = x : go xs++        isPrefixed t = any (`T.isPrefixOf` t)+            [ "--ghc-option="+            , "--ghc-options="+            ]+     userOpts = filter (not . isStackOpt)+             . (if configRebuildGhcOptions config+                   then id+                   else stripGhcOptions)              . map T.pack              . (\(ConfigureOpts x y) -> x ++ y)              . configCacheOpts@@ -494,13 +524,17 @@      newComponents = configCacheComponents new `Set.difference` configCacheComponents old -psDirty :: PackageSource -> Bool+psDirty :: PackageSource -> Maybe (Set FilePath) psDirty (PSLocal lp) = lpDirtyFiles lp-psDirty (PSUpstream _ _ _) = False -- files never change in an upstream package+psDirty (PSUpstream _ _ _) = Nothing -- files never change in an upstream package  psWanted :: PackageSource -> Bool psWanted (PSLocal lp) = lpWanted lp psWanted (PSUpstream _ _ _) = False++psLocal :: PackageSource -> Bool+psLocal (PSLocal _) = True+psLocal (PSUpstream _ _ _) = False  psPackage :: PackageName -> PackageSource -> M Package psPackage _ (PSLocal lp) = return $ lpPackage lp
src/Stack/Build/Coverage.hs view
@@ -5,13 +5,15 @@ {-# LANGUAGE TemplateHaskell       #-} -- | Generate HPC (Haskell Program Coverage) reports module Stack.Build.Coverage-    ( generateHpcReport+    ( updateTixFile+    , generateHpcReport+    , generateHpcUnifiedReport     , generateHpcMarkupIndex     ) where  import           Control.Applicative import           Control.Exception.Lifted-import           Control.Monad                  (liftM)+import           Control.Monad                  (liftM, when, void) import           Control.Monad.Catch            (MonadCatch) import           Control.Monad.IO.Class import           Control.Monad.Logger@@ -30,6 +32,7 @@ import qualified Data.Text.IO                   as T import qualified Data.Text.Lazy                 as LT import           Data.Traversable               (forM)+import           Trace.Hpc.Tix import           Path import           Path.IO import           Prelude                        hiding (FilePath, writeFile)@@ -39,11 +42,35 @@ import           System.Process.Read import           Text.Hastache                  (htmlEscape) +-- | Move a tix file into a sub-directory of the hpc report directory.+-- Deletes the old one if one is present.+updateTixFile :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env)+            => Path Abs File -> String -> m ()+updateTixFile tixSrc pkgId = do+    exists <- fileExists tixSrc+    when exists $ do+        outputDir <- hpcReportDir+        pkgIdRel <- parseRelDir pkgId+        let tixDest = outputDir </> pkgIdRel </> filename tixSrc+        removeFileIfExists tixDest+        createTree (parent tixDest)+        renameFile tixSrc tixDest++-- | Get the tix file location, given the name of the file (without+-- extension), and the package identifier string.+tixFilePath ::  (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env)+            => String -> String ->  m (Path Abs File)+tixFilePath pkgId tixName = do+    outputDir <- hpcReportDir+    pkgIdRel <- parseRelDir pkgId+    tixRel <- parseRelFile (tixName ++ ".tix")+    return (outputDir </> pkgIdRel </> tixRel)+ -- | Generates the HTML coverage report and shows a textual coverage--- summary.+-- summary for a package. generateHpcReport :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env)-                  => Path Abs Dir -> Package -> [Text] -> (PackageName -> m (Maybe Text)) -> m ()-generateHpcReport pkgDir package tests getGhcPkgKey = do+                  => Package -> [Text] -> (PackageName -> m (Maybe Text)) -> m ()+generateHpcReport package tests getGhcPkgKey = do     -- If we're using > GHC 7.10, the hpc 'include' parameter must specify a     -- ghc package key. See     -- https://github.com/commercialhaskell/stack/issues/785@@ -59,67 +86,136 @@                     Nothing -> fail $ "Before computing test coverage report, failed to find GHC package key for " ++ T.unpack pkgName                     Just ghcPkgKey -> return $ T.unpack ghcPkgKey     forM_ tests $ \testName -> do-        let whichTest = pkgName <> "'s test-suite \"" <> testName <> "\""-        -- Compute destination directory.-        installDir <- installationRootLocal-        testNamePath <- parseRelDir (T.unpack testName)-        pkgIdPath <- parseRelDir pkgId-        let destDir = installDir </> hpcDirSuffix </> pkgIdPath </> testNamePath-        -- Directories for .mix files.-        hpcDir <- hpcDirFromDir pkgDir-        hpcRelDir <- (</> dotHpc) <$> hpcRelativeDir-        -- Compute arguments used for both "hpc markup" and "hpc report".-        pkgDirs <- Map.keys . envConfigPackages <$> asks getEnvConfig-        let args =-                -- Use index files from all packages (allows cross-package-                -- coverage results).-                concatMap (\x -> ["--srcdir", toFilePath x]) pkgDirs ++-                -- Look for index files in the correct dir (relative to-                -- each pkgdir).-                ["--hpcdir", toFilePath hpcRelDir, "--reset-hpcdirs"-                -- Restrict to just the current library code (see #634 --                -- this will likely be customizable in the future)-                ,"--include", includeName ++ ":"]-        -- If a .tix file exists, generate an HPC report for it.-        tixFile <- parseRelFile (T.unpack testName ++ ".tix")-        let tixFileAbs = hpcDir </> tixFile-        tixFileExists <- fileExists tixFileAbs-        if not tixFileExists-            then $logError $ T.concat-                [ "Didn't find .tix coverage file for "-                , whichTest-                , " - expected to find it at "-                , T.pack (toFilePath tixFileAbs)-                , "."-                ]-            else (`onException` $logError ("Error occurred while producing coverage report for " <> whichTest)) $ do-                menv <- getMinimalEnvOverride-                $logInfo $ "Generating HTML coverage report for " <> whichTest-                _ <- readProcessStdout (Just hpcDir) menv "hpc"-                    ("markup" : toFilePath tixFileAbs : ("--destdir=" ++ toFilePath destDir) : args)-                output <- readProcessStdout (Just hpcDir) menv "hpc"-                    ("report" : toFilePath tixFileAbs : args)-                -- Print output, stripping @\r@ characters because-                -- Windows.-                forM_ (S8.lines output) ($logInfo . T.decodeUtf8 . S8.filter (not . (=='\r')))-                $logInfo-                    ("The HTML coverage report for " <> whichTest <> " is available at " <>-                     T.pack (toFilePath (destDir </> $(mkRelFile "hpc_index.html"))))+        tixSrc <- tixFilePath pkgId (T.unpack testName)+        subdir <- parseRelDir (T.unpack testName)+        let report = "coverage report for " <> pkgName <> "'s test-suite \"" <> testName <> "\""+            -- Restrict to just the current library code (see #634 -+            -- this will likely be customizable in the future)+            extraArgs = ["--include", includeName ++ ":"]+        generateHpcReportInternal tixSrc subdir report extraArgs extraArgs +generateHpcReportInternal :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env)+                          => Path Abs File -> Path Rel Dir -> Text -> [String] -> [String] -> m ()+generateHpcReportInternal tixSrc subdir report extraMarkupArgs extraReportArgs = do+    -- If a .tix file exists, move it to the HPC output directory+    -- and generate a report for it.+    tixFileExists <- fileExists tixSrc+    if not tixFileExists+        then $logError $ T.concat+            [ "Didn't find .tix for "+            , report+            , " - expected to find it at "+            , T.pack (toFilePath tixSrc)+            , "."+            ]+        else (`onException` $logError ("Error occurred while producing " <> report)) $ do+            -- Directories for .mix files.+            hpcRelDir <- (</> dotHpc) <$> hpcRelativeDir+            -- Compute arguments used for both "hpc markup" and "hpc report".+            pkgDirs <- Map.keys . envConfigPackages <$> asks getEnvConfig+            let args =+                    -- Use index files from all packages (allows cross-package+                    -- coverage results).+                    concatMap (\x -> ["--srcdir", toFilePath x]) pkgDirs +++                    -- Look for index files in the correct dir (relative to+                    -- each pkgdir).+                    ["--hpcdir", toFilePath hpcRelDir, "--reset-hpcdirs"]+                reportDest = parent tixSrc </> subdir+            menv <- getMinimalEnvOverride+            $logInfo $ "Generating " <> report+            outputLines <- liftM S8.lines $ readProcessStdout Nothing menv "hpc"+                ( "report"+                : toFilePath tixSrc+                : (args ++ extraReportArgs)+                )+            if all ("(0/0)" `S8.isSuffixOf`) outputLines+                then $logError $ T.concat+                    [ "Error: The "+                    , report+                    , " did not consider any code. One possible cause of this is"+                    , " if your test-suite builds the library code (see stack"+                    , " issue #1008). It may also indicate a bug in stack or"+                    , " the hpc program. Please report this issue if you think"+                    , " your coverage report should have meaningful results."+                    ]+                else do+                    -- Print output, stripping @\r@ characters because+                    -- Windows.+                    forM_ outputLines ($logInfo . T.decodeUtf8 . S8.filter (not . (=='\r')))+                    $logInfo+                        ("The " <> report <> " is available at " <>+                         T.pack (toFilePath (reportDest </> $(mkRelFile "hpc_index.html"))))+            -- Generate the markup.+            void $ readProcessStdout Nothing menv "hpc"+                ( "markup"+                : toFilePath tixSrc+                : ("--destdir=" ++ toFilePath reportDest)+                : (args ++ extraMarkupArgs)+                )++generateHpcUnifiedReport :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env)+                     => m ()+generateHpcUnifiedReport = do+    outputDir <- hpcReportDir+    createTree outputDir+    (dirs, _) <- listDirectory outputDir+    tixFiles <- liftM concat $ forM dirs $ \dir -> do+        (_, files) <- listDirectory dir+        return (filter ((".tix" `isSuffixOf`) . toFilePath) files)+    if length tixFiles < 2+        then $logInfo $ T.concat $+            [ if null tixFiles then "No tix files" else "Only one tix file"+            , " found in "+            , T.pack (toFilePath outputDir)+            , ", so not generating a unified coverage report."+            ]+        else do+            tixes <- mapM (liftM (fmap removeExeModules) . readTixOrLog) tixFiles+            let (errs, tix) = unionTixes (catMaybes tixes)+            when (not (null errs)) $ $logWarn $ T.concat $+                "The following modules are left out of the unified report due to version mismatches: " :+                intersperse ", " (map T.pack errs)+            let tixDest = outputDir </> $(mkRelFile "unified/unified.tix")+            createTree (parent tixDest)+            liftIO $ writeTix (toFilePath tixDest) tix+            generateHpcReportInternal tixDest $(mkRelDir "unified") "unified report" [] []++readTixOrLog :: (MonadLogger m, MonadIO m) => Path b File -> m (Maybe Tix)+readTixOrLog path = do+    mtix <- liftIO $ readTix (toFilePath path)+    when (isNothing mtix) $+        $logError $ "Failed to read tix file " <> T.pack (toFilePath path)+    return mtix++-- | Module names which contain '/' have a package name, and so they+-- weren't built into the executable.+removeExeModules :: Tix -> Tix+removeExeModules (Tix ms) = Tix (filter (\(TixModule name _ _ _) -> '/' `elem` name) ms)++unionTixes :: [Tix] -> ([String], Tix)+unionTixes tixes = (Map.keys errs, Tix (Map.elems outputs))+  where+    (errs, outputs) = Map.mapEither id $ Map.unionsWith merge $ map toMap tixes+    toMap (Tix ms) = Map.fromList (map (\x@(TixModule k _ _ _) -> (k, Right x)) ms)+    merge (Right (TixModule k hash1 len1 tix1))+          (Right (TixModule _ hash2 len2 tix2))+        | hash1 == hash2 && len1 == len2 = Right (TixModule k hash1 len1 (zipWith (+) tix1 tix2))+    merge _ _ = Left ()+ generateHpcMarkupIndex :: (MonadIO m,MonadReader env m,MonadLogger m,MonadCatch m,HasEnvConfig env)                        => m () generateHpcMarkupIndex = do-    installDir <- installationRootLocal-    let markupDir = installDir </> hpcDirSuffix-        outputFile = markupDir </> $(mkRelFile "index.html")-    (dirs, _) <- listDirectory markupDir+    outputDir <- hpcReportDir+    let outputFile = outputDir </> $(mkRelFile "index.html")+    createTree outputDir+    (dirs, _) <- listDirectory outputDir     rows <- liftM (catMaybes . concat) $ forM dirs $ \dir -> do         (subdirs, _) <- listDirectory dir         forM subdirs $ \subdir -> do             let indexPath = subdir </> $(mkRelFile "hpc_index.html")-            exists <- fileExists indexPath-            if not exists then return Nothing else do-                relPath <- stripDir markupDir indexPath+            exists' <- fileExists indexPath+            if not exists' then return Nothing else do+                relPath <- stripDir outputDir indexPath                 let package = dirname dir                     testsuite = dirname subdir                 return $ Just $ T.concat@@ -145,7 +241,7 @@         (if null rows             then                 [ "<b>No hpc_index.html files found in \""-                , pathToHtml markupDir+                , pathToHtml outputDir                 , "\".</b>"                 ]             else
src/Stack/Build/Execute.hs view
@@ -81,8 +81,6 @@ import           System.Exit                    (ExitCode (ExitSuccess)) import qualified System.FilePath                as FP import           System.IO-import           System.IO.Temp                 (withSystemTempDirectory)- import           System.PosixCompat.Files       (createLink) import           System.Process.Read import           System.Process.Run@@ -226,8 +224,7 @@             , "-"             , Distribution.Text.display $ configPlatform config             , "-"-            , T.unpack $ compilerVersionName-                       $ envConfigCompilerVersion econfig+            , compilerVersionString $ envConfigCompilerVersion econfig             ]         exeNameS = baseNameS ++             case configPlatform config of@@ -286,14 +283,13 @@                -> (ExecuteEnv -> m a)                -> m a withExecuteEnv menv bopts baseConfigOpts locals globals sourceMap inner = do-    withSystemTempDirectory stackProgName $ \tmpdir -> do-        tmpdir' <- parseAbsDir tmpdir+    withCanonicalizedSystemTempDirectory stackProgName $ \tmpdir -> do         configLock <- newMVar ()         installLock <- newMVar ()         idMap <- liftIO $ newTVarIO Map.empty-        let setupHs = tmpdir' </> $(mkRelFile "Setup.hs")+        let setupHs = tmpdir </> $(mkRelFile "Setup.hs")         liftIO $ writeFile (toFilePath setupHs) "import Distribution.Simple\nmain = defaultMain"-        setupExe <- getSetupExe setupHs tmpdir'+        setupExe <- getSetupExe setupHs tmpdir         cabalPkgVer <- asks (envConfigCabalVersion . getEnvConfig)         globalDB <- getGlobalDB menv =<< getWhichCompiler         inner ExecuteEnv@@ -307,7 +303,7 @@             , eeInstallLock = installLock             , eeBaseConfigOpts = baseConfigOpts             , eeGhcPkgIds = idMap-            , eeTempDir = tmpdir'+            , eeTempDir = tmpdir             , eeSetupHs = setupHs             , eeSetupExe = setupExe             , eeCabalPkgVer = cabalPkgVer@@ -491,7 +487,9 @@         generateLocalHaddockIndex eeEnvOverride wc eeBaseConfigOpts eeLocals         generateDepsHaddockIndex eeEnvOverride wc eeBaseConfigOpts eeLocals         generateSnapHaddockIndex eeEnvOverride wc eeBaseConfigOpts eeGlobalDB-    when (toCoverage $ boptsTestOpts eeBuildOpts) generateHpcMarkupIndex+    when (toCoverage $ boptsTestOpts eeBuildOpts) $ do+        generateHpcUnifiedReport+        generateHpcMarkupIndex   where     installedMap' = Map.difference installedMap                   $ Map.fromList@@ -601,7 +599,19 @@     when needConfig $ withMVar eeConfigureLock $ \_ -> do         deleteCaches pkgDir         announce-        cabal False $ "configure" : dirs ++ nodirs+        menv <- getMinimalEnvOverride+        let programNames =+                if eeCabalPkgVer < $(mkVersion "1.22") then ["ghc"] else ["ghc", "ghcjs"]+        exes <- forM programNames $ \name -> do+            mpath <- findExecutable menv name+            return $ case mpath of+                Nothing -> []+                Just x -> return $ concat ["--with-", name, "=", toFilePath x]+        cabal False $ "configure" : concat+            [ concat exes+            , dirs+            , nodirs+            ]         writeConfigCache pkgDir newConfigCache         writeCabalMod pkgDir newCabalMod @@ -684,7 +694,7 @@             , esStackExe = False             , esLocaleUtf8 = True             }-        getRunhaskellPath <- runOnce $ liftIO $ join $ findExecutable menv "runhaskell"+        getGhcPath <- runOnce $ liftIO $ join $ findExecutable menv "ghc"         getGhcjsPath <- runOnce $ liftIO $ join $ findExecutable menv "ghcjs"         distRelativeDir' <- distRelativeDir         esetupexehs <-@@ -701,7 +711,7 @@                                                           eeCabalPkgVer)                 packageArgs =                     case mdeps of-                        Just deps ->+                        Just deps | explicitSetupDeps (packageName package) config ->                             -- Stack always builds with the global Cabal for various                             -- reproducibility issues.                             let depsMinusCabal@@ -709,13 +719,16 @@                                  $ Set.toList                                  $ addGlobalPackages deps eeGlobalPackages                             in-                              "-clear-package-db"-                            : "-global-package-db"-                            : ("-package-db=" ++ toFilePath (bcoSnapDB eeBaseConfigOpts))-                            : ("-package-db=" ++ toFilePath (bcoLocalDB eeBaseConfigOpts))-                            : "-hide-all-packages"-                            : cabalPackageArg-                            : map ("-package-id=" ++) depsMinusCabal+                                ( "-clear-package-db"+                                : "-global-package-db"+                                : map (("-package-db=" ++) . toFilePath) (bcoExtraDBs eeBaseConfigOpts)+                                ) +++                                ( ("-package-db=" ++ toFilePath (bcoSnapDB eeBaseConfigOpts))+                                : ("-package-db=" ++ toFilePath (bcoLocalDB eeBaseConfigOpts))+                                : "-hide-all-packages"+                                : cabalPackageArg+                                : map ("-package-id=" ++) depsMinusCabal+                                )                         -- This branch is debatable. It adds access to the                         -- snapshot package database for Cabal. There are two                         -- possible objections:@@ -727,13 +740,15 @@                         -- 2. This doesn't provide enough packages: we should also                         -- include the local database when building local packages.                         ---                        -- Currently, this branch is only taken via `stack sdist`.-                        Nothing ->-                            [ cabalPackageArg-                            , "-clear-package-db"-                            , "-global-package-db"-                            , "-package-db=" ++ toFilePath (bcoSnapDB eeBaseConfigOpts)-                            ]+                        -- Currently, this branch is only taken via `stack+                        -- sdist` or when explicitly requested in the+                        -- stack.yaml file.+                        _ ->+                              cabalPackageArg+                            : "-clear-package-db"+                            : "-global-package-db"+                            : map (("-package-db=" ++) . toFilePath) (bcoExtraDBs eeBaseConfigOpts)+                           ++ ["-package-db=" ++ toFilePath (bcoSnapDB eeBaseConfigOpts)]                  setupArgs = ("--builddir=" ++ toFilePath distRelativeDir') : args                 runExe exeName fullArgs = do@@ -793,17 +808,16 @@             wc <- getWhichCompiler             (exeName, fullArgs) <- case (esetupexehs, wc) of                 (Left setupExe, _) -> return (setupExe, setupArgs)-                (Right setuphs, Ghc) -> do-                    exeName <- getRunhaskellPath-                    let fullArgs = packageArgs ++ (toFilePath setuphs : setupArgs)-                    return (exeName, fullArgs)-                (Right setuphs, Ghcjs) -> do+                (Right setuphs, compiler) -> do                     distDir <- distDirFromDir pkgDir                     let setupDir = distDir </> $(mkRelDir "setup")                         outputFile = setupDir </> $(mkRelFile "setup")                     createTree setupDir-                    ghcjsPath <- getGhcjsPath-                    runExe ghcjsPath $+                    compilerPath <-+                        case compiler of+                            Ghc -> getGhcPath+                            Ghcjs -> getGhcjsPath+                    runExe compilerPath $                         [ "--make"                         , "-odir", toFilePath setupDir                         , "-hidir", toFilePath setupDir@@ -811,8 +825,10 @@                         ] ++ packageArgs ++                         [ toFilePath setuphs                         , "-o", toFilePath outputFile-                        , "-build-runner"-                        ]+                        ] +++                        (case compiler of+                            Ghc -> []+                            Ghcjs -> ["-build-runner"])                     return (outputFile, setupArgs)             runExe exeName $ (if boptsCabalVerbose eeBuildOpts then ("--verbose":) else id) fullArgs @@ -869,7 +885,9 @@     getPrecompiled cache =         case taskLocation task of             Snap | not shouldHaddockPackage' -> do-                mpc <- readPrecompiledCache taskProvides $ configCacheOpts cache+                mpc <- readPrecompiledCache taskProvides+                    (configCacheOpts cache)+                    (configCacheDeps cache)                 case mpc of                     Nothing -> return Nothing                     Just pc -> do@@ -885,11 +903,18 @@         announceTask task "copying precompiled package"         forM_ mlib $ \libpath -> do             menv <- getMinimalEnvOverride-            withMVar eeInstallLock $ \() ->-                readProcessNull Nothing menv "ghc-pkg"+            withMVar eeInstallLock $ \() -> do+                -- We want to ignore the global and user databases.+                -- Unfortunately, ghc-pkg doesn't take such arguments on the+                -- command line. Instead, we'll set GHC_PACKAGE_PATH. See:+                -- https://github.com/commercialhaskell/stack/issues/1146++                menv' <- modifyEnvOverride menv+                       $ Map.insert+                            "GHC_PACKAGE_PATH"+                            (T.pack $ toFilePath $ bcoSnapDB eeBaseConfigOpts)+                readProcessNull Nothing menv' "ghc-pkg"                     [ "register"-                    , "--no-user-package-db"-                    , "--package-db=" ++ toFilePath (bcoSnapDB eeBaseConfigOpts)                     , "--force"                     , libpath                     ]@@ -897,6 +922,9 @@             D.createDirectoryIfMissing True bindir             let dst = bindir FP.</> FP.takeFileName exe             createLink exe dst `catchIO` \_ -> D.copyFile exe dst+        case (mlib, exes) of+            (Nothing, _:_) -> markExeInstalled (taskLocation task) taskProvides+            _ -> return ()          -- Find the package in the database         wc <- getWhichCompiler@@ -965,13 +993,21 @@          when (doHaddock package) $ do             announce "haddock"-            hscolourExists <- doesExecutableExist eeEnvOverride "HsColour"-            unless hscolourExists $ $logWarn-                ("Warning: haddock not generating hyperlinked sources because 'HsColour' not\n" <>-                 "found on PATH (use 'stack install hscolour' to install).")+            sourceFlag <- do+                hyped <- tryProcessStdout Nothing eeEnvOverride "haddock" ["--hyperlinked-source"]+                case hyped of+                    -- Fancy crosslinked source+                    Right _ -> do+                        return ["--haddock-option=--hyperlinked-source"]+                    -- Older hscolour colouring+                    Left _  -> do+                        hscolourExists <- doesExecutableExist eeEnvOverride "HsColour"+                        unless hscolourExists $ $logWarn+                            ("Warning: haddock not generating hyperlinked sources because 'HsColour' not\n" <>+                             "found on PATH (use 'stack install hscolour' to install).")+                        return ["--hyperlink-source" | hscolourExists]             cabal False (concat [["haddock", "--html", "--hoogle", "--html-location=../$pkg-$version/"]-                                ,["--hyperlink-source" | hscolourExists]-                                ,["--ghcjs" | wc == Ghcjs]])+                                ,sourceFlag])          withMVar eeInstallLock $ \() -> do             announce "install"@@ -1004,7 +1040,10 @@                     Set.empty          case taskLocation task of-            Snap -> writePrecompiledCache eeBaseConfigOpts taskProvides (configCacheOpts cache) mpkgid (packageExes package)+            Snap -> writePrecompiledCache eeBaseConfigOpts taskProvides+                (configCacheOpts cache)+                (configCacheDeps cache)+                mpkgid (packageExes package)             Local -> return ()          return mpkgid'@@ -1043,7 +1082,10 @@          let needBuild = neededConfig ||                 (case taskType task of-                    TTLocal lp -> lpDirtyFiles lp+                    TTLocal lp ->+                        case lpDirtyFiles lp of+                            Just _ -> True+                            Nothing -> False                     _ -> assert False True) ||                 not testBuilt @@ -1133,10 +1175,11 @@                         (Just inH, Nothing, Nothing, ph) <- liftIO $ createProcess_ "singleBuild.runTests" cp                         liftIO $ hClose inH                         ec <- liftIO $ waitForProcess ph-                        -- Move the .tix file out of the package directory-                        -- into the hpc work dir, for tidiness.+                        -- Move the .tix file out of the package+                        -- directory into the hpc work dir, for+                        -- tidiness.                         when needHpc $-                            moveFileIfExists nameTix hpcDir+                            updateTixFile nameTix (packageIdentifierString (packageIdentifier package))                         return $ case ec of                             ExitSuccess -> Map.empty                             _ -> Map.singleton testName $ Just ec@@ -1155,7 +1198,7 @@                         [ bcoSnapDB (eeBaseConfigOpts ee)                         , bcoLocalDB (eeBaseConfigOpts ee)                         ]-                generateHpcReport pkgDir package testsToRun (findGhcPkgKey (eeEnvOverride ee) wc pkgDbs)+                generateHpcReport package testsToRun (findGhcPkgKey (eeEnvOverride ee) wc pkgDbs)              bs <- liftIO $                 case mlogFile of@@ -1196,7 +1239,10 @@          let needBuild = neededConfig ||                 (case taskType task of-                    TTLocal lp -> lpDirtyFiles lp+                    TTLocal lp ->+                        case lpDirtyFiles lp of+                            Just _ -> True+                            Nothing -> False                     _ -> assert False True) ||                 not benchBuilt         when needBuild $ do
src/Stack/Build/Installed.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell       #-} -- Determine which packages are already installed module Stack.Build.Installed@@ -47,8 +48,6 @@     }     deriving Show -type InstalledMap = Map PackageName (Version, InstallLocation, Installed) -- TODO Version is now redundant and can be gleaned from Installed- -- | Options for 'getInstalled'. data GetInstalledOpts = GetInstalledOpts     { getInstalledProfiling :: !Bool@@ -69,6 +68,7 @@ getInstalled menv opts sourceMap = do     snapDBPath <- packageDatabaseDeps     localDBPath <- packageDatabaseLocal+    extraDBPaths <- packageDatabaseExtra      bconfig <- asks getBuildConfig @@ -78,12 +78,17 @@             else return Nothing      let loadDatabase' = loadDatabase menv opts mcache sourceMap+     (installedLibs0, globalInstalled) <- loadDatabase' Nothing []-    (installedLibs1, _snapInstalled) <--        loadDatabase' (Just (Snap, snapDBPath)) installedLibs0-    (installedLibs2, localInstalled) <--        loadDatabase' (Just (Local, localDBPath)) installedLibs1-    let installedLibs = M.fromList $ map lhPair installedLibs2+    (installedLibs1, _extraInstalled) <-+      (foldM (\lhs' pkgdb -> do+        lhs'' <- loadDatabase' (Just (ExtraGlobal, pkgdb)) (fst lhs')+        return lhs'') ((installedLibs0, globalInstalled)) extraDBPaths)+    (installedLibs2, _snapInstalled) <-+        loadDatabase' (Just (InstalledTo Snap, snapDBPath)) installedLibs1+    (installedLibs3, localInstalled) <-+        loadDatabase' (Just (InstalledTo Local, localDBPath)) installedLibs2+    let installedLibs = M.fromList $ map lhPair installedLibs3      case mcache of         Nothing -> return ()@@ -126,13 +131,14 @@              -> GetInstalledOpts              -> Maybe InstalledCache -- ^ if Just, profiling or haddock is required              -> Map PackageName pii -- ^ to determine which installed things we should include-             -> Maybe (InstallLocation, Path Abs Dir) -- ^ package database, Nothing for global+             -> Maybe (InstalledPackageLocation, Path Abs Dir) -- ^ package database, Nothing for global              -> [LoadHelper] -- ^ from parent databases              -> m ([LoadHelper], [DumpPackage () ()]) loadDatabase menv opts mcache sourceMap mdb lhs0 = do     wc <- getWhichCompiler-    (lhs1, dps) <- ghcPkgDump menv wc (fmap snd mdb)-                  $ conduitDumpPackage =$ sink+    (lhs1, dps) <- ghcPkgDump menv wc (fmap snd (maybeToList mdb))+                $ conduitDumpPackage =$ sink+     let lhs = pruneDeps             id             lhId@@ -168,7 +174,7 @@           => GetInstalledOpts           -> Maybe InstalledCache           -> Map PackageName pii-          -> Maybe InstallLocation+          -> Maybe InstalledPackageLocation           -> DumpPackage Bool Bool           -> Maybe LoadHelper isAllowed opts mcache sourceMap mloc dp@@ -188,10 +194,15 @@             if name `HashSet.member` wiredInPackages                 then []                 else dpDepends dp-        , lhPair = (name, (version, fromMaybe Snap mloc, Library ident gid))+        , lhPair = (name, (version, toPackageLocation mloc, Library ident gid))         }     | otherwise = Nothing   where+    toPackageLocation :: Maybe InstalledPackageLocation -> InstallLocation+    toPackageLocation Nothing = Snap+    toPackageLocation (Just ExtraGlobal) = Snap+    toPackageLocation (Just (InstalledTo loc)) = loc+     toInclude =         case Map.lookup name sourceMap of             Nothing ->@@ -199,6 +210,7 @@                     -- The sourceMap has nothing to say about this global                     -- package, so we can use it                     Nothing -> True+                    Just ExtraGlobal -> True                     -- For non-global packages, don't include unknown packages.                     -- See:                     -- https://github.com/commercialhaskell/stack/issues/292@@ -210,8 +222,8 @@      -- Ensure that the installed location matches where the sourceMap says it     -- should be installed-    checkLocation Snap = mloc /= Just Local -- we can allow either global or snap-    checkLocation Local = mloc == Just Local+    checkLocation Snap = mloc /= Just (InstalledTo Local) -- we can allow either global or snap+    checkLocation Local = mloc == Just (InstalledTo Local) || mloc == Just ExtraGlobal -- 'locally' installed snapshot packages can come from extra dbs      gid = dpGhcPkgId dp     ident@(PackageIdentifier name version) = dpPackageIdent dp
src/Stack/Build/Source.hs view
@@ -80,7 +80,6 @@     bconfig <- asks getBuildConfig     rawLocals <- getLocalPackageViews     (mbp0, cliExtraDeps, targets) <- parseTargetsFromBuildOpts needTargets bopts-     menv <- getMinimalEnvOverride     caches <- getPackageCaches menv     let latestVersion = Map.fromListWith max $ map toTuple $ Map.keys caches@@ -181,6 +180,7 @@     flagExtraDeps <- convertSnapshotToExtra         snapshot         (bcExtraDeps bconfig)+        rawLocals         (catMaybes $ Map.keys $ boptsFlags bopts)      (cliExtraDeps, targets) <-@@ -200,14 +200,16 @@     :: MonadLogger m     => Map PackageName Version -- ^ snapshot     -> Map PackageName Version -- ^ extra-deps+    -> Map PackageName a -- ^ locals     -> [PackageName] -- ^ packages referenced by a flag     -> m (Map PackageName Version)-convertSnapshotToExtra snapshot extra0 flags0 =+convertSnapshotToExtra snapshot extra0 locals flags0 =     go Map.empty flags0   where     go !extra [] = return extra     go extra (flag:flags)         | Just _ <- Map.lookup flag extra0 = go extra flags+        | flag `Map.member` locals = go extra flags         | otherwise = case Map.lookup flag snapshot of             Nothing -> go extra flags             Just version -> do@@ -336,7 +338,7 @@         benchpkg = resolvePackage benchconfig gpkg     mbuildCache <- tryGetBuildCache $ lpvRoot lpv     (files,_) <- getPackageFilesSimple pkg (lpvCabalFP lpv)-    (isDirty, newBuildCache) <- checkBuildCache+    (dirtyFiles, newBuildCache) <- checkBuildCache         (fromMaybe Map.empty mbuildCache)         (map toFilePath $ Set.toList files) @@ -350,7 +352,14 @@                 Just _ -> Just exes         , lpTestBench = btpkg         , lpFiles = files-        , lpDirtyFiles = isDirty || boptsForceDirty bopts+        , lpDirtyFiles =+            if not (Set.null dirtyFiles) || boptsForceDirty bopts+                then let tryStripPrefix y =+                            case stripPrefix (toFilePath $ lpvRoot lpv) y of+                                Nothing -> y+                                Just z -> z+                      in Just $ Set.map tryStripPrefix dirtyFiles+                else Nothing         , lpNewBuildCache = newBuildCache         , lpCabalFile = lpvCabalFP lpv         , lpDir = lpvRoot lpv@@ -453,15 +462,15 @@ checkBuildCache :: MonadIO m                 => Map FilePath FileCacheInfo -- ^ old cache                 -> [FilePath] -- ^ files in package-                -> m (Bool, Map FilePath FileCacheInfo)+                -> m (Set FilePath, Map FilePath FileCacheInfo) checkBuildCache oldCache files = liftIO $ do-    (Any isDirty, m) <- fmap mconcat $ mapM go files-    return (isDirty, m)+    (dirtyFiles, m) <- fmap mconcat $ mapM go files+    return (dirtyFiles, m)   where     go fp = do         mmodTime <- getModTimeMaybe fp         case mmodTime of-            Nothing -> return (Any False, Map.empty)+            Nothing -> return (Set.empty, Map.empty)             Just modTime' -> do                 (isDirty, newFci) <-                     case Map.lookup fp oldCache of@@ -476,7 +485,7 @@                         Nothing -> do                             newFci <- calcFci modTime' fp                             return (True, newFci)-                return (Any isDirty, Map.singleton fp newFci)+                return (if isDirty then Set.singleton fp else Set.empty, Map.singleton fp newFci)  -- | Returns entries to add to the build cache for any newly found unlisted modules addUnlistedToBuildCache
src/Stack/Build/Target.hs view
@@ -275,7 +275,7 @@  parseTargets :: (MonadThrow m, MonadIO m)              => NeedTargets -- ^ need at least one target-             -> Bool -- ^ using implicit global?+             -> Bool -- ^ using implicit global project?              -> Map PackageName Version -- ^ snapshot              -> Map PackageName Version -- ^ extra deps              -> Map PackageName LocalPackageView
src/Stack/Config.hs view
@@ -26,6 +26,8 @@   ,loadMiniConfig   ,packagesParser   ,resolvePackageEntry+  ,getImplicitGlobalProjectDir+  ,getIsGMP4   ) where  import qualified Codec.Archive.Tar as Tar@@ -41,6 +43,7 @@ import           Control.Monad.Trans.Control (MonadBaseControl) import qualified Crypto.Hash.SHA256 as SHA256 import           Data.Aeson.Extended+import qualified Data.ByteString as S import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Lazy as L import qualified Data.IntMap as IntMap@@ -64,7 +67,7 @@ import           Safe (headMay) import           Stack.BuildPlan import           Stack.Constants-import qualified Stack.Docker as Docker+import           Stack.Config.Docker import qualified Stack.Image as Image import           Stack.Init import           Stack.Types@@ -89,20 +92,16 @@                 Just lts -> lts     return (ResolverSnapshot snap) --- | Note that this will be @Nothing@ on Windows, which is by design.-defaultStackGlobalConfig :: Maybe (Path Abs File)-defaultStackGlobalConfig = parseAbsFile "/etc/stack/config"- -- Interprets ConfigMonoid options. configFromConfigMonoid     :: (MonadLogger m, MonadIO m, MonadCatch m, MonadReader env m, HasHttpManager env)     => Path Abs Dir -- ^ stack root, e.g. ~/.stack+    -> Path Abs File -- ^ user config file path, e.g. ~/.stack/config.yaml     -> Maybe Project     -> ConfigMonoid     -> m Config-configFromConfigMonoid configStackRoot mproject configMonoid@ConfigMonoid{..} = do-     let configDocker = Docker.dockerOptsFromMonoid mproject configStackRoot configMonoidDockerOpts-         configConnectionCount = fromMaybe 8 configMonoidConnectionCount+configFromConfigMonoid configStackRoot configUserConfigPath mproject configMonoid@ConfigMonoid{..} = do+     let configConnectionCount = fromMaybe 8 configMonoidConnectionCount          configHideTHLoading = fromMaybe True configMonoidHideTHLoading          configLatestSnapshotUrl = fromMaybe             "https://s3.amazonaws.com/haddock.stackage.org/snapshots.json"@@ -146,6 +145,8 @@           configCompilerCheck = fromMaybe MatchMinor configMonoidCompilerCheck +     configDocker <- dockerOptsFromMonoid mproject configStackRoot configMonoidDockerOpts+      rawEnv <- liftIO getEnvironment      origEnv <- mkEnvOverride configPlatform               $ augmentPathMap (map toFilePath configMonoidExtraPath)@@ -154,15 +155,15 @@      let configEnvOverride _ = return origEnv       platformOnlyDir <- runReaderT platformOnlyRelDir configPlatform-     configLocalPrograms <-+     configLocalProgramsBase <-          case configPlatform of              Platform _ Windows -> do                  progsDir <- getWindowsProgsDir configStackRoot origEnv-                 return $ progsDir </> $(mkRelDir stackProgName) </> platformOnlyDir+                 return $ progsDir </> $(mkRelDir stackProgName)              _ ->                  return $-                 configStackRoot </> $(mkRelDir "programs") </>-                 platformOnlyDir+                 configStackRoot </> $(mkRelDir "programs")+     let configLocalPrograms = configLocalProgramsBase </> platformOnlyDir       configLocalBin <-          case configMonoidLocalBinPath of@@ -186,6 +187,10 @@          configGhcOptions = configMonoidGhcOptions          configSetupInfoLocations = configMonoidSetupInfoLocations          configPvpBounds = fromMaybe PvpBoundsNone configMonoidPvpBounds+         configModifyCodePage = fromMaybe True configMonoidModifyCodePage+         configExplicitSetupDeps = configMonoidExplicitSetupDeps+         configRebuildGhcOptions = fromMaybe False configMonoidRebuildGhcOptions+         configApplyGhcOptions = fromMaybe AGOLocals configMonoidApplyGhcOptions       return Config {..} @@ -194,20 +199,25 @@     :: (MonadIO m, MonadBaseControl IO m, MonadCatch m, MonadLogger m)     => EnvOverride -> Platform -> m GHCVariant getDefaultGHCVariant menv (Platform _ Linux) = do+    isGMP4 <- getIsGMP4 menv+    return (if isGMP4 then GHCGMP4 else GHCStandard)+getDefaultGHCVariant _ _ = return GHCStandard++-- Determine whether 'stack' is linked with libgmp4 (libgmp.so.3)+getIsGMP4+    :: (MonadIO m, MonadBaseControl IO m, MonadCatch m, MonadLogger m)+    => EnvOverride -> m Bool+getIsGMP4 menv = do     executablePath <- liftIO getExecutablePath     elddOut <- tryProcessStdout Nothing menv "ldd" [executablePath]     return $         case elddOut of-            Left _ -> GHCStandard-            Right lddOut ->-                if hasLineWithFirstWord "libgmp.so.3" lddOut-                    then GHCGMP4-                    else GHCStandard+            Left _ -> False+            Right lddOut -> hasLineWithFirstWord "libgmp.so.3" lddOut   where     hasLineWithFirstWord w =         elem (Just w) .         map (headMay . T.words) . T.lines . decodeUtf8With lenientDecode-getDefaultGHCVariant _ _ = return GHCStandard  -- | Get the directory on Windows where we should install extra programs. For -- more information, see discussion at:@@ -257,9 +267,16 @@            -> m (LoadConfig m) loadConfig configArgs mstackYaml = do     stackRoot <- determineStackRoot-    extraConfigs <- getExtraConfigs stackRoot >>= mapM loadYaml+    userConfigPath <- getDefaultUserConfigPath stackRoot+    extraConfigs0 <- getExtraConfigs userConfigPath >>= mapM loadYaml+    let extraConfigs =+            -- non-project config files' existence of a docker section should never default docker+            -- to enabled, so make it look like they didn't exist+            map (\c -> c {configMonoidDockerOpts =+                              (configMonoidDockerOpts c) {dockerMonoidDefaultEnable = False}})+                extraConfigs0     mproject <- loadProjectConfig mstackYaml-    config <- configFromConfigMonoid stackRoot (fmap (\(proj, _, _) -> proj) mproject) $ mconcat $+    config <- configFromConfigMonoid stackRoot userConfigPath (fmap (\(proj, _, _) -> proj) mproject) $ mconcat $         case mproject of             Nothing -> configArgs : extraConfigs             Just (_, _, projectConfig) -> configArgs : projectConfig : extraConfigs@@ -267,7 +284,7 @@         (throwM (BadStackVersionException (configRequireStackVersion config)))     return $ LoadConfig         { lcConfig          = config-        , lcLoadBuildConfig = loadBuildConfig mproject config stackRoot+        , lcLoadBuildConfig = loadBuildConfig mproject config         , lcProjectRoot     = fmap (\(_, fp, _) -> parent fp) mproject         } @@ -276,20 +293,19 @@ loadBuildConfig :: (MonadLogger m, MonadIO m, MonadCatch m, MonadReader env m, HasHttpManager env, MonadBaseControl IO m, HasTerminal env)                 => Maybe (Project, Path Abs File, ConfigMonoid)                 -> Config-                -> Path Abs Dir                 -> Maybe AbstractResolver -- override resolver                 -> m BuildConfig-loadBuildConfig mproject config stackRoot mresolver = do+loadBuildConfig mproject config mresolver = do     env <- ask     miniConfig <- loadMiniConfig config      (project', stackYamlFP) <- case mproject of       Just (project, fp, _) -> return (project, fp)       Nothing -> do-            $logInfo "Run from outside a project, using implicit global config"+            $logInfo "Run from outside a project, using implicit global project config"+            destDir <- getImplicitGlobalProjectDir config             let dest :: Path Abs File                 dest = destDir </> stackDotYaml-                destDir = implicitGlobalDir stackRoot                 dest' :: FilePath                 dest' = toFilePath dest             createTree destDir@@ -301,7 +317,7 @@                        case mresolver of                            Nothing ->                                $logInfo ("Using resolver: " <> resolverName (projectResolver project) <>-                                         " from global config file: " <> T.pack dest')+                                         " from implicit global project's config file: " <> T.pack dest')                            Just aresolver -> do                                let name =                                         case aresolver of@@ -316,15 +332,29 @@                else do                    r <- runReaderT getLatestResolver miniConfig                    $logInfo ("Using latest snapshot resolver: " <> resolverName r)-                   $logInfo ("Writing global (non-project-specific) config file to: " <> T.pack dest')+                   $logInfo ("Writing implicit global project config file to: " <> T.pack dest')                    $logInfo "Note: You can change the snapshot via the resolver field there."                    let p = Project                            { projectPackages = mempty                            , projectExtraDeps = mempty                            , projectFlags = mempty                            , projectResolver = r+                           , projectExtraPackageDBs = []                            }-                   liftIO $ Yaml.encodeFile dest' p+                   liftIO $ do+                       S.writeFile dest' $ S.concat+                           [ "# This is the implicit global project's config file, which is only used when\n"+                           , "# 'stack' is run outside of a real project.  Settings here do _not_ act as\n"+                           , "# defaults for all projects.  To change stack's default settings, edit\n"+                           , "# '", encodeUtf8 (T.pack $ toFilePath $ configUserConfigPath config), "' instead.\n"+                           , "#\n"+                           , "# For more information about stack's configuration, see\n"+                           , "# https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md\n"+                           , "#\n"+                           , Yaml.encode p]+                       S.writeFile (toFilePath $ parent dest </> $(mkRelFile "README.txt")) $ S.concat+                           [ "This is the implicit global project, which is used only when 'stack' is run\n"+                           , "outside of a real project.\n" ]                    return (p, dest)     resolver <-         case mresolver of@@ -343,12 +373,15 @@                 return $ mbpCompilerVersion mbp             ResolverCompiler wantedCompiler -> return wantedCompiler +    extraPackageDBs <- mapM parseRelAsAbsDir (projectExtraPackageDBs project)+     return BuildConfig         { bcConfig = config         , bcResolver = projectResolver project         , bcWantedCompiler = wantedCompiler         , bcPackageEntries = projectPackages project         , bcExtraDeps = projectExtraDeps project+        , bcExtraPackageDBs = extraPackageDBs         , bcStackYaml = stackYamlFP         , bcFlags = projectFlags project         , bcImplicitGlobal = isNothing mproject@@ -372,7 +405,7 @@             subs -> mapM (resolveDir entryRoot) subs     case peValidWanted pe of         Nothing -> return ()-        Just _ -> $logWarn "Warning: you are using the deprecated valid-wanted field. You should instead use extra-dep. See: https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md#packages"+        Just _ -> $logWarn "Warning: you are using the deprecated valid-wanted field. You should instead use extra-dep. See: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md#packages"     return $ map (, not $ peExtraDep pe) paths  -- | Resolve a PackageLocation into a path, downloading and cloning as@@ -460,10 +493,12 @@ -- | Determine the extra config file locations which exist. -- -- Returns most local first-getExtraConfigs :: MonadIO m-                => Path Abs Dir -- ^ stack root+getExtraConfigs :: (MonadIO m, MonadLogger m)+                => Path Abs File -- ^ use config path                 -> m [Path Abs File]-getExtraConfigs stackRoot = liftIO $ do+getExtraConfigs userConfigPath = do+  defaultStackGlobalConfigPath <- getDefaultGlobalConfigPath+  liftIO $ do     env <- getEnvironment     mstackConfig <-         maybe (return Nothing) (fmap Just . parseAbsFile)@@ -472,8 +507,8 @@         maybe (return Nothing) (fmap Just . parseAbsFile)       $ lookup "STACK_GLOBAL_CONFIG" env     filterM fileExists-        $ fromMaybe (stackRoot </> stackDotYaml) mstackConfig-        : maybe [] return (mstackGlobalConfig <|> defaultStackGlobalConfig)+        $ fromMaybe userConfigPath mstackConfig+        : maybe [] return (mstackGlobalConfig <|> defaultStackGlobalConfigPath)  -- | Load and parse YAML from the given file. loadYaml :: (FromJSON (a, [JSONWarning]), MonadIO m, MonadLogger m) => Path Abs File -> m a@@ -541,6 +576,47 @@     load fp = do         ProjectAndConfigMonoid project config <- loadYaml fp         return $ Just (project, fp, config)++-- | Get the location of the default stack configuration file.+-- If a file already exists at the deprecated location, its location is returned.+-- Otherwise, the new location is returned.+getDefaultGlobalConfigPath+    :: (MonadIO m, MonadLogger m)+    => m (Maybe (Path Abs File))+getDefaultGlobalConfigPath =+    case (defaultGlobalConfigPath, defaultGlobalConfigPathDeprecated) of+        (Just new,Just old) ->+            liftM (Just . fst ) $+            tryDeprecatedPath+                (Just "non-project global configuration file")+                fileExists+                new+                old+        (Just new,Nothing) -> return (Just new)+        _ -> return Nothing++-- | Get the location of the default user configuration file.+-- If a file already exists at the deprecated location, its location is returned.+-- Otherwise, the new location is returned.+getDefaultUserConfigPath+    :: (MonadIO m, MonadLogger m)+    => Path Abs Dir -> m (Path Abs File)+getDefaultUserConfigPath stackRoot = do+    (path, exists) <- tryDeprecatedPath+        (Just "non-project configuration file")+        fileExists+        (defaultUserConfigPath stackRoot)+        (defaultUserConfigPathDeprecated stackRoot)+    unless exists $ do+        createTree (parent path)+        liftIO $ S.writeFile (toFilePath path) $ S.concat+            [ "# This file contains default non-project-specific settings for 'stack', used\n"+            , "# in all projects.  For more information about stack's configuration, see\n"+            , "# https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md\n"+            , "#\n"+            , Yaml.encode (mempty :: Object) ]+    return path+  packagesParser :: Parser [String] packagesParser = many (strOption (long "package" <> help "Additional packages that must be installed"))
+ src/Stack/Config/Docker.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE CPP, DeriveDataTypeable, RecordWildCards, TemplateHaskell #-}++-- | Docker configuration+module Stack.Config.Docker where++import Control.Exception.Lifted+import Control.Monad+import Control.Monad.Catch (throwM, MonadThrow)+import Data.List (find)+import Data.Maybe+import qualified Data.Text as T+import Data.Typeable (Typeable)+import Path+import Stack.Types++-- | Interprets DockerOptsMonoid options.+dockerOptsFromMonoid+    :: MonadThrow m+    => Maybe Project -> Path Abs Dir -> DockerOptsMonoid -> m DockerOpts+dockerOptsFromMonoid mproject stackRoot DockerOptsMonoid{..} = do+    let dockerEnable =+            fromMaybe dockerMonoidDefaultEnable dockerMonoidEnable+        dockerImage =+            let defaultTag =+                    case mproject of+                        Nothing -> ""+                        Just proj ->+                            case projectResolver proj of+                                ResolverSnapshot n@(LTS _ _) ->+                                    ":" ++ T.unpack (renderSnapName n)+                                _ ->+                                    throwM+                                        (ResolverNotSupportedException $+                                         show $ projectResolver proj)+            in case dockerMonoidRepoOrImage of+                   Nothing -> "fpco/stack-build" ++ defaultTag+                   Just (DockerMonoidImage image) -> image+                   Just (DockerMonoidRepo repo) ->+                       case find (`elem` (":@" :: String)) repo of+                           Just _    -- Repo already specified a tag or digest, so don't append default+                            ->+                               repo+                           Nothing -> repo ++ defaultTag+        dockerRegistryLogin =+            fromMaybe+                (isJust (emptyToNothing dockerMonoidRegistryUsername))+                dockerMonoidRegistryLogin+        dockerRegistryUsername = emptyToNothing dockerMonoidRegistryUsername+        dockerRegistryPassword = emptyToNothing dockerMonoidRegistryPassword+        dockerAutoPull = fromMaybe False dockerMonoidAutoPull+        dockerDetach = fromMaybe False dockerMonoidDetach+        dockerPersist = fromMaybe False dockerMonoidPersist+        dockerContainerName = emptyToNothing dockerMonoidContainerName+        dockerRunArgs = dockerMonoidRunArgs+        dockerMount = dockerMonoidMount+        dockerEnv = dockerMonoidEnv+        dockerSetUser = dockerMonoidSetUser+    dockerDatabasePath <-+        case dockerMonoidDatabasePath of+            Nothing -> return $ stackRoot </> $(mkRelFile "docker.db")+            Just fp ->+                case parseAbsFile fp of+                    Left e -> throwM (InvalidDatabasePathException e)+                    Right p -> return p+    dockerStackExe <-+        case dockerMonoidStackExe of+            Just e -> liftM Just (parseDockerStackExe e)+            Nothing -> return Nothing+    return DockerOpts{..}+  where emptyToNothing Nothing = Nothing+        emptyToNothing (Just s) | null s = Nothing+                                | otherwise = Just s++-- | Exceptions thrown by Stack.Docker.Config.+data StackDockerConfigException+    = ResolverNotSupportedException String+    -- ^ Only LTS resolvers are supported for default image tag.+    | InvalidDatabasePathException SomeException+    -- ^ Invalid global database path.+    deriving (Typeable)++-- | Exception instance for StackDockerConfigException.+instance Exception StackDockerConfigException++-- | Show instance for StackDockerConfigException.+instance Show StackDockerConfigException where+    show (ResolverNotSupportedException resolver) =+        concat+            [ "Resolver not supported for Docker images:\n    "+            , resolver+            , "\nUse an LTS resolver, or set the '"+            , T.unpack dockerImageArgName+            , "' explicitly, in your configuration file."]+    show (InvalidDatabasePathException ex) =+        concat ["Invalid database path: ", show ex]
src/Stack/Constants.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} @@ -26,13 +27,17 @@     ,stackProgName     ,wiredInPackages     ,cabalPackageName-    ,implicitGlobalDir+    ,implicitGlobalProjectDirDeprecated+    ,implicitGlobalProjectDir     ,hpcRelativeDir     ,hpcDirFromDir     ,dotHpc     ,objectInterfaceDir     ,templatesDir-    ,globalConfigPath+    ,defaultUserConfigPathDeprecated+    ,defaultUserConfigPath+    ,defaultGlobalConfigPathDeprecated+    ,defaultGlobalConfigPath     )     where @@ -47,6 +52,13 @@ import           Stack.Types.Config import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName+#ifdef mingw32_HOST_OS+import qualified Crypto.Hash.SHA1 as SHA1+import qualified Data.ByteString as B+import qualified Data.ByteString.Base16 as Base16+import qualified Data.ByteString.Char8 as B8+import qualified Data.Text.Encoding as T+#endif  -- | Extensions for anything that can be a Haskell module. haskellModuleExts :: [Text]@@ -205,11 +217,22 @@         parseRelDir $         packageIdentifierString             (PackageIdentifier cabalPackageName cabalPkgVer)++#ifdef mingw32_HOST_OS+    -- This is an attempt to shorten path to stack build artifacts dir on Windows to+    -- decrease our chances of hitting 260 symbol path limit.+    -- The idea is to calculate SHA1 hash from concatenated platform and cabal strings,+    -- encode with base 16 and take first 8 symbols of it.+    let concatenatedText = T.pack . toFilePath $ platform </> cabal+        sha1 = SHA1.hash $ T.encodeUtf8 concatenatedText+    platformAndCabal <- parseRelDir . B8.unpack . B.take 8 $ Base16.encode sha1+#else+    let platformAndCabal = platform </> cabal+#endif     return $         workDirRel </>         $(mkRelDir "dist") </>-        platform </>-        cabal+        platformAndCabal  -- | Get a URL for a raw file on Github rawGithubUrl :: Text -- ^ user/org name@@ -285,17 +308,41 @@ cabalPackageName =     $(mkPackageName "Cabal") --- | Implicit global directory used when outside of a project.-implicitGlobalDir :: Path Abs Dir -- ^ Stack root.-                  -> Path Abs Dir-implicitGlobalDir p =+-- | Deprecated implicit global project directory used when outside of a project.+implicitGlobalProjectDirDeprecated :: Path Abs Dir -- ^ Stack root.+                                   -> Path Abs Dir+implicitGlobalProjectDirDeprecated p =     p </>     $(mkRelDir "global") +-- | Implicit global project directory used when outside of a project.+-- Normally, @getImplicitGlobalProjectDir@ should be used instead.+implicitGlobalProjectDir :: Path Abs Dir -- ^ Stack root.+                         -> Path Abs Dir+implicitGlobalProjectDir p =+    p </>+    $(mkRelDir "global-project")+ -- | Where .mix files go. dotHpc :: Path Rel Dir dotHpc = $(mkRelDir ".hpc") --- | Global config path.-globalConfigPath :: Config -> Path Abs File-globalConfigPath = (</> $(mkRelFile "stack.yaml")) . configStackRoot+-- | Deprecated default global config path.+defaultUserConfigPathDeprecated :: Path Abs Dir -> Path Abs File+defaultUserConfigPathDeprecated = (</> $(mkRelFile "stack.yaml"))++-- | Default global config path.+-- Normally, @getDefaultUserConfigPath@ should be used instead.+defaultUserConfigPath :: Path Abs Dir -> Path Abs File+defaultUserConfigPath = (</> $(mkRelFile "config.yaml"))++-- | Deprecated default global config path.+-- Note that this will be @Nothing@ on Windows, which is by design.+defaultGlobalConfigPathDeprecated :: Maybe (Path Abs File)+defaultGlobalConfigPathDeprecated = parseAbsFile "/etc/stack/config"++-- | Default global config path.+-- Normally, @getDefaultGlobalConfigPath@ should be used instead.+-- Note that this will be @Nothing@ on Windows, which is by design.+defaultGlobalConfigPath :: Maybe (Path Abs File)+defaultGlobalConfigPath = parseAbsFile "/etc/stack/config.yaml"
src/Stack/Docker.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP, ConstraintKinds, DeriveDataTypeable, FlexibleContexts, MultiWayIf, NamedFieldPuns,-             OverloadedStrings, RankNTypes, RecordWildCards, TemplateHaskell, TupleSections #-}+             OverloadedStrings, RankNTypes, RecordWildCards, ScopedTypeVariables, TemplateHaskell,+             TupleSections #-}  -- | Run commands in Docker containers module Stack.Docker@@ -8,7 +9,6 @@   ,CleanupAction(..)   ,dockerCleanupCmdName   ,dockerCmdName-  ,dockerOptsFromMonoid   ,dockerPullCmdName   ,execWithOptionalContainer   ,preventInContainer@@ -21,7 +21,7 @@ import           Control.Applicative import           Control.Exception.Lifted import           Control.Monad-import           Control.Monad.Catch (MonadThrow,throwM,MonadCatch)+import           Control.Monad.Catch (MonadThrow,throwM,MonadCatch,MonadMask) import           Control.Monad.IO.Class (MonadIO,liftIO) import           Control.Monad.Logger (MonadLogger,logError,logInfo,logWarn) import           Control.Monad.Reader (MonadReader,asks)@@ -32,7 +32,8 @@ import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as LBS import           Data.Char (isSpace,toUpper,isAscii,isDigit)-import           Data.List (dropWhileEnd,find,intercalate,intersperse,isPrefixOf,isInfixOf,foldl',sortBy)+import           Data.Conduit.List (sinkNull)+import           Data.List (dropWhileEnd,intercalate,intersperse,isPrefixOf,isInfixOf,foldl',sortBy) import           Data.List.Extra (trim) import           Data.Map.Strict (Map) import qualified Data.Map.Strict as Map@@ -43,17 +44,23 @@ import qualified Data.Text.Encoding as T import           Data.Time (UTCTime,LocalTime(..),diffDays,utcToLocalTime,getZonedTime,ZonedTime(..)) import           Data.Typeable (Typeable)+import           Data.Version (showVersion)+import           Distribution.System (Platform (Platform), Arch (X86_64), OS (Linux))+import           Distribution.Text (display)+import           Network.HTTP.Client.Conduit (HasHttpManager) import           Path import           Path.IO (getWorkingDir,listDirectory,createTree,removeFile,removeTree,dirExists)+import qualified Paths_stack as Meta import           Prelude -- Fix redundant import warnings-import           Stack.Constants (projectDockerSandboxDir,stackProgName,stackDotYaml,stackRootEnvVar)+import           Stack.Constants (projectDockerSandboxDir,stackProgName,stackRootEnvVar)+import           Stack.Docker.GlobalDB import           Stack.Types import           Stack.Types.Internal-import           Stack.Docker.GlobalDB-import           System.Environment (lookupEnv,getProgName,getArgs,getExecutablePath)+import           Stack.Setup (ensureDockerStackExe)+import           System.Directory (canonicalizePath, getModificationTime)+import           System.Environment (lookupEnv,getProgName, getArgs,getExecutablePath) import           System.Exit (exitSuccess, exitWith) import           System.FilePath (dropTrailingPathSeparator,takeBaseName)-import           System.Info (arch,os) import           System.IO (stderr,stdin,stdout,hIsTerminalDevice) import           System.Process.PagerEditor (editByteString) import           System.Process.Read@@ -82,21 +89,86 @@     -> Maybe (m ())     -> m () reexecWithOptionalContainer mprojectRoot =-  execWithOptionalContainer mprojectRoot getCmdArgs+    execWithOptionalContainer mprojectRoot getCmdArgs   where-    getCmdArgs =-      do args <- (("--" ++ reExecArgName) :) <$> getArgs-         if arch == "x86_64" && os == "linux"-             then do exePath <- getExecutablePath-                     let mountPath = concat ["/opt/host/bin/",takeBaseName exePath]-                     return (mountPath-                            ,args-                            ,[]-                            ,\c -> c{configDocker=(configDocker c)-                                                  {dockerMount=Mount exePath mountPath :-                                                               dockerMount (configDocker c)}})-             else do progName <- getProgName-                     return (takeBaseName progName,args,[],id)+    getCmdArgs envOverride imageInfo = do+        config <- asks getConfig+        args <-+            fmap+                (("--" ++ reExecArgName ++ "=" ++ showVersion Meta.version) :)+                (liftIO getArgs)+        case dockerStackExe (configDocker config) of+            Just DockerStackExeHost+              | configPlatform config == dockerContainerPlatform ->+                  fmap (cmdArgs args) (liftIO getExecutablePath)+              | otherwise -> throwM UnsupportedStackExeHostPlatformException+            Just DockerStackExeImage -> do+                progName <- liftIO getProgName+                return (takeBaseName progName, args, [], [])+            Just (DockerStackExePath path) ->+                fmap+                    (cmdArgs args)+                    (liftIO $ canonicalizePath (toFilePath path))+            Just DockerStackExeDownload -> exeDownload args+            Nothing+              | configPlatform config == dockerContainerPlatform -> do+                  (exePath,exeTimestamp,misCompatible) <-+                      liftIO $+                      do exePath <- liftIO getExecutablePath+                         exeTimestamp <- liftIO (getModificationTime exePath)+                         isKnown <-+                             liftIO $+                             getDockerImageExe+                                 config+                                 (iiId imageInfo)+                                 exePath+                                 exeTimestamp+                         return (exePath, exeTimestamp, isKnown)+                  case misCompatible of+                      Just True -> do+                          return (cmdArgs args exePath)+                      Just False -> do+                          exeDownload args+                      Nothing -> do+                          e <-+                              try $+                              sinkProcessStderrStdout+                                  Nothing+                                  envOverride+                                  "docker"+                                  [ "run"+                                  , "-v"+                                  , exePath ++ ":" ++ "/tmp/stack"+                                  , iiId imageInfo+                                  , "/tmp/stack"+                                  , "--version"]+                                  sinkNull+                                  sinkNull+                          let compatible =+                                  case e of+                                      Left (ProcessExitedUnsuccessfully _ _) ->+                                          False+                                      Right _ -> True+                          liftIO $+                              setDockerImageExe+                                  config+                                  (iiId imageInfo)+                                  exePath+                                  exeTimestamp+                                  compatible+                          if compatible+                              then return (cmdArgs args exePath)+                              else exeDownload args+            Nothing+              | otherwise -> do+                  exeDownload args+    exeDownload args =+        fmap+            (cmdArgs args . toFilePath)+            (ensureDockerStackExe dockerContainerPlatform)+    cmdArgs args exePath =+        let mountPath = concat ["/opt/host/bin/", takeBaseName exePath]+        in (mountPath, args, [], [Mount exePath mountPath])  -- | If Docker is enabled, re-runs the OS command returned by the second argument in a -- Docker container.  Otherwise, runs the inner action.@@ -105,7 +177,7 @@ execWithOptionalContainer     :: M env m     => Maybe (Path Abs Dir)-    -> IO (FilePath,[String],[(String,String)],Config -> Config)+    -> (EnvOverride -> Inspect -> m (FilePath,[String],[(String,String)],[Mount]))     -> Maybe (m ())     -> IO ()     -> Maybe (m ())@@ -126,15 +198,11 @@                fromMaybeAction mafter                liftIO exitSuccess         | otherwise ->-            do (cmd_,args,envVars,modConfig) <- liftIO getCmdArgs-               fromMaybeAction mrelease+            do fromMaybeAction mrelease                runContainerAndExit-                 modConfig+                 getCmdArgs                  mprojectRoot                  (fromMaybeAction mbefore)-                 cmd_-                 args-                 envVars                  (fromMaybeAction mafter)   where     fromMaybeAction Nothing = return ()@@ -154,38 +222,40 @@  -- | Run a command in a new Docker container, then exit the process. runContainerAndExit :: M env m-                    => (Config -> Config)+                    => (EnvOverride -> Inspect -> m (FilePath,[String],[(String,String)],[Mount]))                     -> Maybe (Path Abs Dir)                     -> m ()-                    -> FilePath-                    -> [String]-                    -> [(String, String)]                     -> m ()                     -> m ()-runContainerAndExit modConfig+runContainerAndExit getCmdArgs                     mprojectRoot                     before-                    cmnd-                    args-                    envVars                     after =-  do config <- fmap modConfig (asks getConfig)+  do config <- asks getConfig      let docker = configDocker config      envOverride <- getEnvOverride (configPlatform config)      checkDockerVersion envOverride-     uidOut <- readProcessStdout Nothing envOverride "id" ["-u"]-     gidOut <- readProcessStdout Nothing envOverride "id" ["-g"]      (dockerHost,dockerCertPath,bamboo,jenkins) <-        liftIO ((,,,) <$> lookupEnv "DOCKER_HOST"                      <*> lookupEnv "DOCKER_CERT_PATH"                      <*> lookupEnv "bamboo_buildKey"                      <*> lookupEnv "JENKINS_HOME")+     let isRemoteDocker = maybe False (isPrefixOf "tcp://") dockerHost+     userEnvVars <-+         if fromMaybe (not isRemoteDocker) (dockerSetUser docker)+             then do+                 uidOut <- readProcessStdout Nothing envOverride "id" ["-u"]+                 gidOut <- readProcessStdout Nothing envOverride "id" ["-g"]+                 return+                     [ "-e","WORK_UID=" ++ dropWhileEnd isSpace (decodeUtf8 uidOut)+                     , "-e","WORK_GID=" ++ dropWhileEnd isSpace (decodeUtf8 gidOut) ]+             else return []      isStdoutTerminal <- asks getTerminal      (isStdinTerminal,isStderrTerminal) <-        liftIO ((,) <$> hIsTerminalDevice stdin                    <*> hIsTerminalDevice stderr)      pwd <- getWorkingDir-     when (maybe False (isPrefixOf "tcp://") dockerHost &&+     when (isRemoteDocker &&            maybe False (isInfixOf "boot2docker") dockerCertPath)           ($logWarn "Warning: Using boot2docker is NOT supported, and not likely to perform well.")      let image = dockerImage docker@@ -200,9 +270,8 @@                   Just ii2 -> return ii2                   Nothing -> throwM (InspectFailedException image)          | otherwise -> throwM (NotPulledException image)-     let uid = dropWhileEnd isSpace (decodeUtf8 uidOut)-         gid = dropWhileEnd isSpace (decodeUtf8 gidOut)-         imageEnvVars = map (break (== '=')) (icEnv (iiConfig imageInfo))+     (cmnd,args,envVars,extraMount) <- getCmdArgs envOverride imageInfo+     let imageEnvVars = map (break (== '=')) (icEnv (iiConfig imageInfo))          sandboxID = fromMaybe "default" (lookupImageEnv sandboxIDEnvVar imageEnvVars)      sandboxIDDir <- parseRelDir (sandboxID ++ "/")      let stackRoot = configStackRoot config@@ -217,6 +286,7 @@                   isStdoutTerminal &&                   isStderrTerminal          keepStdinOpen = not (dockerDetach docker) &&+                         -- Workaround for https://github.com/docker/docker/issues/12319                          (isTerm || (isNothing bamboo && isNothing jenkins))      liftIO        (do updateDockerImageLastUsed config@@ -233,8 +303,6 @@           ,"--net=host"           ,"-e",inContainerEnvVar ++ "=1"           ,"-e",stackRootEnvVar ++ "=" ++ toFPNoTrailingSep stackRoot-          ,"-e","WORK_UID=" ++ uid-          ,"-e","WORK_GID=" ++ gid           ,"-e","WORK_WD=" ++ toFPNoTrailingSep pwd           ,"-e","WORK_HOME=" ++ toFPNoTrailingSep sandboxRepoDir           ,"-e","WORK_ROOT=" ++ toFPNoTrailingSep projectRoot@@ -244,9 +312,10 @@           ,"-v",toFPNoTrailingSep sandboxHomeDir ++ ":" ++ toFPNoTrailingSep sandboxRepoDir           ,"-v",toFPNoTrailingSep stackRoot ++ ":" ++                 toFPNoTrailingSep (sandboxRepoDir </> $(mkRelDir ("." ++ stackProgName ++ "/")))]+         ,userEnvVars          ,concatMap (\(k,v) -> ["-e", k ++ "=" ++ v]) envVars          ,concatMap sandboxSubdirArg sandboxSubdirs-         ,concatMap mountArg (dockerMount docker)+         ,concatMap mountArg (extraMount ++ dockerMount docker)          ,concatMap (\nv -> ["-e", nv]) (dockerEnv docker)          ,case dockerContainerName docker of             Just name -> ["--name=" ++ name]@@ -476,8 +545,8 @@              buildInspect hash              return True         buildContainer removeAge (hash,(image,name),created) =-          do let display = (name ++ " (image: " ++ image ++ ")")-             buildTime containerStr removeAge created display+          do let disp = (name ++ " (image: " ++ image ++ ")")+             buildTime containerStr removeAge created disp              buildInspect hash              return True         buildProject (lastUsedTime, projectPath) =@@ -507,10 +576,10 @@               LocalTime oldDay _ = utcToLocalTime zone oldTime           in diffDays today oldDay         buildImageTime = buildTime imageStr-        buildTime t removeAge time display =+        buildTime t removeAge time disp =           case removeAge of-            Just d | daysAgo time >= d -> buildStrLn ("R " ++ t ++ " " ++ display)-            _ -> buildKeep t display+            Just d | daysAgo time >= d -> buildStrLn ("R " ++ t ++ " " ++ disp)+            _ -> buildKeep t disp         buildKeep t d = buildStrLn ("  " ++ t ++ " " ++ d)         buildKeepImage = buildKeep imageStr         buildSectionHead s = buildStrLn ("\n#\n# " ++ s ++ "\n#\n")@@ -648,48 +717,6 @@ homeDirName :: Path Rel Dir homeDirName = $(mkRelDir "_home/") --- | Interprets DockerOptsMonoid options.-dockerOptsFromMonoid :: Maybe Project -> Path Abs Dir -> DockerOptsMonoid -> DockerOpts-dockerOptsFromMonoid mproject stackRoot DockerOptsMonoid{..} = DockerOpts-  {dockerEnable = fromMaybe (fromMaybe False dockerMonoidExists) dockerMonoidEnable-  ,dockerImage =-     let defaultTag =-           case mproject of-             Nothing -> ""-             Just proj ->-               case projectResolver proj of-                 ResolverSnapshot n@(LTS _ _) -> ":" ++  T.unpack (renderSnapName n)-                 _ -> throw (ResolverNotSupportedException (projectResolver proj))-     in case dockerMonoidRepoOrImage of-       Nothing -> "fpco/stack-build" ++ defaultTag-       Just (DockerMonoidImage image) -> image-       Just (DockerMonoidRepo repo) ->-         case find (`elem` (":@" :: String)) repo of-           Just _ -> -- Repo already specified a tag or digest, so don't append default-                     repo-           Nothing -> repo ++ defaultTag-  ,dockerRegistryLogin = fromMaybe (isJust (emptyToNothing dockerMonoidRegistryUsername))-                                   dockerMonoidRegistryLogin-  ,dockerRegistryUsername = emptyToNothing dockerMonoidRegistryUsername-  ,dockerRegistryPassword = emptyToNothing dockerMonoidRegistryPassword-  ,dockerAutoPull = fromMaybe False dockerMonoidAutoPull-  ,dockerDetach = fromMaybe False dockerMonoidDetach-  ,dockerPersist = fromMaybe False dockerMonoidPersist-  ,dockerContainerName = emptyToNothing dockerMonoidContainerName-  ,dockerRunArgs = dockerMonoidRunArgs-  ,dockerMount = dockerMonoidMount-  ,dockerEnv = dockerMonoidEnv-  ,dockerDatabasePath =-     case dockerMonoidDatabasePath of-       Nothing -> stackRoot </> $(mkRelFile "docker.db")-       Just fp -> case parseAbsFile fp of-                    Left e -> throw (InvalidDatabasePathException e)-                    Right p -> p-  }-  where emptyToNothing Nothing = Nothing-        emptyToNothing (Just s) | null s = Nothing-                                | otherwise = Just s- -- | Convenience function to decode ByteString to String. decodeUtf8 :: BS.ByteString -> String decodeUtf8 bs = T.unpack (T.decodeUtf8 (bs))@@ -724,7 +751,7 @@  -- | Command-line option for @--internal-re-exec@. reExecArgName :: String-reExecArgName = "internal-re-exec"+reExecArgName = "internal-re-exec-version"  -- | Options for 'cleanup'. data CleanupOpts = CleanupOpts@@ -800,14 +827,12 @@     -- ^ Version of @stack@ on host is too old for version in image.   | ContainerStackTooOldException Version Version     -- ^ Version of @stack@ in container/image is too old for version on host.-  | ResolverNotSupportedException Resolver-    -- ^ Only LTS resolvers are supported for default image tag.   | CannotDetermineProjectRootException     -- ^ Can't determine the project root (where to put docker sandbox).   | DockerNotInstalledException     -- ^ @docker --version@ failed.-  | InvalidDatabasePathException SomeException-    -- ^ Invalid global database path.+  | UnsupportedStackExeHostPlatformException+    -- ^ Using host stack-exe on unsupported platform.   deriving (Typeable)  -- | Exception instance for StackDockerException.@@ -816,14 +841,13 @@ -- | Show instance for StackDockerException. instance Show StackDockerException where   show DockerMustBeEnabledException =-    concat ["Docker must be enabled in your ",toFilePath stackDotYaml," to use this command."]+    concat ["Docker must be enabled in your configuration file to use this command."]   show OnlyOnHostException =     "This command must be run on host OS (not in a Docker container)."   show (InspectFailedException image) =     concat ["'docker inspect' failed for image after pull: ",image,"."]   show (NotPulledException image) =-    concat ["The Docker image referenced by "-           ,toFilePath stackDotYaml+    concat ["The Docker image referenced by your configuration file"            ," has not\nbeen downloaded:\n    "            ,image            ,"\n\nRun '"@@ -841,8 +865,7 @@     concat ["Could not pull Docker image:\n    "            ,image            ,"\nThere may not be an image on the registry for your resolver's LTS version in\n"-           ,toFilePath stackDotYaml-           ,"."]+           ,"your configuration file."]   show (DockerTooOldException minVersion haveVersion) =     concat ["Minimum docker version '"            ,versionString minVersion@@ -879,20 +902,20 @@            ," is required; the container has "            ,versionString containerVersion            ,"."]-  show (ResolverNotSupportedException resolver) =-    concat ["Resolver not supported for Docker images:\n    "-           ,show resolver-           ,"\nUse an LTS resolver, or set the '"-           ,T.unpack dockerImageArgName-           ,"' explicitly, in "-           ,toFilePath stackDotYaml-           ,"."]   show CannotDetermineProjectRootException =     "Cannot determine project root directory for Docker sandbox."-  show DockerNotInstalledException=+  show DockerNotInstalledException =     "Cannot find 'docker' in PATH.  Is Docker installed?"-  show (InvalidDatabasePathException ex) =-    concat ["Invalid database path: ",show ex]+  show UnsupportedStackExeHostPlatformException = concat+    [ "Using host's "+    , stackProgName+    , " executable in Docker container is only supported on "+    , display dockerContainerPlatform+    , " platform" ] +-- | Platform that Docker containers run+dockerContainerPlatform :: Platform+dockerContainerPlatform = Platform X86_64 Linux+ type M env m = (MonadIO m,MonadReader env m,MonadLogger m,MonadBaseControl IO m,MonadCatch m-               ,HasConfig env,HasTerminal env,HasReExec env)+               ,HasConfig env,HasTerminal env,HasReExec env,HasHttpManager env,MonadMask m)
src/Stack/Docker/GlobalDB.hs view
@@ -9,7 +9,10 @@   ,getDockerImagesLastUsed   ,pruneDockerImagesLastUsed   ,DockerImageLastUsed-  ,DockerImageProjectId)+  ,DockerImageProjectId+  ,getDockerImageExe+  ,setDockerImageExe+  ,DockerImageExeId)   where  import           Control.Exception (IOException,catch,throwIO)@@ -36,6 +39,13 @@     lastUsedTime              UTCTime     DockerImageProjectPathKey imageHash projectPath     deriving Show+DockerImageExe+    imageHash                 String+    exePath                   FilePath+    exeTimestamp              UTCTime+    compatible                Bool+    DockerImageExeUnique      imageHash exePath exeTimestamp+    deriving Show |]  -- | Update last used time and project for a Docker image hash.@@ -70,6 +80,20 @@                            if h `elem` existingHashes                              then return ()                              else delete k)++-- | Get the record of whether an executable is compatible with a Docker image+getDockerImageExe :: Config -> String -> FilePath -> UTCTime -> IO (Maybe Bool)+getDockerImageExe config imageId exePath exeTimestamp =+    withGlobalDB config $ do+        mentity <- getBy (DockerImageExeUnique imageId exePath exeTimestamp)+        return (fmap (dockerImageExeCompatible . entityVal) mentity)++-- | Seet the record of whether an executable is compatible with a Docker image+setDockerImageExe :: Config -> String -> FilePath -> UTCTime -> Bool -> IO ()+setDockerImageExe config imageId exePath exeTimestamp compatible =+    withGlobalDB config $+    do _ <- upsert (DockerImageExe imageId exePath exeTimestamp compatible) []+       return ()  -- | Run an action with the global database.  This performs any needed migrations as well. withGlobalDB :: forall a. Config -> SqlPersistT (NoLoggingT (ResourceT IO)) a -> IO a
src/Stack/FileWatch.hs view
@@ -10,7 +10,7 @@ import Blaze.ByteString.Builder.Char.Utf8 (fromShow) import Control.Concurrent.Async (race_) import Control.Concurrent.STM-import Control.Exception (Exception)+import Control.Exception (Exception, fromException) import Control.Exception.Enclosed (tryAny) import Control.Monad (forever, unless, when) import qualified Data.ByteString.Lazy as L@@ -20,10 +20,13 @@ import qualified Data.Set as Set import Data.String (fromString) import Data.Traversable (forM)+import GHC.IO.Handle (hIsTerminalDevice) import Ignore import Path+import System.Console.ANSI+import System.Exit import System.FSNotify-import System.IO (stderr)+import System.IO (stdout, stderr)  -- | Print an exception to stderr printExceptionStderr :: Exception e => e -> IO ()@@ -110,6 +113,7 @@                     "watched" -> do                         watch <- readTVarIO watchVar                         mapM_ (putStrLn . toFilePath) (Map.keys watch)+                    "" -> atomically $ writeTVar dirtyVar True                     _ -> putStrLn $ concat                         [ "Unknown command: "                         , show line@@ -133,8 +137,22 @@         -- https://github.com/commercialhaskell/stack/issues/822         atomically $ writeTVar dirtyVar False +        let withColor color action = do+                outputIsTerminal <- hIsTerminalDevice stdout+                if outputIsTerminal+                then do+                    setSGR [SetColor Foreground Dull color]+                    action+                    setSGR [Reset]+                else action+         case eres of-            Left e -> printExceptionStderr e-            Right () -> putStrLn "Success! Waiting for next file change."+            Left e -> do+                let color = case fromException e of+                        Just ExitSuccess -> Green+                        _ -> Red+                withColor color $ printExceptionStderr e+            _ -> withColor Green $+                putStrLn "Success! Waiting for next file change." -        putStrLn "Type help for available commands"+        putStrLn "Type help for available commands. Press enter to force a rebuild."
src/Stack/Ghci.hs view
@@ -30,6 +30,7 @@ import           Path import           Prelude import           Stack.Build+import           Stack.Build.Installed import           Stack.Build.Source import           Stack.Build.Target import           Stack.Constants@@ -55,6 +56,7 @@   , ghciPkgDir :: Path Abs Dir   , ghciPkgModules :: Set ModuleName   , ghciPkgModFiles :: Set (Path Abs File) -- ^ Module file paths.+  , ghciPkgCFiles :: Set (Path Abs File) -- ^ C files.   , ghciPkgMainIs :: Map NamedComponent (Set (Path Abs File))   } @@ -176,6 +178,14 @@     let bopts = makeBuildOpts targets     econfig <- asks getEnvConfig     (realTargets,_,_,_,sourceMap) <- loadSourceMap AllowNoTargets bopts+    menv <- getMinimalEnvOverride+    (installedMap, _, _) <- getInstalled+        menv+        GetInstalledOpts+            { getInstalledProfiling = False+            , getInstalledHaddock   = False+            }+        sourceMap     locals <-         liftM catMaybes $         forM (M.toList (envConfigPackages econfig)) $@@ -191,7 +201,7 @@     infos <-         forM locals $         \(name,(cabalfp,components)) ->-             makeGhciPkgInfo sourceMap (map fst locals) name cabalfp components+             makeGhciPkgInfo sourceMap installedMap (map fst locals) name cabalfp components     unless (M.null realTargets) (build (const (return ())) Nothing bopts)     return (realTargets, mainIsTargets, infos)   where@@ -230,12 +240,13 @@ makeGhciPkgInfo     :: (MonadReader r m, HasEnvConfig r, MonadLogger m, MonadIO m, MonadCatch m)     => SourceMap+    -> InstalledMap     -> [PackageName]     -> PackageName     -> Path Abs File     -> SimpleTarget     -> m GhciPkgInfo-makeGhciPkgInfo sourceMap locals name cabalfp components = do+makeGhciPkgInfo sourceMap installedMap locals name cabalfp components = do     econfig <- asks getEnvConfig     bconfig <- asks getBuildConfig     let config =@@ -249,7 +260,7 @@     (warnings,pkg) <- readPackage config cabalfp     mapM_ (printCabalFileWarning cabalfp) warnings     (componentsModules,componentFiles,componentsOpts,generalOpts) <--        getPackageOpts (packageOpts pkg) sourceMap locals cabalfp+        getPackageOpts (packageOpts pkg) sourceMap installedMap locals cabalfp     let filterWithinWantedComponents m =             M.elems                 (M.filterWithKey@@ -272,6 +283,9 @@               (filterWithinWantedComponents                    (M.map (setMapMaybe dotCabalModulePath) componentFiles))         , ghciPkgMainIs = M.map (setMapMaybe dotCabalMainPath) componentFiles+        , ghciPkgCFiles = mconcat+              (filterWithinWantedComponents+                   (M.map (setMapMaybe dotCabalCFilePath) componentFiles))         }   where     badForGhci :: String -> Bool
src/Stack/Ide.hs view
@@ -3,44 +3,36 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-}  -- | Run a IDE configured with the user's project(s). -module Stack.Ide (ide) where+module Stack.Ide+    (ide, getPackageOptsAndTargetFiles)+    where -import           Control.Concurrent import           Control.Monad.Catch import           Control.Monad.IO.Class import           Control.Monad.Logger import           Control.Monad.Reader import           Control.Monad.Trans.Control (MonadBaseControl)-import           Data.Aeson-import qualified Data.ByteString as S-import qualified Data.ByteString.Char8 as S8-import           Data.ByteString.Lazy (ByteString)-import qualified Data.ByteString.Lazy as L import           Data.List import           Data.Maybe import           Data.Monoid import qualified Data.Set as S import           Data.Text (Text)-import qualified Data.Text as T+import           Distribution.System import           Network.HTTP.Client.Conduit import           Path import           Path.IO import           Stack.Constants-import           Stack.Exec (defaultEnvSettings) import           Stack.Ghci (GhciPkgInfo(..), ghciSetup) import           Stack.Package import           Stack.Types import           Stack.Types.Internal-import           System.Directory (doesFileExist) import           System.Environment (lookupEnv)-import           System.Exit-import           System.IO-import qualified System.Process as P-import           System.Process.Read+import           System.Process.Run  -- | Launch a GHCi IDE for the given local project targets with the -- given options and configure it with the load paths and extensions@@ -53,28 +45,8 @@ ide targets useropts = do     (_realTargets,_,pkgs) <- ghciSetup Nothing targets     pwd <- getWorkingDir-    (pkgopts,srcfiles) <--        liftM mconcat $-        forM pkgs $-        \pkg ->-             do dist <- distDirFromDir (ghciPkgDir pkg)-                autogen <- return (autogenDir dist)-                paths_foo <--                    liftM-                        (autogen </>)-                        (parseRelFile-                             ("Paths_" ++-                              packageNameString (ghciPkgName pkg) ++ ".hs"))-                paths_foo_exists <- fileExists paths_foo-                return-                    ( ["--dist-dir=" <> toFilePath dist] ++-                      map ("--ghc-option=" ++) (ghciPkgOpts pkg)-                    , mapMaybe-                          (fmap toFilePath . stripDir pwd)-                          (S.toList (ghciPkgModFiles pkg) <>-                           if paths_foo_exists-                               then [paths_foo]-                               else []))+    (pkgopts,_srcfiles) <-+        liftM mconcat $ forM pkgs $ getPackageOptsAndTargetFiles pwd     localdb <- packageDatabaseLocal     depsdb <- packageDatabaseDeps     mpath <- liftIO $ lookupEnv "PATH"@@ -86,66 +58,46 @@               intercalate ":" (map toFilePath bindirs) <>               (maybe "" (':' :) mpath)]         args =-            ["--verbose"] <> ["--local-work-dir=" ++ toFilePath pwd] <>+            ["--verbose"] <> ["--include=" <> includeDirs pkgopts] <>+            ["--local-work-dir=" ++ toFilePath pwd] <>             map ("--ghc-option=" ++) useropts <>             paths <>             pkgopts <>             pkgdbs-    let initialStdin = encode (initialRequest srcfiles)-    $logDebug $ "Initial stack-ide request: " <> T.pack (show initialStdin)-    exec "stack-ide" args initialStdin---- | Make the initial request.-initialRequest :: [FilePath] -> Value-initialRequest srcfiles =-    object-        [ "tag" .= "RequestUpdateSession"-        , "contents" .=-            [ object-                [ "tag" .= "RequestUpdateTargets"-                , "contents" .= object-                    [ "tag" .= "TargetsInclude"-                    , "contents" .= srcfiles ]-                ]-            ]-        ]+    menv <- getMinimalEnvOverride+    Platform _ os <- asks getPlatform+    when+        (os == OSX)+        (catch (callProcess (Just pwd) menv "stty" ["cbreak", "-imaxbel"])+               (\(_ :: ProcessExitedUnsuccessfully) -> undefined))+    callProcess (Just pwd) menv "stack-ide" args+  where+    includeDirs pkgopts =+        intercalate+            ":"+            (mapMaybe+                 (stripPrefix "--ghc-option=-i")+                 pkgopts) --- | Execute a process within the Stack configured environment.-exec :: (HasConfig r, MonadReader r m, MonadIO m, MonadLogger m, MonadThrow m)-        => String -> [String] -> ByteString -> m b-exec cmd args input = do-    config <- asks getConfig-    menv <--        liftIO-            (configEnvOverride-                 config-                 defaultEnvSettings-                 { esIncludeGhcPackagePath = False-                 })-    exists <- liftIO $ doesFileExist cmd-    cmd' <--        if exists-            then return cmd-            else liftM toFilePath $-                 join $ System.Process.Read.findExecutable menv cmd-    let cp =-            (P.proc cmd' args)-            { P.env = envHelper menv-            , P.delegate_ctlc = True-            , P.std_in = P.CreatePipe-            }-    $logProcessRun cmd' args-    (Just procin,Nothing,Nothing,ph) <- liftIO (P.createProcess cp)-    liftIO-        (do hSetBuffering stdin LineBuffering-            hSetBuffering procin LineBuffering)-    liftIO (do {-S8.hPutStrLn stdout (L.toStrict input)-}-               S8.hPutStrLn procin (L.toStrict input))-    _tid <--        liftIO-            (forkIO-                 (forever-                      (do bytes <- S.getLine-                          S.hPutStr procin bytes)))-    ec <- liftIO (P.waitForProcess ph)-    liftIO (exitWith ec)+-- | Get options and target files for the given package info.+getPackageOptsAndTargetFiles+    :: (MonadThrow m, MonadIO m, MonadReader env m, HasEnvConfig env)+    => Path Abs Dir -> GhciPkgInfo -> m ([FilePath], [FilePath])+getPackageOptsAndTargetFiles pwd pkg = do+    dist <- distDirFromDir (ghciPkgDir pkg)+    autogen <- return (autogenDir dist)+    paths_foo <-+        liftM+            (autogen </>)+            (parseRelFile+                 ("Paths_" ++ packageNameString (ghciPkgName pkg) ++ ".hs"))+    paths_foo_exists <- fileExists paths_foo+    return+        ( ["--dist-dir=" <> toFilePath dist] +++          map ("--ghc-option=" ++) (ghciPkgOpts pkg)+        , mapMaybe+              (fmap toFilePath . stripDir pwd)+              (S.toList (ghciPkgCFiles pkg) <> S.toList (ghciPkgModFiles pkg) <>+               if paths_foo_exists+                   then [paths_foo]+                   else []))
src/Stack/Image.hs view
@@ -47,6 +47,7 @@                              => m () stageContainerImageArtifacts = do     imageDir <- imageStagingDir <$> getWorkingDir+    removeTreeIfExists imageDir     createTree imageDir     stageExesInDir imageDir     syncAddContentToDir imageDir
src/Stack/Init.hs view
@@ -9,12 +9,14 @@     , SnapPref (..)     , Method (..)     , makeConcreteResolver+    , tryDeprecatedPath+    , getImplicitGlobalProjectDir     ) where  import           Control.Exception               (assert)-import           Control.Exception.Enclosed      (handleIO, catchAny)+import           Control.Exception.Enclosed      (catchAny, handleIO) import           Control.Monad                   (liftM, when)-import           Control.Monad.Catch             (MonadMask, throwM, MonadThrow)+import           Control.Monad.Catch             (MonadMask, MonadThrow, throwM) import           Control.Monad.IO.Class import           Control.Monad.Logger import           Control.Monad.Reader            (MonadReader, asks)@@ -92,6 +94,7 @@             , projectExtraDeps = extraDeps             , projectFlags = flags             , projectResolver = r+            , projectExtraPackageDBs = []             }         pkgs = map toPkg cabalfps         toPkg fp = PackageEntry@@ -118,7 +121,7 @@         _ -> assert False $ B.byteString $ Yaml.encode p   where     renderObject o =-        B.byteString "# For more information, see: https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md\n\n" <>+        B.byteString "# For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md\n\n" <>         F.foldMap (goComment o) comments <>         goOthers (o `HM.difference` HM.fromList comments) <>         B.byteString@@ -139,6 +142,7 @@         , ("packages", "Local packages, usually specified by relative directory name")         , ("extra-deps", "Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)")         , ("flags", "Override default flag values for local packages and extra-deps")+        , ("extra-package-dbs", "Extra package databases containing global packages")         ]      goComment o (name, comment) =@@ -170,7 +174,7 @@         $logError ""         $logError "You can try again, or create your stack.yaml file by hand. See:"         $logError ""-        $logError "    https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md"+        $logError "    https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md"         $logError ""         $logError $ "Exception was: " <> T.pack (show e)         return Nothing@@ -206,7 +210,7 @@                     return (ResolverSnapshot snap, flags, Map.empty)                 Nothing -> return (resolver, Map.empty, Map.empty)         MethodSolver -> do-            (compilerVersion, extraDeps) <- cabalSolver Ghc (map parent cabalfps) Map.empty []+            (compilerVersion, extraDeps) <- cabalSolver Ghc (map parent cabalfps) Map.empty Map.empty []             return                 ( ResolverCompiler compilerVersion                 , Map.filter (not . Map.null) $ fmap snd extraDeps@@ -248,7 +252,7 @@         PrefNightly -> return $ namesNightly ++ namesLTS  data InitOpts = InitOpts-    { ioMethod :: !Method+    { ioMethod       :: !Method     -- ^ Preferred snapshots     , forceOverwrite :: Bool     -- ^ Overwrite existing files@@ -272,8 +276,9 @@         case ar of             ARResolver r -> assert False $ return r             ARGlobal -> do-                stackRoot <- asks $ configStackRoot . getConfig-                let fp = implicitGlobalDir stackRoot </> stackDotYaml+                config <- asks getConfig+                implicitGlobalDir <- getImplicitGlobalProjectDir config+                let fp = implicitGlobalDir </> stackDotYaml                 (ProjectAndConfigMonoid project _, _warnings) <-                     liftIO (Yaml.decodeFileEither $ toFilePath fp)                     >>= either throwM return@@ -290,3 +295,48 @@                      in return $ ResolverSnapshot $ LTS x y     $logInfo $ "Selected resolver: " <> resolverName r     return r++-- | Get the location of the implicit global project directory.+-- If the directory already exists at the deprecated location, its location is returned.+-- Otherwise, the new location is returned.+getImplicitGlobalProjectDir+    :: (MonadIO m, MonadLogger m)+    => Config -> m (Path Abs Dir)+getImplicitGlobalProjectDir config =+    --TEST no warning printed+    liftM fst $ tryDeprecatedPath+        Nothing+        dirExists+        (implicitGlobalProjectDir stackRoot)+        (implicitGlobalProjectDirDeprecated stackRoot)+  where+    stackRoot = configStackRoot config++-- | If deprecated path exists, use it and print a warning.+-- Otherwise, return the new path.+tryDeprecatedPath+    :: (MonadIO m, MonadLogger m)+    => Maybe T.Text -- ^ Description of file for warning (if Nothing, no deprecation warning is displayed)+    -> (Path Abs a -> m Bool) -- ^ Test for existence+    -> Path Abs a -- ^ New path+    -> Path Abs a -- ^ Deprecated path+    -> m (Path Abs a, Bool) -- ^ (Path to use, whether it already exists)+tryDeprecatedPath mWarningDesc exists new old = do+    newExists <- exists new+    if newExists+        then return (new, True)+        else do+            oldExists <- exists old+            if oldExists+                then do+                    case mWarningDesc of+                        Nothing -> return ()+                        Just desc ->+                            $logWarn $ T.concat+                                [ "Warning: Location of ", desc, " at '"+                                , T.pack (toFilePath old)+                                , "' is deprecated; rename it to '"+                                , T.pack (toFilePath new)+                                , "' instead" ]+                    return (old, True)+                else return (new, False)
src/Stack/New.hs view
@@ -60,6 +60,8 @@ data NewOpts = NewOpts     { newOptsProjectName  :: PackageName     -- ^ Name of the project to create.+    , newOptsCreateBare   :: Bool+    -- ^ Whether to create the project without a directory.     , newOptsTemplate     :: TemplateName     -- ^ Name of the template to use.     , newOptsNonceParams  :: Map Text Text@@ -72,13 +74,14 @@     => NewOpts -> m (Path Abs Dir) new opts = do     pwd <- getWorkingDir-    relDir <- parseRelDir (packageNameString (newOptsProjectName opts))-    absDir <- liftM (pwd </>) (return relDir)+    absDir <- if bare then return pwd+                      else do relDir <- parseRelDir (packageNameString project)+                              liftM (pwd </>) (return relDir)     exists <- dirExists absDir-    if exists+    if exists && not bare         then throwM (AlreadyExists absDir)         else do-            logUsing relDir+            logUsing absDir             templateText <- loadTemplate template             files <-                 applyTemplate@@ -93,13 +96,15 @@   where     template = newOptsTemplate opts     project = newOptsProjectName opts-    logUsing relDir =+    bare = newOptsCreateBare opts+    logUsing absDir =         $logInfo             ("Downloading template \"" <> templateName template <>              "\" to create project \"" <>              packageNameText project <>              "\" in " <>-             T.pack (toFilePath relDir) <>+             if bare then "the current directory"+                     else T.pack (toFilePath (dirname absDir)) <>              " ...")  -- | Download and read in a template's text content.@@ -139,7 +144,7 @@                  templateText                  (mkStrContextM (contextFunction context)))     when (not (S.null missingKeys))-         ($logInfo (T.pack (show (MissingParameters project template config missingKeys))))+         ($logInfo (T.pack (show (MissingParameters project template missingKeys (configUserConfigPath config)))))     files :: Map FilePath LB.ByteString <-         execWriterT $         yield (T.encodeUtf8 (LT.toStrict applied)) $$@@ -271,7 +276,7 @@     | BadTemplatesResponse !Int     | BadTemplatesJSON !String !LB.ByteString     | AlreadyExists !(Path Abs Dir)-    | MissingParameters !PackageName !TemplateName !Config !(Set String)+    | MissingParameters !PackageName !TemplateName !(Set String) !(Path Abs File)     deriving (Typeable)  instance Exception NewException@@ -301,13 +306,13 @@     show (BadTemplatesJSON err bytes) =         "Github returned some JSON that couldn't be parsed: " <> err <> "\n\n" <>         L8.unpack bytes-    show (MissingParameters name template config missingKeys) =+    show (MissingParameters name template missingKeys userConfigPath) =         intercalate             "\n"             [ "The following parameters were needed by the template but not provided: " <>               intercalate ", " (S.toList missingKeys)             , "You can provide them in " <>-              toFilePath (globalConfigPath config) <>+              toFilePath userConfigPath <>               ", like this:"             , "templates:"             , "  params:"
src/Stack/Options.hs view
@@ -9,6 +9,7 @@     ,dockerCleanupOptsParser     ,dotOptsParser     ,execOptsParser+    ,evalOptsParser     ,globalOptsParser     ,initOptsParser     ,newOptsParser@@ -22,6 +23,7 @@  import           Control.Monad.Logger (LogLevel(..)) import           Data.Char (isSpace, toLower)+import           Data.List (intercalate) import           Data.List.Split (splitOn) import qualified Data.Map as Map import           Data.Map.Strict (Map)@@ -36,6 +38,7 @@ import           Options.Applicative.Simple import           Options.Applicative.Types (readerAsk) import           Stack.Config (packagesParser)+import           Stack.Constants (stackProgName) import           Stack.Docker import qualified Stack.Docker as Docker import           Stack.Dot@@ -217,7 +220,7 @@ -- | Command-line arguments parser for configuration. configOptsParser :: Bool -> Parser ConfigMonoid configOptsParser docker =-    (\opts systemGHC installGHC arch os ghcVariant jobs includes libs skipGHCCheck skipMsys localBin -> mempty+    (\opts systemGHC installGHC arch os ghcVariant jobs includes libs skipGHCCheck skipMsys localBin modifyCodePage -> mempty         { configMonoidDockerOpts = opts         , configMonoidSystemGHC = systemGHC         , configMonoidInstallGHC = installGHC@@ -230,6 +233,7 @@         , configMonoidExtraLibDirs = libs         , configMonoidSkipMsys = skipMsys         , configMonoidLocalBinPath = localBin+        , configMonoidModifyCodePage = modifyCodePage         })     <$> dockerOptsParser docker     <*> maybeBoolFlags@@ -280,12 +284,16 @@              <> metavar "DIR"              <> help "Install binaries to DIR"               ))+    <*> maybeBoolFlags+            "modify-code-page"+            "setting the codepage to support UTF-8 (Windows only)"+            idm  -- | Options parser configuration for Docker. dockerOptsParser :: Bool -> Parser DockerOptsMonoid dockerOptsParser showOptions =     DockerOptsMonoid-    <$> pure Nothing+    <$> pure False     <*> maybeBoolFlags dockerCmdName                        "using a Docker container"                        hide@@ -341,6 +349,20 @@                         hide <>                         metavar "PATH" <>                         help "Location of image usage tracking database")+    <*> optional (option str+            (long(dockerOptName dockerStackExeArgName) <>+             hide <>+             metavar (intercalate "|"+                          [ dockerStackExeDownloadVal+                          , dockerStackExeHostVal+                          , dockerStackExeImageVal+                          , "PATH" ]) <>+             help (concat [ "Location of "+                          , stackProgName+                          , " executable used in container" ])))+    <*> maybeBoolFlags (dockerOptName dockerSetUserArgName)+                       "setting user in container to match host"+                       hide   where     dockerOptName optName = dockerCmdName ++ "-" ++ T.unpack optName     maybeStrOption = optional . option str@@ -455,18 +477,32 @@     ExecOpts         <$> pure mcmd         <*> eoArgsParser-        <*> (eoPlainParser <|>-             ExecOptsEmbellished-                <$> eoEnvSettingsParser-                <*> eoPackagesParser)+        <*> execOptsExtraParser   where     eoArgsParser :: Parser [String]     eoArgsParser = many (strArgument (metavar meta))       where-        meta =-            (maybe ("CMD ") (const "") mcmd) ++-            "-- ARGS (e.g. stack ghc -- X.hs -o x)"+        meta = (maybe ("CMD ") (const "") mcmd) +++               "-- ARGS (e.g. stack ghc -- X.hs -o x)" +evalOptsParser :: Maybe String -- ^ metavar+               -> Parser EvalOpts+evalOptsParser mmeta =+    EvalOpts+        <$> eoArgsParser+        <*> execOptsExtraParser+  where+    eoArgsParser :: Parser String+    eoArgsParser = strArgument (metavar meta)+    meta = maybe ("CODE") id mmeta++-- | Parser for extra options to exec command+execOptsExtraParser :: Parser ExecOptsExtra+execOptsExtraParser = eoPlainParser <|>+                      ExecOptsEmbellished+                         <$> eoEnvSettingsParser+                         <*> eoPackagesParser+  where     eoEnvSettingsParser :: Parser EnvSettings     eoEnvSettingsParser = EnvSettings         <$> pure True@@ -493,9 +529,9 @@ globalOptsParser :: Bool -> Parser GlobalOpts globalOptsParser defaultTerminal =     GlobalOpts <$>-    switch (long Docker.reExecArgName <>-            hidden <>-            internal) <*>+    optional (strOption (long Docker.reExecArgName <>+                         hidden <>+                         internal)) <*>     logLevelOptsParser <*>     configOptsParser False <*>     optional abstractResolverOptsParser <*>@@ -508,11 +544,7 @@     optional (strOption (long "stack-yaml" <>                          metavar "STACK-YAML" <>                          help ("Override project stack.yaml file " <>-                               "(overrides any STACK_YAML environment variable)"))) <*>-    boolFlags True-        "modify-code-page"-        "setting the codepage to support UTF-8 (Windows only)"-        idm+                               "(overrides any STACK_YAML environment variable)")))  initOptsParser :: Parser InitOpts initOptsParser =@@ -648,6 +680,9 @@         NewOpts <$>         packageNameArgument             (metavar "PACKAGE_NAME" <> help "A valid package name.") <*>+        switch+            (long "bare" <>+             help "Do not create a subdirectory for the project") <*>         templateNameArgument             (metavar "TEMPLATE_NAME" <>              help "Name of a template, for example: foo or foo.hsfiles" <>
src/Stack/Package.hs view
@@ -74,6 +74,7 @@ import           Path.IO import           Prelude import           Safe (headDef, tailSafe)+import           Stack.Build.Installed import           Stack.Constants import           Stack.Types import qualified Stack.Types.PackageIdentifier@@ -194,10 +195,10 @@       [T.pack (exeName b) | b <- executables pkg                           , buildable (buildInfo b)]     , packageOpts = GetPackageOpts $-      \sourceMap locals cabalfp ->+      \sourceMap installedMap locals cabalfp ->            do (componentsModules,componentFiles,_,_) <- getPackageFiles pkgFiles cabalfp               (componentsOpts,generalOpts) <--                  generatePkgDescOpts sourceMap locals cabalfp pkg componentFiles+                  generatePkgDescOpts sourceMap installedMap locals cabalfp pkg componentFiles               return (componentsModules,componentFiles,componentsOpts,generalOpts)     , packageHasExposedModules = maybe           False@@ -227,12 +228,13 @@ generatePkgDescOpts     :: (HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadIO m)     => SourceMap+    -> InstalledMap     -> [PackageName]     -> Path Abs File     -> PackageDescription     -> Map NamedComponent (Set DotCabalPath)     -> m (Map NamedComponent [String],[String])-generatePkgDescOpts sourceMap locals cabalfp pkg componentPaths = do+generatePkgDescOpts sourceMap installedMap locals cabalfp pkg componentPaths = do     distDir <- distDirFromDir cabalDir     let cabalmacros = autogenDir distDir </> $(mkRelFile "cabal_macros.h")     exists <- fileExists cabalmacros@@ -244,6 +246,7 @@             ( namedComponent             , generateBuildInfoOpts                   sourceMap+                  installedMap                   mcabalmacros                   cabalDir                   distDir@@ -283,6 +286,7 @@ -- | Generate GHC options for the target. generateBuildInfoOpts     :: SourceMap+    -> InstalledMap     -> Maybe (Path Abs File)     -> Path Abs Dir     -> Path Abs Dir@@ -291,7 +295,7 @@     -> Set DotCabalPath     -> NamedComponent     -> [String]-generateBuildInfoOpts sourceMap mcabalmacros cabalDir distDir locals b dotCabalPaths componentName =+generateBuildInfoOpts sourceMap installedMap mcabalmacros cabalDir distDir locals b dotCabalPaths componentName =     nubOrd (concat [ghcOpts b, extOpts b, srcOpts, includeOpts, macros, deps, extra b, extraDirs, fworks b, cObjectFiles])   where     cObjectFiles =@@ -301,8 +305,10 @@     cfiles = mapMaybe dotCabalCFilePath (S.toList dotCabalPaths)     deps =         concat-            [ ["-package=" <> display name <>-               maybe "" -- This empty case applies to e.g. base.+            [ case M.lookup (fromCabalPackageName name) installedMap of+                Just (_, _, Stack.Types.Library _ident ipid) -> ["-package-id=" <> ghcPkgIdString ipid]+                _ -> ["-package=" <> display name <>+                 maybe "" -- This empty case applies to e.g. base.                      ((("-" <>) . versionString) . sourceVersion)                      (M.lookup (fromCabalPackageName name) sourceMap)]             | Dependency name _ <- targetBuildDepends b
src/Stack/PackageDump.hs view
@@ -42,7 +42,6 @@ import qualified Data.Conduit.Binary as CB import qualified Data.Conduit.List as CL import           Data.Either (partitionEithers)-import qualified Data.Foldable as F import           Data.IORef import           Data.Map (Map) import qualified Data.Map as Map@@ -81,18 +80,20 @@     :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, MonadCatch m, MonadThrow m)     => EnvOverride     -> WhichCompiler-    -> Maybe (Path Abs Dir) -- ^ if Nothing, use global+    -> [Path Abs Dir] -- ^ if empty, use global     -> Sink ByteString IO a     -> m a-ghcPkgDump menv wc mpkgDb sink = do-    F.mapM_ (createDatabase menv wc) mpkgDb -- TODO maybe use some retry logic instead?+ghcPkgDump menv wc mpkgDbs sink = do+    case reverse mpkgDbs of+        (pkgDb:_) -> (createDatabase menv wc) pkgDb -- TODO maybe use some retry logic instead?+        _ -> return ()     a <- sinkProcessStdout Nothing menv (ghcPkgExeName wc) args sink     return a   where     args = concat-        [ case mpkgDb of-            Nothing -> ["--global", "--no-user-package-db"]-            Just pkgdb -> ["--user", "--no-user-package-db", "--package-db", toFilePath pkgdb]+        [ case mpkgDbs of+            [] -> ["--global", "--no-user-package-db"]+            _ -> ["--user", "--no-user-package-db"] ++ concatMap (\pkgDb -> ["--package-db", toFilePath pkgDb]) mpkgDbs         , ["dump", "--expand-pkgroot"]         ] 
src/Stack/SDist.hs view
@@ -39,6 +39,7 @@ import           Distribution.Version.Extra import           Network.HTTP.Client.Conduit (HasHttpManager) import           Path+import           Path.IO import           Prelude -- Fix redundant import warnings import           Stack.Build (mkBaseConfigOpts) import           Stack.Build.Execute@@ -50,7 +51,6 @@ import           Stack.Types import           Stack.Types.Internal import qualified System.FilePath as FP-import           System.IO.Temp (withSystemTempDirectory)  type M env m = (MonadIO m,MonadReader env m,HasHttpManager env,MonadLogger m,MonadBaseControl IO m,MonadMask m,HasLogLevel env,HasEnvConfig env,HasTerminal env) @@ -179,7 +179,7 @@         , lpTestDeps = Map.empty         , lpBenchDeps = Map.empty         , lpTestBench = Nothing-        , lpDirtyFiles = True+        , lpDirtyFiles = Just Set.empty         , lpNewBuildCache = Map.empty         , lpFiles = Set.empty         , lpComponents = Set.empty@@ -188,7 +188,7 @@ -- | Returns a newline-separate list of paths, and the absolute path to the .cabal file. getSDistFileList :: M env m => LocalPackage -> m (String, Path Abs File) getSDistFileList lp =-    withSystemTempDirectory (stackProgName <> "-sdist") $ \tmpdir -> do+    withCanonicalizedSystemTempDirectory (stackProgName <> "-sdist") $ \tmpdir -> do         menv <- getMinimalEnvOverride         let bopts = defaultBuildOpts         baseConfigOpts <- mkBaseConfigOpts bopts@@ -198,7 +198,7 @@             [] -- provide empty list of globals. This is a hack around custom Setup.hs files             sourceMap $ \ee -> do             withSingleContext runInBase ac ee task Nothing (Just "sdist") $ \_package cabalfp _pkgDir cabal _announce _console _mlogFile -> do-                let outFile = tmpdir FP.</> "source-files-list"+                let outFile = toFilePath tmpdir FP.</> "source-files-list"                 cabal False ["sdist", "--list-sources", outFile]                 contents <- liftIO (readFile outFile)                 return (contents, cabalfp)
src/Stack/Setup.hs view
@@ -13,7 +13,8 @@  module Stack.Setup   ( setupEnv-  , ensureGHC+  , ensureCompiler+  , ensureDockerStackExe   , SetupOpts (..)   , defaultStackSetupYaml   ) where@@ -31,11 +32,14 @@ import           Data.Aeson.Extended import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy as LBS+import           Data.Char (isSpace) import           Data.Conduit (Conduit, ($$), (=$), await, yield, awaitForever)+import qualified Data.Conduit.Binary as CB import           Data.Conduit.Lift (evalStateC) import qualified Data.Conduit.List as CL import           Data.Either-import           Data.Foldable hiding (concatMap, or)+import           Data.Foldable hiding (concatMap, or, maximum) import           Data.IORef import           Data.IORef.RunOnce (runOnce) import           Data.List hiding (concat, elem, maximumBy)@@ -56,18 +60,19 @@ import           Distribution.System (OS, Arch (..), Platform (..)) import qualified Distribution.System as Cabal import           Distribution.Text (simpleParse)+import           Language.Haskell.TH as TH import           Network.HTTP.Client.Conduit import           Network.HTTP.Download.Verified import           Path import           Path.IO+import qualified Paths_stack as Meta import           Prelude hiding (concat, elem) -- Fix AMP warning import           Safe (readMay)-import           Stack.Types.Build import           Stack.Config (resolvePackageEntry)-import           Stack.Constants (distRelativeDir)+import           Stack.Constants (distRelativeDir, stackProgName) import           Stack.Fetch import           Stack.GhcPkg (createDatabase, getCabalPkgVer, getGlobalDB, mkGhcPackagePath)-import           Stack.Solver (getCompilerVersion)+import           Stack.Setup.Installed import           Stack.Types import           Stack.Types.StackT import qualified System.Directory as D@@ -75,11 +80,9 @@ import           System.Exit (ExitCode (ExitSuccess)) import           System.FilePath (searchPathSeparator) import qualified System.FilePath as FP-import           System.IO.Temp (withSystemTempDirectory) import           System.Process (rawSystem) import           System.Process.Read import           System.Process.Run (runIn)-import           System.IO.Temp (withTempDirectory) import           Text.Printf (printf)  -- | Default location of the stack-setup.yaml file@@ -114,13 +117,16 @@     deriving Show data SetupException = UnsupportedSetupCombo OS Arch                     | MissingDependencies [String]-                    | UnknownCompilerVersion Text CompilerVersion (Set Version)+                    | UnknownCompilerVersion Text CompilerVersion [CompilerVersion]                     | UnknownOSKey Text                     | GHCSanityCheckCompileFailed ReadProcessException (Path Abs File)                     | WantedMustBeGHC                     | RequireCustomGHCVariant                     | ProblemWhileDecompressing (Path Abs File)                     | SetupInfoMissingSevenz+                    | GHCJSRequiresStandardVariant+                    | GHCJSNotBooted+                    | DockerStackExeNotFound Version Text     deriving Typeable instance Exception SetupException instance Show SetupException where@@ -134,9 +140,9 @@         intercalate ", " tools     show (UnknownCompilerVersion oskey wanted known) = concat         [ "No information found for "-        , T.unpack (compilerVersionName wanted)+        , compilerVersionString wanted         , ".\nSupported versions for OS key '" ++ T.unpack oskey ++ "': "-        , intercalate ", " (map show $ Set.toList known)+        , intercalate ", " (map show known)         ]     show (UnknownOSKey oskey) =         "Unable to find installation URLs for OS key: " ++@@ -145,7 +151,7 @@         [ "The GHC located at "         , toFilePath ghc         , " failed to compile a sanity check. Please see:\n\n"-        , "    https://github.com/commercialhaskell/stack/blob/master/doc/install_and_upgrade.md\n\n"+        , "    https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md\n\n"         , "for more information. Exception was:\n"         , show e         ]@@ -157,6 +163,19 @@         "Problem while decompressing " ++ toFilePath archive     show SetupInfoMissingSevenz =         "SetupInfo missing Sevenz EXE/DLL"+    show GHCJSRequiresStandardVariant =+        "stack does not yet support using --ghc-variant with GHCJS"+    show GHCJSNotBooted =+        "GHCJS does not yet have its boot packages installed.  Use \"stack setup\" to attempt to run ghcjs-boot."+    show (DockerStackExeNotFound stackVersion osKey) = concat+        [ stackProgName+        , "-"+        , versionString stackVersion+        , " executable not found for "+        , T.unpack osKey+        , "\nUse the '"+        , T.unpack dockerStackExeArgName+        , "' option to specify a location"]  -- | Modify the environment variables (like PATH) appropriately, possibly doing installation too setupEnv :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasBuildConfig env, HasHttpManager env, HasGHCVariant env, MonadBaseControl IO m)@@ -182,7 +201,7 @@             , soptsGHCBindistURL = Nothing             } -    mghcBin <- ensureGHC sopts+    mghcBin <- ensureCompiler sopts      -- Modify the initial environment to include the GHC path, if a local GHC     -- is being used@@ -287,23 +306,11 @@         (Set.fromList $ map T.pack libs)     } -data ExtraDirs = ExtraDirs-    { edBins :: ![FilePath]-    , edInclude :: ![FilePath]-    , edLib :: ![FilePath]-    }-instance Monoid ExtraDirs where-    mempty = ExtraDirs [] [] []-    mappend (ExtraDirs a b c) (ExtraDirs x y z) = ExtraDirs-        (a ++ x)-        (b ++ y)-        (c ++ z)---- | Ensure GHC is installed and provide the PATHs to add if necessary-ensureGHC :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, HasGHCVariant env, MonadBaseControl IO m)-          => SetupOpts-          -> m (Maybe ExtraDirs)-ensureGHC sopts = do+-- | Ensure compiler (ghc or ghcjs) is installed and provide the PATHs to add if necessary+ensureCompiler :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, HasGHCVariant env, MonadBaseControl IO m)+               => SetupOpts+               -> m (Maybe ExtraDirs)+ensureCompiler sopts = do     let wc = whichCompiler (soptsWantedCompiler sopts)     when (getGhcVersion (soptsWantedCompiler sopts) < $(mkVersion "7.8")) $ do         $logWarn "stack will almost certainly fail with GHC below version 7.8"@@ -330,9 +337,9 @@         isWanted = isWantedCompiler (soptsCompilerCheck sopts) (soptsWantedCompiler sopts)      -- If we need to install a GHC, try to do so-    mpaths <- if needLocal+    mtools <- if needLocal         then do-            getSetupInfo' <- runOnce (getSetupInfo sopts =<< asks getHttpManager)+            getSetupInfo' <- runOnce (getSetupInfo (soptsStackSetupYaml sopts) =<< asks getHttpManager)              installed <- listInstalled @@ -340,12 +347,16 @@             ghcVariant <- asks getGHCVariant             config <- asks getConfig             ghcPkgName <- parsePackageNameFromString ("ghc" ++ ghcVariantSuffix ghcVariant)-            ghcIdent <- case getInstalledTool installed ghcPkgName (isWanted . GhcVersion) of-                Just ident -> return ident+            let installedCompiler =+                    case wc of+                        Ghc -> getInstalledTool installed ghcPkgName (isWanted . GhcVersion)+                        Ghcjs -> getInstalledGhcjs installed isWanted+            compilerTool <- case installedCompiler of+                Just tool -> return tool                 Nothing                     | soptsInstallIfMissing sopts -> do                         si <- getSetupInfo'-                        downloadAndInstallGHC+                        downloadAndInstallCompiler                             si                             (soptsWantedCompiler sopts)                             (soptsCompilerCheck sopts)@@ -364,51 +375,91 @@              -- Install msys2 on windows, if necessary             platform <- asks getPlatform-            mmsys2Ident <- case platform of+            mmsys2Tool <- case platform of                 Platform _ Cabal.Windows | not (soptsSkipMsys sopts) ->                     case getInstalledTool installed $(mkPackageName "msys2") (const True) of-                        Just ident -> return (Just ident)+                        Just tool -> return (Just tool)                         Nothing                             | soptsInstallIfMissing sopts -> do                                 si <- getSetupInfo'-                                osKey <- getOSKey+                                osKey <- getOSKey platform                                 VersionedDownloadInfo version info <-                                     case Map.lookup osKey $ siMsys2 si of                                         Just x -> return x                                         Nothing -> error $ "MSYS2 not found for " ++ T.unpack osKey-                                Just <$> downloadAndInstallTool si info $(mkPackageName "msys2") version (installMsys2Windows osKey)+                                let tool = Tool (PackageIdentifier $(mkPackageName "msys2") version)+                                Just <$> downloadAndInstallTool (configLocalPrograms config) si info tool (installMsys2Windows osKey)                             | otherwise -> do                                 $logWarn "Continuing despite missing tool: msys2"                                 return Nothing                 _ -> return Nothing -            let idents = catMaybes [Just ghcIdent, mmsys2Ident]+            return $ Just (compilerTool, mmsys2Tool)+        else return Nothing++    mpaths <- case mtools of+        Nothing -> return Nothing+        Just (compilerTool, mmsys2Tool) -> do+            let idents = catMaybes [Just compilerTool, mmsys2Tool]             paths <- mapM extraDirs idents             return $ Just $ mconcat paths-        else return Nothing      menv <-         case mpaths of             Nothing -> return menv0             Just ed -> do                 config <- asks getConfig-                let m0 = unEnvOverride menv0-                    path0 = Map.lookup "PATH" m0-                    path = augmentPath (edBins ed) path0-                    m = Map.insert "PATH" path m0+                let m = augmentPathMap (edBins ed) (unEnvOverride menv0)                 mkEnvOverride (configPlatform config) (removeHaskellEnvVars m)      when (soptsUpgradeCabal sopts) $ do         unless needLocal $ do             $logWarn "Trying to upgrade Cabal library on a GHC not installed by stack."             $logWarn "This may fail, caveat emptor!"-         upgradeCabal menv wc -    when (soptsSanityCheck sopts) $ sanityCheck menv+    case mtools of+        Just (ToolGhcjs cv, _) -> ensureGhcjsBooted menv cv (soptsInstallIfMissing sopts)+        _ -> return () +    when (soptsSanityCheck sopts) $ sanityCheck menv wc+     return mpaths +-- Ensure Docker container-compatible 'stack' executable is downloaded+ensureDockerStackExe+    :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+    => Platform -> m (Path Abs File)+ensureDockerStackExe containerPlatform = do+    config <- asks getConfig+    containerPlatformDir <- runReaderT platformOnlyRelDir containerPlatform+    let programsPath = configLocalProgramsBase config </> containerPlatformDir+        stackVersion = fromCabalVersion Meta.version+        tool = Tool (PackageIdentifier $(mkPackageName "stack") stackVersion)+    stackExePath <- (</> $(mkRelFile "stack")) <$> installDir programsPath tool+    stackExeExists <- fileExists stackExePath+    unless stackExeExists $+        do+           $logInfo $ mconcat ["Downloading Docker-compatible ", T.pack stackProgName, " executable"]+           si <- getSetupInfo defaultStackSetupYaml =<< asks getHttpManager+           osKey <- getOSKey containerPlatform+           info <-+               case Map.lookup osKey (siStack si) of+                   Just versions ->+                       case Map.lookup stackVersion versions of+                           Just x -> return x+                           Nothing -> throwM (DockerStackExeNotFound stackVersion osKey)+                   Nothing -> throwM (DockerStackExeNotFound stackVersion osKey)+           _ <-+               downloadAndInstallTool+                   programsPath+                   si+                   info+                   tool+                   installDockerStackExe+           return ()+    return stackExePath+ -- | Install the newest version of Cabal globally upgradeCabal :: (MonadIO m, MonadLogger m, MonadReader env m, HasHttpManager env, HasConfig env, MonadBaseControl IO m, MonadMask m)              => EnvOverride@@ -432,16 +483,15 @@             , T.pack $ versionString newest             , ". I'm not upgrading Cabal."             ]-        else withSystemTempDirectory "stack-cabal-upgrade" $ \tmpdir -> do+        else withCanonicalizedSystemTempDirectory "stack-cabal-upgrade" $ \tmpdir -> do             $logInfo $ T.concat                 [ "Installing Cabal-"                 , T.pack $ versionString newest                 , " to replace "                 , T.pack $ versionString installed                 ]-            tmpdir' <- parseAbsDir tmpdir             let ident = PackageIdentifier name newest-            m <- unpackPackageIdents menv tmpdir' Nothing (Set.singleton ident)+            m <- unpackPackageIdents menv tmpdir Nothing (Set.singleton ident)              compilerPath <- join $ findExecutable menv (compilerExeName wc)             newestDir <- parseRelDir $ versionString newest@@ -504,16 +554,15 @@ -- | Download the most recent SetupInfo getSetupInfo     :: (MonadIO m, MonadThrow m, MonadLogger m, MonadReader env m, HasConfig env)-    => SetupOpts -> Manager -> m SetupInfo-getSetupInfo sopts manager = do+    => String -> Manager -> m SetupInfo+getSetupInfo stackSetupYaml manager = do     config <- asks getConfig     setupInfos <-         mapM             loadSetupInfo-            (SetupInfoFileOrURL (soptsStackSetupYaml sopts) :+            (SetupInfoFileOrURL stackSetupYaml :              configSetupInfoLocations config)-    return-        (mconcat setupInfos)+    return (mconcat setupInfos)   where     loadSetupInfo (SetupInfoInline si) = return si     loadSetupInfo (SetupInfoFileOrURL urlOrFile) = do@@ -529,121 +578,61 @@                     return $ S8.concat bss                 Nothing -> liftIO $ S.readFile urlOrFile         (si,warnings) <- either throwM return (Yaml.decodeEither' bs)-        logJSONWarnings urlOrFile warnings+        when (urlOrFile /= defaultStackSetupYaml) $+            logJSONWarnings urlOrFile warnings         return si -markInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)-              => PackageIdentifier -- ^ e.g., ghc-7.8.4, msys2-20150512-              -> m ()-markInstalled ident = do-    dir <- asks $ configLocalPrograms . getConfig-    fpRel <- parseRelFile $ packageIdentifierString ident ++ ".installed"-    liftIO $ writeFile (toFilePath $ dir </> fpRel) "installed"--unmarkInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)-                => PackageIdentifier-                -> m ()-unmarkInstalled ident = do-    dir <- asks $ configLocalPrograms . getConfig-    fpRel <- parseRelFile $ packageIdentifierString ident ++ ".installed"-    removeFileIfExists $ dir </> fpRel--listInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)-              => m [PackageIdentifier]-listInstalled = do-    dir <- asks $ configLocalPrograms . getConfig-    createTree dir-    (_, files) <- listDirectory dir-    return $ mapMaybe toIdent files-  where-    toIdent fp = do-        x <- T.stripSuffix ".installed" $ T.pack $ toFilePath $ filename fp-        parsePackageIdentifierFromString $ T.unpack x--installDir :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m)-           => PackageIdentifier-           -> m (Path Abs Dir)-installDir ident = do-    config <- asks getConfig-    reldir <- parseRelDir $ packageIdentifierString ident-    return $ configLocalPrograms config </> reldir---- | Binary directories for the given installed package-extraDirs :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m)-          => PackageIdentifier-          -> m ExtraDirs-extraDirs ident = do-    platform <- asks getPlatform-    dir <- installDir ident-    case (platform, packageNameString $ packageIdentifierName ident) of-        (Platform _ Cabal.Windows, isGHC -> True) -> return mempty-            { edBins = goList-                [ dir </> $(mkRelDir "bin")-                , dir </> $(mkRelDir "mingw") </> $(mkRelDir "bin")-                ]-            }-        (Platform _ Cabal.Windows, "msys2") -> return mempty-            { edBins = goList-                [ dir </> $(mkRelDir "usr") </> $(mkRelDir "bin")-                ]-            , edInclude = goList-                [ dir </> $(mkRelDir "mingw64") </> $(mkRelDir "include")-                , dir </> $(mkRelDir "mingw32") </> $(mkRelDir "include")-                ]-            , edLib = goList-                [ dir </> $(mkRelDir "mingw64") </> $(mkRelDir "lib")-                , dir </> $(mkRelDir "mingw32") </> $(mkRelDir "lib")-                ]-            }-        (_, isGHC -> True) -> return mempty-            { edBins = goList-                [ dir </> $(mkRelDir "bin")-                ]-            }-        (Platform _ x, tool) -> do-            $logWarn $ "binDirs: unexpected OS/tool combo: " <> T.pack (show (x, tool))-            return mempty+getInstalledTool :: [Tool]            -- ^ already installed+                 -> PackageName       -- ^ package to find+                 -> (Version -> Bool) -- ^ which versions are acceptable+                 -> Maybe Tool+getInstalledTool installed name goodVersion =+    if null available+        then Nothing+        else Just $ Tool $ maximumBy (comparing packageIdentifierVersion) available   where-    goList = map toFilePathNoTrailingSlash-    isGHC n = "ghc" == n || "ghc-" `isPrefixOf` n+    available = mapMaybe goodPackage installed+    goodPackage (Tool pi') =+        if packageIdentifierName pi' == name &&+           goodVersion (packageIdentifierVersion pi')+            then Just pi'+            else Nothing+    goodPackage _ = Nothing -getInstalledTool :: [PackageIdentifier] -- ^ already installed-                 -> PackageName         -- ^ package to find-                 -> (Version -> Bool)   -- ^ which versions are acceptable-                 -> Maybe PackageIdentifier-getInstalledTool installed name goodVersion =+getInstalledGhcjs :: [Tool]+                  -> (CompilerVersion -> Bool)+                  -> Maybe Tool+getInstalledGhcjs installed goodVersion =     if null available         then Nothing-        else Just $ maximumBy (comparing packageIdentifierVersion) available+        else Just $ ToolGhcjs $ maximum available   where-    available = filter goodPackage installed-    goodPackage pi' =-        packageIdentifierName pi' == name &&-        goodVersion (packageIdentifierVersion pi')+    available = mapMaybe goodPackage installed+    goodPackage (ToolGhcjs cv) = if goodVersion cv then Just cv else Nothing+    goodPackage _ = Nothing  downloadAndInstallTool :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)-                       => SetupInfo+                       => Path Abs Dir+                       -> SetupInfo                        -> DownloadInfo-                       -> PackageName-                       -> Version-                       -> (SetupInfo -> Path Abs File -> ArchiveType -> Path Abs Dir -> PackageIdentifier -> m ())-                       -> m PackageIdentifier-downloadAndInstallTool si downloadInfo name version installer = do-    let ident = PackageIdentifier name version-    (file, at) <- downloadFromInfo downloadInfo ident-    dir <- installDir ident-    unmarkInstalled ident-    installer si file at dir ident-    markInstalled ident-    return ident+                       -> Tool+                       -> (SetupInfo -> Path Abs File -> ArchiveType -> Path Abs Dir -> m ())+                       -> m Tool+downloadAndInstallTool programsDir si downloadInfo tool installer = do+    (file, at) <- downloadFromInfo programsDir downloadInfo tool+    dir <- installDir programsDir tool+    unmarkInstalled tool+    installer si file at dir+    markInstalled tool+    return tool -downloadAndInstallGHC :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasGHCVariant env, HasHttpManager env, MonadBaseControl IO m)-           => SetupInfo-           -> CompilerVersion-           -> VersionCheck-           -> (Maybe String)-           -> m PackageIdentifier-downloadAndInstallGHC si wanted versionCheck mbindistURL = do+downloadAndInstallCompiler :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasGHCVariant env, HasHttpManager env, MonadBaseControl IO m)+                           => SetupInfo+                           -> CompilerVersion+                           -> VersionCheck+                           -> (Maybe String)+                           -> m Tool+downloadAndInstallCompiler si wanted@(GhcVersion{}) versionCheck mbindistURL = do     ghcVariant <- asks getGHCVariant     (selectedVersion, downloadInfo) <- case mbindistURL of         Just bindistURL -> do@@ -657,22 +646,14 @@                     throwM WantedMustBeGHC         _ -> do             ghcKey <- getGhcKey-            pairs <--                case Map.lookup ghcKey $ siGHCs si of-                    Nothing -> throwM $ UnknownOSKey ghcKey-                    Just pairs -> return pairs-            let mpair =-                    listToMaybe $-                    sortBy (flip (comparing fst)) $-                    filter (\(v, _) -> isWantedCompiler versionCheck wanted (GhcVersion v)) (Map.toList pairs)-            case mpair of-                Just pair -> return pair-                Nothing -> throwM $ UnknownCompilerVersion ghcKey wanted (Map.keysSet pairs)-    platform <- asks getPlatform+            case Map.lookup ghcKey $ siGHCs si of+                Nothing -> throwM $ UnknownOSKey ghcKey+                Just pairs -> getWantedCompilerInfo ghcKey versionCheck wanted GhcVersion pairs+    config <- asks getConfig     let installer =-            case platform of-                Platform _ Cabal.Windows -> installGHCWindows-                _ -> installGHCPosix+            case configPlatform config of+                Platform _ Cabal.Windows -> installGHCWindows selectedVersion+                _ -> installGHCPosix selectedVersion     $logInfo $         "Preparing to install GHC" <>         (case ghcVariant of@@ -681,19 +662,49 @@         " to an isolated location."     $logInfo "This will not interfere with any system-level installation."     ghcPkgName <- parsePackageNameFromString ("ghc" ++ ghcVariantSuffix ghcVariant)-    downloadAndInstallTool si downloadInfo ghcPkgName selectedVersion installer+    let tool = Tool $ PackageIdentifier ghcPkgName selectedVersion+    downloadAndInstallTool (configLocalPrograms config) si downloadInfo tool installer+downloadAndInstallCompiler si wanted@(GhcjsVersion version _) versionCheck _mbindistUrl = do+    config <- asks getConfig+    ghcVariant <- asks getGHCVariant+    case ghcVariant of+        GHCStandard -> return ()+        _ -> throwM GHCJSRequiresStandardVariant+    (selectedVersion, downloadInfo) <- case Map.lookup "source" $ siGHCJSs si of+        Nothing -> throwM $ UnknownOSKey "source"+        Just pairs -> getWantedCompilerInfo "source" versionCheck wanted id pairs+    $logInfo "Preparing to install GHCJS to an isolated location."+    $logInfo "This will not interfere with any system-level installation."+    downloadAndInstallTool (configLocalPrograms config) si downloadInfo (ToolGhcjs selectedVersion) (installGHCJS version) +getWantedCompilerInfo :: (Ord k, MonadThrow m)+                      => Text+                      -> VersionCheck+                      -> CompilerVersion+                      -> (k -> CompilerVersion)+                      -> Map k a+                      -> m (k, a)+getWantedCompilerInfo key versionCheck wanted toCV pairs = do+    case mpair of+        Just pair -> return pair+        Nothing -> throwM $ UnknownCompilerVersion key wanted (map toCV (Map.keys pairs))+  where+    mpair =+        listToMaybe $+        sortBy (flip (comparing fst)) $+        filter (isWantedCompiler versionCheck wanted . toCV . fst) (Map.toList pairs)+ getGhcKey :: (MonadReader env m, MonadThrow m, HasPlatform env, HasGHCVariant env, MonadLogger m, MonadIO m, MonadCatch m, MonadBaseControl IO m)-         => m Text+          => m Text getGhcKey = do     ghcVariant <- asks getGHCVariant-    osKey <- getOSKey+    platform <- asks getPlatform+    osKey <- getOSKey platform     return $ osKey <> T.pack (ghcVariantSuffix ghcVariant)  getOSKey :: (MonadReader env m, MonadThrow m, HasPlatform env, MonadLogger m, MonadIO m, MonadCatch m, MonadBaseControl IO m)-         => m Text-getOSKey = do-    platform <- asks getPlatform+         => Platform -> m Text+getOSKey platform = do     case platform of         Platform I386   Cabal.Linux   -> return "linux32"         Platform X86_64 Cabal.Linux   -> return "linux64"@@ -707,21 +718,20 @@         Platform X86_64 Cabal.Windows -> return "windows64"         Platform arch os -> throwM $ UnsupportedSetupCombo os arch -downloadFromInfo :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)-             => DownloadInfo-             -> PackageIdentifier-             -> m (Path Abs File, ArchiveType)-downloadFromInfo downloadInfo ident = do-    config <- asks getConfig+downloadFromInfo+    :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+    => Path Abs Dir -> DownloadInfo -> Tool -> m (Path Abs File, ArchiveType)+downloadFromInfo programsDir downloadInfo tool = do     at <-         case extension of             ".tar.xz" -> return TarXz             ".tar.bz2" -> return TarBz2+            ".tar.gz" -> return TarGz             ".7z.exe" -> return SevenZ-            _ -> error $ "Unknown extension: " ++ extension-    relfile <- parseRelFile $ packageIdentifierString ident ++ extension-    let path = configLocalPrograms config </> relfile-    chattyDownload (packageIdentifierText ident) downloadInfo path+            _ -> error $ "Unknown extension for url: " ++ T.unpack url+    relfile <- parseRelFile $ toolString tool ++ extension+    let path = programsDir </> relfile+    chattyDownload (T.pack (toolString tool)) downloadInfo path     return (path, at)   where     url = downloadInfoUrl downloadInfo@@ -729,7 +739,7 @@         loop $ T.unpack url       where         loop fp-            | ext `elem` [".tar", ".bz2", ".xz", ".exe", ".7z"] = loop fp' ++ ext+            | ext `elem` [".tar", ".bz2", ".xz", ".exe", ".7z", ".gz"] = loop fp' ++ ext             | otherwise = ""           where             (fp', ext) = FP.splitExtension fp@@ -737,16 +747,17 @@ data ArchiveType     = TarBz2     | TarXz+    | TarGz     | SevenZ  installGHCPosix :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)-                => SetupInfo+                => Version+                -> SetupInfo                 -> Path Abs File                 -> ArchiveType                 -> Path Abs Dir-                -> PackageIdentifier                 -> m ()-installGHCPosix _ archiveFile archiveType destDir ident = do+installGHCPosix version _ archiveFile archiveType destDir = do     platform <- asks getPlatform     menv0 <- getMinimalEnvOverride     menv <- mkEnvOverride platform (removeHaskellEnvVars (unEnvOverride menv0))@@ -755,6 +766,7 @@         case archiveType of             TarXz -> return "xz"             TarBz2 -> return "bzip2"+            TarGz -> return "gzip"             SevenZ -> error "Don't know how to deal with .7z files on non-Windows"     (zipTool, makeTool, tarTool) <- checkDependencies $ (,,)         <$> checkDependency zipTool'@@ -765,12 +777,11 @@     $logDebug $ "make: " <> T.pack makeTool     $logDebug $ "tar: " <> T.pack tarTool -    withSystemTempDirectory "stack-setup" $ \root' -> do-        root <- parseAbsDir root'+    withCanonicalizedSystemTempDirectory "stack-setup" $ \root -> do         dir <-             liftM (root Path.</>) $             parseRelDir $-            "ghc-" ++ versionString (packageIdentifierVersion ident)+            "ghc-" ++ versionString version          $logSticky $ T.concat ["Unpacking GHC into ", (T.pack . toFilePath $ root), " ..."]         $logDebug $ "Unpacking " <> T.pack (toFilePath archiveFile)@@ -785,15 +796,198 @@          $logStickyDone $ "Installed GHC."         $logDebug $ "GHC installed to " <> T.pack (toFilePath destDir)-  where-    -- | Check if given processes appear to be present, throwing an exception if-    -- missing.-    checkDependencies :: (MonadIO m, MonadThrow m, MonadReader env m, HasConfig env)-                      => CheckDependency a -> m a-    checkDependencies (CheckDependency f) = do-        menv <- getMinimalEnvOverride-        liftIO (f menv) >>= either (throwM . MissingDependencies) return +installGHCJS :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+             => Version+             -> SetupInfo+             -> Path Abs File+             -> ArchiveType+             -> Path Abs Dir+             -> m ()+installGHCJS version si archiveFile archiveType destDir = do+    platform <- asks getPlatform+    menv0 <- getMinimalEnvOverride+    -- This ensures that locking is disabled for the invocations of+    -- stack below.+    let removeLockVar = Map.delete "STACK_LOCK"+    menv <- mkEnvOverride platform (removeLockVar (removeHaskellEnvVars (unEnvOverride menv0)))+    $logDebug $ "menv = " <> T.pack (show (unEnvOverride menv))++    -- NOTE: this is a bit of a hack - instead of using a temp+    -- directory, leave the unpacked source tarball in the destination+    -- directory. This way, the absolute paths in the wrapper scripts+    -- will point to executables that exist in+    -- src/.stack-work/install/... - see+    -- https://github.com/commercialhaskell/stack/issues/1016+    --+    -- This is also used by 'ensureGhcjsBooted', because it can use the+    -- environment of the stack.yaml which came with ghcjs, in order to+    -- install cabal-install. This lets us also fix the version of+    -- cabal-install used.+    let unpackDir = destDir Path.</> $(mkRelDir "src")+    tarComponent <- parseRelDir ("ghcjs-" ++ versionString version)+    runUnpack <- case platform of+        Platform _ Cabal.Windows -> return $ do+            withUnpackedTarball7z "GHCJS" si archiveFile archiveType tarComponent unpackDir+        _ -> do+            zipTool' <-+                case archiveType of+                    TarXz -> return "xz"+                    TarBz2 -> return "bzip2"+                    TarGz -> return "gzip"+                    SevenZ -> error "Don't know how to deal with .7z files on non-Windows"+            (zipTool, tarTool) <- checkDependencies $ (,)+                <$> checkDependency zipTool'+                <*> checkDependency "tar"+            $logDebug $ "ziptool: " <> T.pack zipTool+            $logDebug $ "tar: " <> T.pack tarTool+            return $ do+                removeTreeIfExists unpackDir+                readInNull destDir tarTool menv ["xf", toFilePath archiveFile] Nothing+                renameDir (destDir Path.</> tarComponent) unpackDir++    $logSticky $ T.concat ["Unpacking GHCJS into ", (T.pack . toFilePath $ unpackDir), " ..."]+    $logDebug $ "Unpacking " <> T.pack (toFilePath archiveFile)+    runUnpack++    $logSticky "Installing GHCJS (this will take a long time) ..."+    let destBinDir = destDir Path.</> $(mkRelDir "bin")+    stackPath <- liftIO getExecutablePath+    createTree destBinDir+    runAndLog (Just unpackDir) stackPath menv+        [ "--install-ghc"+        , "--stack-yaml"+        , toFilePath (unpackDir </> $(mkRelFile "stack.yaml"))+        , "--local-bin-path"+        , toFilePath destBinDir+        , "install"+        , "-v"+        ]+    $logStickyDone "Installed GHCJS."++-- Install the downloaded stack binary distribution+installDockerStackExe+    :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+    => SetupInfo+    -> Path Abs File+    -> ArchiveType+    -> Path Abs Dir+    -> m ()+installDockerStackExe _ archiveFile _ destDir = do+    (_,tarTool) <-+        checkDependencies $+        (,) <$> checkDependency "gzip" <*> checkDependency "tar"+    menv <- getMinimalEnvOverride+    createTree destDir+    readInNull+        destDir+        tarTool+        menv+        ["xf", toFilePath archiveFile, "--strip-components", "1"]+        Nothing++ensureGhcjsBooted :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+                  => EnvOverride -> CompilerVersion -> Bool -> m ()+ensureGhcjsBooted menv cv shouldBoot  = do+    eres <- try $ sinkProcessStdout Nothing menv "ghcjs" [] (return ())+    case eres of+        Right () -> return ()+        Left (ReadProcessException _ _ _ err) | "no input files" `S.isInfixOf` LBS.toStrict err ->+            return ()+        Left (ReadProcessException _ _ _ err) | "ghcjs_boot.completed" `S.isInfixOf` LBS.toStrict err ->+            if not shouldBoot then throwM GHCJSNotBooted else do+                config <- asks getConfig+                destDir <- installDir (configLocalPrograms config) (ToolGhcjs cv)+                let stackYaml = destDir </> $(mkRelFile "src/stack.yaml")+                -- TODO: Remove 'actualStackYaml' and just use+                -- 'stackYaml' for a version after 0.1.6. It's for+                -- compatibility with the directories setup used for+                -- most of the life of the development branch between+                -- 0.1.5 and 0.1.6. See+                -- https://github.com/commercialhaskell/stack/issues/749#issuecomment-147382783+                -- This only affects the case where GHCJS has been+                -- installed with an older version and not yet booted.+                stackYamlExists <- fileExists stackYaml+                actualStackYaml <- if stackYamlExists then return stackYaml+                    else case cv of+                        GhcjsVersion version _ ->+                            liftM ((destDir Path.</> $(mkRelDir "src")) Path.</>) $+                            parseRelFile $ "ghcjs-" ++ versionString version ++ "/stack.yaml"+                        _ -> fail "ensureGhcjsBooted invoked on non GhcjsVersion"+                actualStackYamlExists <- fileExists actualStackYaml+                when (not actualStackYamlExists) $+                    fail "Couldn't find GHCJS stack.yaml in old or new location."+                bootGhcjs menv actualStackYaml+        Left err -> throwM err++bootGhcjs :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, MonadCatch m)+          => EnvOverride -> Path Abs File -> m ()+bootGhcjs menv stackYaml  = do+    stackPath <- liftIO getExecutablePath+    -- Install cabal-install if missing, or if the installed one is old.+    mcabal <- getCabalInstallVersion menv stackYaml+    shouldInstallCabal <- case mcabal of+        Nothing -> do+            $logInfo "No 'cabal' binary found for use with GHCJS.  Installing a local copy of 'cabal' from source."+            return True+        Just v+            | v < $(mkVersion "1.22.4") -> do+                $logInfo $+                    "'cabal' binary found on PATH is too old to be used for booting GHCJS (version " <>+                    versionText v <>+                    ").  Installing a local copy of 'cabal' from source."+                return True+            | otherwise -> return False+    when shouldInstallCabal $ do+        $logSticky "Building cabal-install for use by ghcjs-boot ... "+        runAndLog Nothing stackPath menv+            [ "--stack-yaml"+            , toFilePath stackYaml+            , "build"+            , "cabal-install"+            ]+    $logSticky "Booting GHCJS (this will take a long time) ..."+    runAndLog Nothing stackPath menv+        [ "--stack-yaml"+        , toFilePath stackYaml+        , "exec"+        , "--no-ghc-package-path"+        , "--"+        , "ghcjs-boot"+        , "--clean"+        ]+    $logStickyDone "GHCJS booted."++-- TODO: something similar is done in Stack.Build.Execute. Create some utilities+-- for this?+runAndLog :: (MonadIO m, MonadBaseControl IO m, MonadLogger m)+          => Maybe (Path Abs Dir) -> String -> EnvOverride -> [String] -> m ()+runAndLog mdir name menv args = liftBaseWith $ \restore -> do+    let logLines = CB.lines =$ CL.mapM_ (void . restore . monadLoggerLog $(TH.location >>= liftLoc) "" LevelInfo . toLogStr)+    void $ restore $ sinkProcessStderrStdout mdir menv name args logLines logLines++getCabalInstallVersion :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, MonadCatch m)+                       => EnvOverride -> Path Abs File -> m (Maybe Version)+getCabalInstallVersion menv stackYaml = do+    ebs <- tryProcessStdout Nothing menv "stack"+      [ "--stack-yaml"+      , toFilePath stackYaml+      , "exec"+      , "--"+      , "cabal"+      , "--numeric-version"]+    case ebs of+        Left _ -> return Nothing+        Right bs -> Just <$> parseVersion (T.encodeUtf8 (T.dropWhileEnd isSpace (T.decodeUtf8 bs)))++-- | Check if given processes appear to be present, throwing an exception if+-- missing.+checkDependencies :: (MonadIO m, MonadThrow m, MonadReader env m, HasConfig env)+                  => CheckDependency a -> m a+checkDependencies (CheckDependency f) = do+    menv <- getMinimalEnvOverride+    liftIO (f menv) >>= either (throwM . MissingDependencies) return+ checkDependency :: String -> CheckDependency String checkDependency tool = CheckDependency $ \menv -> do     exists <- doesExecutableExist menv tool@@ -821,40 +1015,15 @@             Right x' -> return $ Right x'  installGHCWindows :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)-                  => SetupInfo+                  => Version+                  -> SetupInfo                   -> Path Abs File                   -> ArchiveType                   -> Path Abs Dir-                  -> PackageIdentifier                   -> m ()-installGHCWindows si archiveFile archiveType destDir ident = do-    suffix <--        case archiveType of-            TarXz -> return ".xz"-            TarBz2 -> return ".bz2"-            _ -> error $ "GHC on Windows must be a tarball file"-    tarFile <--        case T.stripSuffix suffix $ T.pack $ toFilePath archiveFile of-            Nothing -> error $ "Invalid GHC filename: " ++ show archiveFile-            Just x -> parseAbsFile $ T.unpack x--    run7z <- setup7z si--    withTempDirectory (toFilePath $ parent destDir)-                      ((FP.dropTrailingPathSeparator $ toFilePath $ dirname destDir) ++ "-tmp") $ \tmpDir0 -> do-        tmpDir <- parseAbsDir tmpDir0-        run7z (parent archiveFile) archiveFile-        run7z tmpDir tarFile-        removeFile tarFile `catchIO` \e ->-            $logWarn (T.concat-                [ "Exception when removing "-                , T.pack $ toFilePath tarFile-                , ": "-                , T.pack $ show e-                ])-        tarComponent <- parseRelDir $ "ghc-" ++ versionString (packageIdentifierVersion ident)-        renameDir (tmpDir </> tarComponent) destDir-+installGHCWindows version si archiveFile archiveType destDir = do+    tarComponent <- parseRelDir $ "ghc-" ++ versionString version+    withUnpackedTarball7z "GHC" si archiveFile archiveType tarComponent destDir     $logInfo $ "GHC installed to " <> T.pack (toFilePath destDir)  installMsys2Windows :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)@@ -863,21 +1032,8 @@                   -> Path Abs File                   -> ArchiveType                   -> Path Abs Dir-                  -> PackageIdentifier                   -> m ()-installMsys2Windows osKey si archiveFile archiveType destDir _ = do-    suffix <--        case archiveType of-            TarXz -> return ".xz"-            TarBz2 -> return ".bz2"-            _ -> error $ "MSYS2 must be a .tar.xz archive"-    tarFile <--        case T.stripSuffix suffix $ T.pack $ toFilePath archiveFile of-            Nothing -> error $ "Invalid MSYS2 filename: " ++ show archiveFile-            Just x -> parseAbsFile $ T.unpack x--    run7z <- setup7z si-+installMsys2Windows osKey si archiveFile archiveType destDir = do     exists <- liftIO $ D.doesDirectoryExist $ toFilePath destDir     when exists $ liftIO (D.removeDirectoryRecursive $ toFilePath destDir) `catchIO` \e -> do         $logError $ T.pack $@@ -885,20 +1041,8 @@             toFilePath destDir         throwM e -    run7z (parent archiveFile) archiveFile-    run7z (parent archiveFile) tarFile-    removeFile tarFile `catchIO` \e ->-        $logWarn (T.concat-            [ "Exception when removing "-            , T.pack $ toFilePath tarFile-            , ": "-            , T.pack $ show e-            ])-     msys <- parseRelDir $ "msys" ++ T.unpack (fromMaybe "32" $ T.stripPrefix "windows" osKey)-    liftIO $ D.renameDirectory-        (toFilePath $ parent archiveFile </> msys)-        (toFilePath destDir)+    withUnpackedTarball7z "MSYS2" si archiveFile archiveType msys destDir      platform <- asks getPlatform     menv0 <- getMinimalEnvOverride@@ -913,9 +1057,52 @@     -- happens, you can just run commands as usual.     runIn destDir "sh" menv ["--login", "-c", "true"] Nothing +    -- No longer installing git, it's unreliable+    -- (https://github.com/commercialhaskell/stack/issues/1046) and the+    -- MSYS2-installed version has bad CRLF defaults.+    --     -- Install git. We could install other useful things in the future too.-    runIn destDir "pacman" menv ["-Sy", "--noconfirm", "git"] Nothing+    -- runIn destDir "pacman" menv ["-Sy", "--noconfirm", "git"] Nothing +-- | Unpack a compressed tarball using 7zip.  Expects a single directory in+-- the unpacked results, which is renamed to the destination directory.+withUnpackedTarball7z :: (MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env, HasHttpManager env, MonadBaseControl IO m)+                      => String -- ^ Name of tool, used in error messages+                      -> SetupInfo+                      -> Path Abs File -- ^ Path to archive file+                      -> ArchiveType+                      -> Path Rel Dir -- ^ Name of directory expected to be in archive.+                      -> Path Abs Dir -- ^ Destination directory.+                      -> m ()+withUnpackedTarball7z name si archiveFile archiveType srcDir destDir = do+    suffix <-+        case archiveType of+            TarXz -> return ".xz"+            TarBz2 -> return ".bz2"+            TarGz -> return ".gz"+            _ -> error $ name ++ " must be a tarball file"+    tarFile <-+        case T.stripSuffix suffix $ T.pack $ toFilePath archiveFile of+            Nothing -> error $ "Invalid " ++ name ++ " filename: " ++ show archiveFile+            Just x -> parseAbsFile $ T.unpack x+    run7z <- setup7z si+    let tmpName = (FP.dropTrailingPathSeparator $ toFilePath $ dirname destDir) ++ "-tmp"+    withCanonicalizedTempDirectory (toFilePath $ parent destDir) tmpName $ \tmpDir -> do+        let absSrcDir = tmpDir </> srcDir+        removeTreeIfExists absSrcDir+        removeFileIfExists tarFile+        removeTreeIfExists destDir+        run7z (parent archiveFile) archiveFile+        run7z tmpDir tarFile+        removeFile tarFile `catchIO` \e ->+            $logWarn (T.concat+                [ "Exception when removing "+                , T.pack $ toFilePath tarFile+                , ": "+                , T.pack $ show e+                ])+        renameDir absSrcDir destDir+ -- | Download 7z as necessary, and get a function for unpacking things. -- -- Returned function takes an unpack directory and archive.@@ -1067,17 +1254,18 @@ -- | Perform a basic sanity check of GHC sanityCheck :: (MonadIO m, MonadMask m, MonadLogger m, MonadBaseControl IO m)             => EnvOverride+            -> WhichCompiler             -> m ()-sanityCheck menv = withSystemTempDirectory "stack-sanity-check" $ \dir -> do-    dir' <- parseAbsDir dir-    let fp = toFilePath $ dir' </> $(mkRelFile "Main.hs")+sanityCheck menv wc = withCanonicalizedSystemTempDirectory "stack-sanity-check" $ \dir -> do+    let fp = toFilePath $ dir </> $(mkRelFile "Main.hs")     liftIO $ writeFile fp $ unlines         [ "import Distribution.Simple" -- ensure Cabal library is present         , "main = putStrLn \"Hello World\""         ]-    ghc <- join $ findExecutable menv "ghc"+    let exeName = compilerExeName wc+    ghc <- join $ findExecutable menv exeName     $logDebug $ "Performing a sanity check on: " <> T.pack (toFilePath ghc)-    eres <- tryProcessStdout (Just dir') menv "ghc"+    eres <- tryProcessStdout (Just dir) menv exeName         [ fp         , "-no-user-package-db"         ]
+ src/Stack/Setup/Installed.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE ViewPatterns #-}+module Stack.Setup.Installed+    ( getCompilerVersion+    , markInstalled+    , unmarkInstalled+    , listInstalled+    , Tool (..)+    , toolString+    , toolNameString+    , parseToolText+    , ExtraDirs (..)+    , extraDirs+    , installDir+    ) where++import           Control.Applicative+import           Control.Monad.Catch+import           Control.Monad.IO.Class (MonadIO, liftIO)+import           Control.Monad.Logger+import           Control.Monad.Reader (MonadReader, asks)+import           Control.Monad.Trans.Control+import qualified Data.ByteString.Char8 as S8+import           Data.List hiding (concat, elem, maximumBy)+import           Data.Maybe+import           Data.Monoid+import           Data.Text (Text)+import qualified Data.Text as T+import           Distribution.System (Platform (..))+import qualified Distribution.System as Cabal+import           Path+import           Path.IO+import           Prelude hiding (concat, elem) -- Fix AMP warning+import           Stack.Types+import qualified System.FilePath as FP+import           System.Process.Read++data Tool+    = Tool PackageIdentifier -- ^ e.g. ghc-7.8.4, msys2-20150512+    | ToolGhcjs CompilerVersion -- ^ e.g. ghcjs-0.1.0_ghc-7.10.2++toolString :: Tool -> String+toolString (Tool ident) = packageIdentifierString ident+toolString (ToolGhcjs cv) = compilerVersionString cv++toolNameString :: Tool -> String+toolNameString (Tool ident) = packageNameString $ packageIdentifierName ident+toolNameString ToolGhcjs{} = "ghcjs"++parseToolText :: Text -> Maybe Tool+parseToolText (parseCompilerVersion -> Just (cv@GhcjsVersion{})) = Just (ToolGhcjs cv)+parseToolText (parsePackageIdentifierFromString . T.unpack -> Just pkgId) = Just (Tool pkgId)+parseToolText _ = Nothing++markInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)+              => Tool+              -> m ()+markInstalled tool = do+    dir <- asks $ configLocalPrograms . getConfig+    fpRel <- parseRelFile $ toolString tool ++ ".installed"+    liftIO $ writeFile (toFilePath $ dir </> fpRel) "installed"++unmarkInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)+                => Tool+                -> m ()+unmarkInstalled tool = do+    dir <- asks $ configLocalPrograms . getConfig+    fpRel <- parseRelFile $ toolString tool ++ ".installed"+    removeFileIfExists $ dir </> fpRel++listInstalled :: (MonadIO m, MonadReader env m, HasConfig env, MonadThrow m)+              => m [Tool]+listInstalled = do+    dir <- asks $ configLocalPrograms . getConfig+    createTree dir+    (_, files) <- listDirectory dir+    return $ mapMaybe toTool files+  where+    toTool fp = do+        x <- T.stripSuffix ".installed" $ T.pack $ toFilePath $ filename fp+        parseToolText x++getCompilerVersion :: (MonadLogger m, MonadCatch m, MonadBaseControl IO m, MonadIO m)+              => EnvOverride -> WhichCompiler -> m CompilerVersion+getCompilerVersion menv wc =+    case wc of+        Ghc -> do+            bs <- readProcessStdout Nothing menv "ghc" ["--numeric-version"]+            let (_, ghcVersion) = versionFromEnd bs+            GhcVersion <$> parseVersion ghcVersion+        Ghcjs -> do+            -- Output looks like+            --+            -- The Glorious Glasgow Haskell Compilation System for JavaScript, version 0.1.0 (GHC 7.10.2)+            bs <- readProcessStdout Nothing menv "ghcjs" ["--version"]+            let (rest, ghcVersion) = versionFromEnd bs+                (_, ghcjsVersion) = versionFromEnd rest+            GhcjsVersion <$> parseVersion ghcjsVersion <*> parseVersion ghcVersion+  where+    versionFromEnd = S8.spanEnd isValid . fst . S8.breakEnd isValid+    isValid c = c == '.' || ('0' <= c && c <= '9')++-- | Binary directories for the given installed package+extraDirs :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m)+          => Tool+          -> m ExtraDirs+extraDirs tool = do+    config <- asks getConfig+    dir <- installDir (configLocalPrograms config) tool+    case (configPlatform config, toolNameString tool) of+        (Platform _ Cabal.Windows, isGHC -> True) -> return mempty+            { edBins = goList+                [ dir </> $(mkRelDir "bin")+                , dir </> $(mkRelDir "mingw") </> $(mkRelDir "bin")+                ]+            }+        (Platform _ Cabal.Windows, "msys2") -> return mempty+            { edBins = goList+                [ dir </> $(mkRelDir "usr") </> $(mkRelDir "bin")+                ]+            , edInclude = goList+                [ dir </> $(mkRelDir "mingw64") </> $(mkRelDir "include")+                , dir </> $(mkRelDir "mingw32") </> $(mkRelDir "include")+                ]+            , edLib = goList+                [ dir </> $(mkRelDir "mingw64") </> $(mkRelDir "lib")+                , dir </> $(mkRelDir "mingw32") </> $(mkRelDir "lib")+                ]+            }+        (_, isGHC -> True) -> return mempty+            { edBins = goList+                [ dir </> $(mkRelDir "bin")+                ]+            }+        (_, isGHCJS -> True) -> return mempty+            { edBins = goList+                [ dir </> $(mkRelDir "bin")+                ]+            }+        (Platform _ x, toolName) -> do+            $logWarn $ "binDirs: unexpected OS/tool combo: " <> T.pack (show (x, toolName))+            return mempty+  where+    goList = map toFilePathNoTrailingSlash+    isGHC n = "ghc" == n || "ghc-" `isPrefixOf` n+    isGHCJS n = "ghcjs" == n++data ExtraDirs = ExtraDirs+    { edBins :: ![FilePath]+    , edInclude :: ![FilePath]+    , edLib :: ![FilePath]+    }+instance Monoid ExtraDirs where+    mempty = ExtraDirs [] [] []+    mappend (ExtraDirs a b c) (ExtraDirs x y z) = ExtraDirs+        (a ++ x)+        (b ++ y)+        (c ++ z)++installDir :: (MonadReader env m, HasConfig env, MonadThrow m, MonadLogger m)+           => Path Abs Dir+           -> Tool+           -> m (Path Abs Dir)+installDir programsDir tool = do+    reldir <- parseRelDir $ toolString tool+    return $ programsDir </> reldir++toFilePathNoTrailingSlash :: Path loc Dir -> FilePath+toFilePathNoTrailingSlash = FP.dropTrailingPathSeparator . toFilePath
src/Stack/Solver.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE TemplateHaskell       #-} module Stack.Solver     ( cabalSolver-    , getCompilerVersion     , solveExtraDeps     ) where @@ -17,39 +16,65 @@ import           Control.Monad.Trans.Control import           Data.Aeson.Extended         (object, (.=), toJSON, logJSONWarnings) import qualified Data.ByteString             as S-import qualified Data.ByteString.Char8       as S8 import           Data.Either import qualified Data.HashMap.Strict         as HashMap import           Data.Map                    (Map) import qualified Data.Map                    as Map+import           Data.Monoid import           Data.Text                   (Text) import qualified Data.Text                   as T import           Data.Text.Encoding          (decodeUtf8, encodeUtf8) import qualified Data.Yaml                   as Yaml import           Network.HTTP.Client.Conduit (HasHttpManager) import           Path+import           Path.IO                     (parseRelAsAbsDir) import           Prelude import           Stack.BuildPlan+import           Stack.Setup.Installed import           Stack.Types import           System.Directory            (copyFile,                                               createDirectoryIfMissing,                                               getTemporaryDirectory) import qualified System.FilePath             as FP-import           System.IO.Temp+import           System.IO.Temp              (withSystemTempDirectory) import           System.Process.Read  cabalSolver :: (MonadIO m, MonadLogger m, MonadMask m, MonadBaseControl IO m, MonadReader env m, HasConfig env)             => WhichCompiler             -> [Path Abs Dir] -- ^ cabal files             -> Map PackageName Version -- ^ constraints+            -> Map PackageName (Map FlagName Bool) -- ^ user-specified flags             -> [String] -- ^ additional arguments             -> m (CompilerVersion, Map PackageName (Version, Map FlagName Bool))-cabalSolver wc cabalfps constraints cabalArgs = withSystemTempDirectory "cabal-solver" $ \dir -> do+cabalSolver wc cabalfps constraints userFlags cabalArgs = withSystemTempDirectory "cabal-solver" $ \dir -> do     configLines <- getCabalConfig dir constraints     let configFile = dir FP.</> "cabal.config"     liftIO $ S.writeFile configFile $ encodeUtf8 $ T.unlines configLines -    menv <- getMinimalEnvOverride+    menv0 <- getMinimalEnvOverride+    mghc <- findExecutable menv0 "ghc"+    platform <- asks getPlatform+    menv <-+        case mghc of+            Just _ -> return menv0+            Nothing -> do+                tools <- listInstalled+                let ghcName = $(mkPackageName "ghc")+                case [version | Tool (PackageIdentifier name version) <- tools, name == ghcName] of+                    [] -> throwM SolverMissingGHC+                    versions -> do+                        let version = maximum versions+                        $logInfo $ "No GHC on path, selecting: " <>+                                   T.pack (versionString version)+                        ed <- extraDirs $ Tool $ PackageIdentifier ghcName version+                        mkEnvOverride platform+                            $ augmentPathMap (edBins ed)+                            $ unEnvOverride menv0+    mcabal <- findExecutable menv "cabal"+    case mcabal of+        Nothing -> throwM SolverMissingCabalInstall+        Just _ -> return ()+     compilerVersion <- getCompilerVersion menv wc      -- Run from a temporary directory to avoid cabal getting confused by any@@ -58,7 +83,7 @@     --     -- In theory we could use --ignore-sandbox, but not all versions of cabal     -- support it.-    tmpdir <- liftIO getTemporaryDirectory >>= parseAbsDir+    tmpdir <- liftIO getTemporaryDirectory >>= parseRelAsAbsDir      let args = ("--config-file=" ++ configFile)              : "install"@@ -72,12 +97,12 @@              : "--package-db=clear"              : "--package-db=global"              : cabalArgs +++               toConstraintArgs userFlags ++                (map toFilePath cabalfps) ++                ["--ghcjs" | wc == Ghcjs]      $logInfo "Asking cabal to calculate a build plan, please wait" -    platform <- asks getPlatform     menv' <- mkEnvOverride platform            $ Map.delete "GHCJS_PACKAGE_PATH"            $ Map.delete "GHC_PACKAGE_PATH" $ unEnvOverride menv@@ -109,26 +134,13 @@                         Nothing -> (t0, True)                         Just x -> (x, True)                 Just x -> (x, False)--getCompilerVersion :: (MonadLogger m, MonadCatch m, MonadBaseControl IO m, MonadIO m)-              => EnvOverride -> WhichCompiler -> m CompilerVersion-getCompilerVersion menv wc =-    case wc of-        Ghc -> do-            bs <- readProcessStdout Nothing menv "ghc" ["--numeric-version"]-            let (_, ghcVersion) = versionFromEnd bs-            GhcVersion <$> parseVersion ghcVersion-        Ghcjs -> do-            -- Output looks like-            ---            -- The Glorious Glasgow Haskell Compilation System for JavaScript, version 0.1.0 (GHC 7.10.2)-            bs <- readProcessStdout Nothing menv "ghcjs" ["--version"]-            let (rest, ghcVersion) = versionFromEnd bs-                (_, ghcjsVersion) = versionFromEnd rest-            GhcjsVersion <$> parseVersion ghcjsVersion <*> parseVersion ghcVersion-  where-    versionFromEnd = S8.spanEnd isValid . fst . S8.breakEnd isValid-    isValid c = c == '.' || ('0' <= c && c <= '9')+    toConstraintArgs userFlagMap =+        [formatFlagConstraint package flag enabled | (package, fs) <- Map.toList userFlagMap+                                                   , (flag, enabled) <- Map.toList fs]+    formatFlagConstraint package flag enabled =+        let sign = if enabled then '+' else '-'+        in+        "--constraint=" ++ unwords [packageNameString package, sign : flagNameString flag]  getCabalConfig :: (MonadReader env m, HasConfig env, MonadIO m, MonadThrow m)                => FilePath -- ^ temp dir@@ -179,13 +191,14 @@      let packages = Map.union             (bcExtraDeps bconfig)-            (fmap mpiVersion snapshot)+            (mpiVersion <$> snapshot)      wc <- getWhichCompiler     (_compilerVersion, extraDeps) <- cabalSolver         wc         (Map.keys $ envConfigPackages econfig)         packages+        (bcFlags bconfig)         []      let newDeps = extraDeps `Map.difference` packages
src/Stack/Types/Build.hs view
@@ -1,11 +1,11 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE FlexibleInstances          #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE ViewPatterns               #-}  -- | Build-specific types. @@ -78,6 +78,7 @@ import           Stack.Types.Version import           System.Exit (ExitCode (ExitFailure)) import           System.FilePath (dropTrailingPathSeparator, pathSeparator)+import           System.Process.Log (showProcessArgDebug)  ---------------------------------------------- -- Exceptions@@ -116,6 +117,8 @@   | InvalidFlagSpecification (Set UnusedFlags)   | TargetParseException [Text]   | DuplicateLocalPackageNames [(PackageName, [Path Abs Dir])]+  | SolverMissingCabalInstall+  | SolverMissingGHC   deriving Typeable  data FlagSource = FSCommandLine | FSStackYaml@@ -137,7 +140,7 @@                     Nothing -> "No compiler found, expected "                     Just (actual, arch) -> concat                         [ "Compiler version mismatched, found "-                        , T.unpack (compilerVersionName actual)+                        , compilerVersionString actual                         , " ("                         , display arch                         , ")"@@ -147,7 +150,7 @@                     MatchMinor -> "minor version match with "                     MatchExact -> "exact version "                     NewerMinor -> "minor version match or newer with "-                , T.unpack (compilerVersionName expected)+                , compilerVersionString expected                 , " ("                 , display earch                 , ghcVariantSuffix ghcVariant@@ -233,7 +236,9 @@                 go _ = Map.empty      -- Supressing duplicate output     show (CabalExitedUnsuccessfully exitCode taskProvides' execName fullArgs logFiles bs) =-        let fullCmd = (dropQuotes (toFilePath execName) ++ " " ++ (unwords fullArgs))+        let fullCmd = unwords+                    $ dropQuotes (toFilePath execName)+                    : map (T.unpack . showProcessArgDebug) fullArgs             logLocations = maybe "" (\fp -> "\n    Logs have been written to: " ++ toFilePath fp) logFiles         in "\n--  While building package " ++ dropQuotes (show taskProvides') ++ " using:\n" ++            "      " ++ fullCmd ++ "\n" ++@@ -312,6 +317,14 @@             : (packageNameString name ++ " used in:")             : map goDir dirs         goDir dir = "- " ++ toFilePath dir+    show SolverMissingCabalInstall = unlines+        [ "Solver requires that cabal be on your PATH"+        , "Try running 'stack install cabal-install'"+        ]+    show SolverMissingGHC = unlines+        [ "Solver requires that GHC be on your PATH"+        , "Try running 'stack setup'"+        ]  instance Exception StackBuildException @@ -593,6 +606,7 @@     , bcoSnapInstallRoot :: !(Path Abs Dir)     , bcoLocalInstallRoot :: !(Path Abs Dir)     , bcoBuildOpts :: !BuildOpts+    , bcoExtraDBs :: ![(Path Abs Dir)]     }  -- | Render a @BaseConfigOpts@ to an actual list of options@@ -600,12 +614,13 @@               -> BaseConfigOpts               -> Map PackageIdentifier GhcPkgId -- ^ dependencies               -> Bool -- ^ wanted?+              -> Bool -- ^ local non-extra-dep?               -> InstallLocation               -> Package               -> ConfigureOpts-configureOpts econfig bco deps wanted loc package = ConfigureOpts+configureOpts econfig bco deps wanted isLocal loc package = ConfigureOpts     { coDirs = configureOptsDirs bco loc package-    , coNoDirs = configureOptsNoDir econfig bco deps wanted package+    , coNoDirs = configureOptsNoDir econfig bco deps wanted isLocal package     }  configureOptsDirs :: BaseConfigOpts@@ -615,8 +630,8 @@ configureOptsDirs bco loc package = concat     [ ["--user", "--package-db=clear", "--package-db=global"]     , map (("--package-db=" ++) . toFilePath) $ case loc of-        Snap -> [bcoSnapDB bco]-        Local -> [bcoSnapDB bco, bcoLocalDB bco]+        Snap -> bcoExtraDBs bco ++ [bcoSnapDB bco]+        Local -> bcoExtraDBs bco ++ [bcoSnapDB bco] ++ [bcoLocalDB bco]     , [ "--libdir=" ++ toFilePathNoTrailingSlash (installRoot </> $(mkRelDir "lib"))       , "--bindir=" ++ toFilePathNoTrailingSlash (installRoot </> bindirSuffix)       , "--datadir=" ++ toFilePathNoTrailingSlash (installRoot </> $(mkRelDir "share"))@@ -646,9 +661,10 @@                    -> BaseConfigOpts                    -> Map PackageIdentifier GhcPkgId -- ^ dependencies                    -> Bool -- ^ wanted?+                   -> Bool -- ^ is this a local, non-extra-dep?                    -> Package                    -> [String]-configureOptsNoDir econfig bco deps wanted package = concat+configureOptsNoDir econfig bco deps wanted isLocal package = concat     [ depOptions     , ["--enable-library-profiling" | boptsLibProfile bopts || boptsExeProfile bopts]     , ["--enable-executable-profiling" | boptsExeProfile bopts]@@ -697,11 +713,17 @@     allGhcOptions = concat         [ fromMaybe [] $ Map.lookup Nothing ghcOptionsMap         , fromMaybe [] $ Map.lookup (Just $ packageName package) ghcOptionsMap-        , if wanted+        , if includeExtraOptions             then boptsGhcOptions bopts             else []         ] +    includeExtraOptions =+        case configApplyGhcOptions config of+            AGOTargets -> wanted+            AGOLocals -> isLocal+            AGOEverything -> True+ -- | Get set of wanted package names from locals. wantedLocalPackages :: [LocalPackage] -> Set PackageName wantedLocalPackages = Set.fromList . map (packageName . lpPackage) . filter lpWanted@@ -715,9 +737,6 @@         , toRational               (utctDayTime x)) -data Installed = Library PackageIdentifier GhcPkgId | Executable PackageIdentifier-    deriving (Show, Eq, Ord)- -- | Configure options to be sent to Setup.hs configure data ConfigureOpts = ConfigureOpts     { coDirs :: ![String]@@ -737,7 +756,7 @@     -- Use FilePath instead of Path Abs File for Binary instances     { pcLibrary :: !(Maybe FilePath)     -- ^ .conf file inside the package database-    , pcExes :: ![FilePath]+    , pcExes    :: ![FilePath]     -- ^ Full paths to executables     }     deriving (Show, Eq, Generic)
src/Stack/Types/Compiler.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ViewPatterns #-}  module Stack.Types.Compiler where@@ -7,6 +8,8 @@ import           Control.DeepSeq import           Data.Aeson import           Data.Binary.VersionTagged (Binary, HasStructuralInfo)+import           Data.Map (Map)+import qualified Data.Map as Map import           Data.Monoid ((<>)) import qualified Data.Text as T import           GHC.Generics (Generic)@@ -36,10 +39,24 @@ instance HasStructuralInfo CompilerVersion instance NFData CompilerVersion instance ToJSON CompilerVersion where-    toJSON = toJSON . compilerVersionName+    toJSON = toJSON . compilerVersionText instance FromJSON CompilerVersion where     parseJSON (String t) = maybe (fail "Failed to parse compiler version") return (parseCompilerVersion t)     parseJSON _ = fail "Invalid CompilerVersion, must be String"+instance FromJSON a => FromJSON (Map CompilerVersion a) where+    -- TODO: Dedupe with similar code in Stack.Types.Version?+    --+    -- Maybe this ought to be abstracted into a 'JSONKey' class, so that a+    -- fully generic definition for Map can be provided.+    parseJSON val = do+        m <- parseJSON val+        fmap Map.fromList $ mapM go $ Map.toList m+      where+        go (k, v) = do+            let mparsed = parseCompilerVersion (T.pack k)+            case mparsed of+                Nothing -> fail $ "Failed to parse CompilerVersion " ++ k+                Just parsed -> return (parsed, v)  parseCompilerVersion :: T.Text -> Maybe CompilerVersion parseCompilerVersion t@@ -54,11 +71,14 @@     | otherwise         = Nothing -compilerVersionName :: CompilerVersion -> T.Text-compilerVersionName (GhcVersion vghc) =+compilerVersionText :: CompilerVersion -> T.Text+compilerVersionText (GhcVersion vghc) =     "ghc-" <> versionText vghc-compilerVersionName (GhcjsVersion vghcjs vghc) =+compilerVersionText (GhcjsVersion vghcjs vghc) =     "ghcjs-" <> versionText vghcjs <> "_ghc-" <> versionText vghc++compilerVersionString :: CompilerVersion -> String+compilerVersionString = T.unpack . compilerVersionText  whichCompiler :: CompilerVersion -> WhichCompiler whichCompiler GhcVersion {} = Ghc
src/Stack/Types/Config.hs view
@@ -25,7 +25,7 @@                  (ToJSON, toJSON, FromJSON, parseJSON, withText, object,                   (.=), (..:), (..:?), (..!=), Value(String, Object),                   withObjectWarnings, WarningParser, Object, jsonSubWarnings, JSONWarning,-                  jsonSubWarningsT, jsonSubWarningsTT, tellJSONField)+                  jsonSubWarningsT, jsonSubWarningsTT) import           Data.Attoparsec.Args import           Data.Binary (Binary) import           Data.ByteString (ByteString)@@ -66,9 +66,14 @@ data Config =   Config {configStackRoot           :: !(Path Abs Dir)          -- ^ ~/.stack more often than not+         ,configUserConfigPath      :: !(Path Abs File)+         -- ^ Path to user configuration file (usually ~/.stack/config.yaml)          ,configDocker              :: !DockerOpts+         -- ^ Docker configuration          ,configEnvOverride         :: !(EnvSettings -> IO EnvOverride)          -- ^ Environment variables to be passed to external tools+         ,configLocalProgramsBase   :: !(Path Abs Dir)+         -- ^ Non-platform-specific path containing local installations          ,configLocalPrograms       :: !(Path Abs Dir)          -- ^ Path containing local installations (mainly GHC)          ,configConnectionCount     :: !Int@@ -138,8 +143,30 @@          -- ^ Additional SetupInfo (inline or remote) to use to find tools.          ,configPvpBounds           :: !PvpBounds          -- ^ How PVP upper bounds should be added to packages+         ,configModifyCodePage      :: !Bool+         -- ^ Force the code page to UTF-8 on Windows+         ,configExplicitSetupDeps   :: !(Map (Maybe PackageName) Bool)+         -- ^ See 'explicitSetupDeps'. 'Nothing' provides the default value.+         ,configRebuildGhcOptions   :: !Bool+         -- ^ Rebuild on GHC options changes+         ,configApplyGhcOptions     :: !ApplyGhcOptions+         -- ^ Which packages to ghc-options on the command line apply to?          } +-- | Which packages to ghc-options on the command line apply to?+data ApplyGhcOptions = AGOTargets -- ^ all local targets+                     | AGOLocals -- ^ all local packages, even non-targets+                     | AGOEverything -- ^ every package+  deriving (Show, Read, Eq, Ord, Enum, Bounded)++instance FromJSON ApplyGhcOptions where+    parseJSON = withText "ApplyGhcOptions" $ \t ->+        case t of+            "targets" -> return AGOTargets+            "locals" -> return AGOLocals+            "everything" -> return AGOEverything+            _ -> fail $ "Invalid ApplyGhcOptions: " ++ show t+ -- | Information on a single package index data PackageIndex = PackageIndex     { indexName :: !IndexName@@ -223,15 +250,20 @@         { eoEnvSettings :: !EnvSettings         , eoPackages :: ![String]         }++data EvalOpts = EvalOpts+    { evalArg :: !String+    , evalExtra :: !ExecOptsExtra+    }+ -- | Parsed global command-line options. data GlobalOpts = GlobalOpts-    { globalReExec       :: !Bool+    { globalReExecVersion :: !(Maybe String) -- ^ Expected re-exec in container version     , globalLogLevel     :: !LogLevel -- ^ Log level     , globalConfigMonoid :: !ConfigMonoid -- ^ Config monoid, for passing into 'loadConfig'     , globalResolver     :: !(Maybe AbstractResolver) -- ^ Resolver override     , globalTerminal     :: !Bool -- ^ We're in a terminal?     , globalStackYaml    :: !(Maybe FilePath) -- ^ Override project stack.yaml-    , globalModifyCodePage :: !Bool -- ^ Force the code page to UTF-8 on Windows     } deriving (Show)  -- | Either an actual resolver value, or an abstract description of one (e.g.,@@ -266,6 +298,8 @@       --       -- These dependencies will not be installed to a shared location, and       -- will override packages provided by the resolver.+    , bcExtraPackageDBs :: ![Path Abs Dir]+      -- ^ Extra package databases     , bcStackYaml  :: !(Path Abs File)       -- ^ Location of the stack.yaml file.       --@@ -401,15 +435,17 @@     -- ^ Per-package flag overrides     , projectResolver :: !Resolver     -- ^ How we resolve which dependencies to use+    , projectExtraPackageDBs :: ![FilePath]     }   deriving Show  instance ToJSON Project where     toJSON p = object-        [ "packages"   .= projectPackages p-        , "extra-deps" .= map fromTuple (Map.toList $ projectExtraDeps p)-        , "flags"      .= projectFlags p-        , "resolver"   .= projectResolver p+        [ "packages"          .= projectPackages p+        , "extra-deps"        .= map fromTuple (Map.toList $ projectExtraDeps p)+        , "flags"             .= projectFlags p+        , "resolver"          .= projectResolver p+        , "extra-package-dbs" .= projectExtraPackageDBs p         ]  -- | How we resolve which dependencies to install given a set of packages.@@ -448,7 +484,7 @@ -- directory names resolverName :: Resolver -> Text resolverName (ResolverSnapshot name) = renderSnapName name-resolverName (ResolverCompiler v) = compilerVersionName v+resolverName (ResolverCompiler v) = compilerVersionText v resolverName (ResolverCustom name _) = "custom-" <> name  -- | Try to parse a @Resolver@ from a @Text@. Won't work for complex resolvers (like custom).@@ -562,6 +598,13 @@     -- ^ Additional setup info (inline or remote) to use for installing tools     ,configMonoidPvpBounds           :: !(Maybe PvpBounds)     -- ^ See 'configPvpBounds'+    ,configMonoidModifyCodePage      :: !(Maybe Bool)+    -- ^ See 'configModifyCodePage'+    ,configMonoidExplicitSetupDeps   :: !(Map (Maybe PackageName) Bool)+    -- ^ See 'configExplicitSetupDeps'+    ,configMonoidRebuildGhcOptions   :: !(Maybe Bool)+    -- ^ See 'configMonoidRebuildGhcOptions'+    ,configMonoidApplyGhcOptions     :: !(Maybe ApplyGhcOptions)     }   deriving Show @@ -593,6 +636,10 @@     , configMonoidExtraPath = []     , configMonoidSetupInfoLocations = mempty     , configMonoidPvpBounds = Nothing+    , configMonoidModifyCodePage = Nothing+    , configMonoidExplicitSetupDeps = mempty+    , configMonoidRebuildGhcOptions = Nothing+    , configMonoidApplyGhcOptions = Nothing     }   mappend l r = ConfigMonoid     { configMonoidDockerOpts = configMonoidDockerOpts l <> configMonoidDockerOpts r@@ -622,6 +669,10 @@     , configMonoidExtraPath = configMonoidExtraPath l ++ configMonoidExtraPath r     , configMonoidSetupInfoLocations = configMonoidSetupInfoLocations l ++ configMonoidSetupInfoLocations r     , configMonoidPvpBounds = configMonoidPvpBounds l <|> configMonoidPvpBounds r+    , configMonoidModifyCodePage = configMonoidModifyCodePage l <|> configMonoidModifyCodePage r+    , configMonoidExplicitSetupDeps = configMonoidExplicitSetupDeps l <> configMonoidExplicitSetupDeps r+    , configMonoidRebuildGhcOptions = configMonoidRebuildGhcOptions l <|> configMonoidRebuildGhcOptions r+    , configMonoidApplyGhcOptions = configMonoidApplyGhcOptions l <|> configMonoidApplyGhcOptions r     }  instance FromJSON (ConfigMonoid, [JSONWarning]) where@@ -677,6 +728,12 @@         maybeToList <$> jsonSubWarningsT (obj ..:? "setup-info")      configMonoidPvpBounds <- obj ..:? "pvp-bounds"+    configMonoidModifyCodePage <- obj ..:? "modify-code-page"+    configMonoidExplicitSetupDeps <-+        (obj ..:? "explicit-setup-deps" ..!= mempty)+        >>= fmap Map.fromList . mapM handleExplicitSetupDep . Map.toList+    configMonoidRebuildGhcOptions <- obj ..:? "rebuild-ghc-options"+    configMonoidApplyGhcOptions <- obj ..:? "apply-ghc-options"      return ConfigMonoid {..}   where@@ -693,6 +750,16 @@             Left e -> fail e             Right vals -> return (name, map T.pack vals) +    handleExplicitSetupDep :: Monad m => (Text, Bool) -> m (Maybe PackageName, Bool)+    handleExplicitSetupDep (name', b) = do+        name <-+            if name' == "*"+                then return Nothing+                else case parsePackageNameFromString $ T.unpack name' of+                        Left e -> fail $ show e+                        Right x -> return $ Just x+        return (name, b)+ -- | Newtype for non-orphan FromJSON instance. newtype VersionRangeJSON = VersionRangeJSON { unVersionRangeJSON :: VersionRange } @@ -719,7 +786,7 @@         , toFilePath configFile         , "':\n"         , show exception-        , "\nSee https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md."+        , "\nSee https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md."         ]     show (ParseResolverException t) = concat         [ "Invalid resolver value: "@@ -757,7 +824,7 @@             (\name -> "    stack init --resolver " ++ T.unpack (renderSnapName name))             names         , "\nYou'll then need to add some extra-deps. See:\n\n"-        , "    https://github.com/commercialhaskell/stack/blob/master/doc/yaml_configuration.md#extra-deps"+        , "    https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md#extra-deps"         , "\n\nYou can also try falling back to a dependency solver with:\n\n"         , "    stack init --solver"         ]@@ -875,7 +942,7 @@     compilerVersion <- asks (envConfigCompilerVersion . getEnvConfig)     parseRelDir $ case compilerVersion of         GhcVersion version -> versionString version-        GhcjsVersion {} -> T.unpack (compilerVersionName compilerVersion)+        GhcjsVersion {} -> compilerVersionString compilerVersion  -- | Package database for installing dependencies into packageDatabaseDeps :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => m (Path Abs Dir)@@ -889,6 +956,12 @@     root <- installationRootLocal     return $ root </> $(mkRelDir "pkgdb") +-- | Extra package databases+packageDatabaseExtra :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => m [Path Abs Dir]+packageDatabaseExtra = do+    bc <- asks getBuildConfig+    return $ bcExtraPackageDBs bc+ -- | Directory for holding flag cache information flagCacheLocal :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => m (Path Abs Dir) flagCacheLocal = do@@ -914,9 +987,12 @@ docDirSuffix :: Path Rel Dir docDirSuffix = $(mkRelDir "doc") --- | Suffix applied to an installation root to get the hpc dir-hpcDirSuffix :: Path Rel Dir-hpcDirSuffix = $(mkRelDir "hpc")+-- | Where HPC reports and tix files get stored.+hpcReportDir :: (MonadThrow m, MonadReader env m, HasEnvConfig env)+             => m (Path Abs Dir)+hpcReportDir = do+   root <- installationRootLocal+   return $ root </> $(mkRelDir "hpc")  -- | Get the extra bin directories (for the PATH). Puts more local first --@@ -964,11 +1040,13 @@         flags <- o ..:? "flags" ..!= mempty         resolver <- jsonSubWarnings (o ..: "resolver")         config <- parseConfigMonoidJSON o+        extraPackageDBs <- o ..:? "extra-package-dbs" ..!= []         let project = Project                 { projectPackages = dirs                 , projectExtraDeps = extraDeps                 , projectFlags = flags                 , projectResolver = resolver+                , projectExtraPackageDBs = extraPackageDBs                 }         return $ ProjectAndConfigMonoid project config       where@@ -1070,8 +1148,6 @@     url <- o ..: "url"     contentLength <- o ..:? "content-length"     sha1TextMay <- o ..:? "sha1"-    -- Don't warn about 'version' field that is sometimes included-    tellJSONField "version"     return         DownloadInfo         { downloadInfoUrl = url@@ -1099,6 +1175,8 @@     , siSevenzDll :: Maybe DownloadInfo     , siMsys2 :: Map Text VersionedDownloadInfo     , siGHCs :: Map Text (Map Version DownloadInfo)+    , siGHCJSs :: Map Text (Map CompilerVersion DownloadInfo)+    , siStack :: Map Text (Map Version DownloadInfo)     }     deriving Show @@ -1108,10 +1186,12 @@         siSevenzDll <- jsonSubWarningsT (o ..:? "sevenzdll-info")         siMsys2 <- jsonSubWarningsT (o ..:? "msys2" ..!= mempty)         siGHCs <- jsonSubWarningsTT (o ..:? "ghc" ..!= mempty)-        -- Don't warn about 'portable-git' that is no-longer used-        tellJSONField "portable-git"+        siGHCJSs <- jsonSubWarningsTT (o ..:? "ghcjs" ..!= mempty)+        siStack <- jsonSubWarningsTT (o ..:? "stack" ..!= mempty)         return SetupInfo {..} +-- | For @siGHCs@ and @siGHCJSs@ fields maps are deeply merged.+-- For all fields the values from the last @SetupInfo@ win. instance Monoid SetupInfo where     mempty =         SetupInfo@@ -1119,13 +1199,17 @@         , siSevenzDll = Nothing         , siMsys2 = Map.empty         , siGHCs = Map.empty+        , siGHCJSs = Map.empty+        , siStack = Map.empty         }     mappend l r =         SetupInfo-        { siSevenzExe = siSevenzExe l <|> siSevenzExe r-        , siSevenzDll = siSevenzDll l <|> siSevenzDll r-        , siMsys2 = siMsys2 l <> siMsys2 r-        , siGHCs = siGHCs l <> siGHCs r }+        { siSevenzExe = siSevenzExe r <|> siSevenzExe l+        , siSevenzDll = siSevenzDll r <|> siSevenzDll l+        , siMsys2 = siMsys2 r <> siMsys2 l+        , siGHCs = Map.unionWith (<>) (siGHCs r) (siGHCs l)+        , siGHCJSs = Map.unionWith (<>) (siGHCJSs r) (siGHCJSs l)+        , siStack = Map.unionWith (<>) (siStack l) (siStack r) }  -- | Remote or inline 'SetupInfo' data SetupInfoLocation@@ -1169,3 +1253,17 @@   toJSON = toJSON . pvpBoundsText instance FromJSON PvpBounds where   parseJSON = withText "PvpBounds" (either fail return . parsePvpBounds)++-- | Provide an explicit list of package dependencies when running a custom Setup.hs+explicitSetupDeps :: (MonadReader env m, HasConfig env) => PackageName -> m Bool+explicitSetupDeps name = do+    m <- asks $ configExplicitSetupDeps . getConfig+    return $+        -- Yes there are far cleverer ways to write this. I honestly consider+        -- the explicit pattern matching much easier to parse at a glance.+        case Map.lookup (Just name) m of+            Just b -> b+            Nothing ->+                case Map.lookup Nothing m of+                    Just b -> b+                    Nothing -> False -- default value
src/Stack/Types/Docker.hs view
@@ -5,6 +5,8 @@ module Stack.Types.Docker where  import Control.Applicative+import Control.Monad+import Control.Monad.Catch (MonadThrow) import Data.Aeson.Extended import Data.Monoid import Data.Text (Text)@@ -40,14 +42,18 @@     -- ^ Environment variables to set in the container.   ,dockerDatabasePath :: !(Path Abs File)     -- ^ Location of image usage database.+  ,dockerStackExe :: !(Maybe DockerStackExe)+    -- ^ Location of container-compatible stack executable+  ,dockerSetUser :: !(Maybe Bool)+   -- ^ Set in-container user to match host's   }   deriving (Show)  -- | An uninterpreted representation of docker options. -- Configurations may be "cascaded" using mappend (left-biased). data DockerOptsMonoid = DockerOptsMonoid-  {dockerMonoidExists :: !(Maybe Bool)-    -- ^ Does a @docker:@ section exist in the top-level (usually project) config?+  {dockerMonoidDefaultEnable :: !Bool+    -- ^ Should Docker be defaulted to enabled (does @docker:@ section exist in the config)?   ,dockerMonoidEnable :: !(Maybe Bool)     -- ^ Is using Docker enabled?   ,dockerMonoidRepoOrImage :: !(Maybe DockerMonoidRepoOrImage)@@ -76,13 +82,17 @@     -- ^ Environment variables to set in the container   ,dockerMonoidDatabasePath :: !(Maybe String)     -- ^ Location of image usage database.+  ,dockerMonoidStackExe :: !(Maybe String)+    -- ^ Location of container-compatible stack executable+  ,dockerMonoidSetUser :: !(Maybe Bool)+   -- ^ Set in-container user to match host's   }   deriving (Show)  -- | Decode uninterpreted docker options from JSON/YAML. instance FromJSON (DockerOptsMonoid, [JSONWarning]) where   parseJSON = withObjectWarnings "DockerOptsMonoid"-    (\o -> do dockerMonoidExists           <- pure (Just True)+    (\o -> do dockerMonoidDefaultEnable    <- pure True               dockerMonoidEnable           <- o ..:? dockerEnableArgName               dockerMonoidRepoOrImage      <- ((Just . DockerMonoidImage) <$> o ..: dockerImageArgName) <|>                                               ((Just . DockerMonoidRepo) <$> o ..: dockerRepoArgName) <|>@@ -98,12 +108,14 @@               dockerMonoidMount            <- o ..:? dockerMountArgName ..!= []               dockerMonoidEnv              <- o ..:? dockerEnvArgName ..!= []               dockerMonoidDatabasePath     <- o ..:? dockerDatabasePathArgName+              dockerMonoidStackExe         <- o ..:? dockerStackExeArgName+              dockerMonoidSetUser          <- o ..:? dockerSetUserArgName               return DockerOptsMonoid{..})  -- | Left-biased combine Docker options instance Monoid DockerOptsMonoid where   mempty = DockerOptsMonoid-    {dockerMonoidExists           = Just False+    {dockerMonoidDefaultEnable    = False     ,dockerMonoidEnable           = Nothing     ,dockerMonoidRepoOrImage      = Nothing     ,dockerMonoidRegistryLogin    = Nothing@@ -117,9 +129,11 @@     ,dockerMonoidMount            = []     ,dockerMonoidEnv              = []     ,dockerMonoidDatabasePath     = Nothing+    ,dockerMonoidStackExe         = Nothing+    ,dockerMonoidSetUser          = Nothing     }   mappend l r = DockerOptsMonoid-    {dockerMonoidExists           = dockerMonoidExists l <|> dockerMonoidExists r+    {dockerMonoidDefaultEnable    = dockerMonoidDefaultEnable l || dockerMonoidDefaultEnable r     ,dockerMonoidEnable           = dockerMonoidEnable l <|> dockerMonoidEnable r     ,dockerMonoidRepoOrImage      = dockerMonoidRepoOrImage l <|> dockerMonoidRepoOrImage r     ,dockerMonoidRegistryLogin    = dockerMonoidRegistryLogin l <|> dockerMonoidRegistryLogin r@@ -133,8 +147,26 @@     ,dockerMonoidMount            = dockerMonoidMount r <> dockerMonoidMount l     ,dockerMonoidEnv              = dockerMonoidEnv r <> dockerMonoidEnv l     ,dockerMonoidDatabasePath     = dockerMonoidDatabasePath l <|> dockerMonoidDatabasePath r+    ,dockerMonoidStackExe         = dockerMonoidStackExe l <|> dockerMonoidStackExe r+    ,dockerMonoidSetUser          = dockerMonoidSetUser l <|> dockerMonoidSetUser r     } +-- | Where to get the `stack` executable to run in Docker containers+data DockerStackExe+    = DockerStackExeDownload  -- ^ Download from official bindist+    | DockerStackExeHost  -- ^ Host's `stack` (linux-x86_64 only)+    | DockerStackExeImage  -- ^ Docker image's `stack` (versions must match)+    | DockerStackExePath (Path Abs File) -- ^ Executable at given path+    deriving (Show)++-- | Parse 'DockerStackExe'.+parseDockerStackExe :: (MonadThrow m) => String -> m DockerStackExe+parseDockerStackExe t+    | t == dockerStackExeDownloadVal = return DockerStackExeDownload+    | t == dockerStackExeHostVal = return DockerStackExeHost+    | t == dockerStackExeImageVal = return DockerStackExeImage+    | otherwise = liftM DockerStackExePath (parseAbsFile t)+ -- | Docker volume mount. data Mount = Mount String String @@ -217,3 +249,23 @@ -- | Docker database path argument name. dockerDatabasePathArgName :: Text dockerDatabasePathArgName = "database-path"++-- | Docker database path argument name.+dockerStackExeArgName :: Text+dockerStackExeArgName = "stack-exe"++-- | Value for @--docker-stack-exe=download@+dockerStackExeDownloadVal :: String+dockerStackExeDownloadVal = "download"++-- | Value for @--docker-stack-exe=host@+dockerStackExeHostVal :: String+dockerStackExeHostVal = "host"++-- | Value for @--docker-stack-exe=image@+dockerStackExeImageVal :: String+dockerStackExeImageVal = "image"++-- | Docker @set-user@ argument name+dockerSetUserArgName :: Text+dockerSetUserArgName = "set-user"
src/Stack/Types/Package.hs view
@@ -36,7 +36,9 @@ import           Stack.Types.Compiler import           Stack.Types.Config import           Stack.Types.FlagName+import           Stack.Types.GhcPkgId import           Stack.Types.PackageName+import           Stack.Types.PackageIdentifier import           Stack.Types.Version  -- | All exceptions thrown by the library.@@ -98,6 +100,7 @@ newtype GetPackageOpts = GetPackageOpts     { getPackageOpts :: forall env m. (MonadIO m,HasEnvConfig env, HasPlatform env, MonadThrow m, MonadReader env m, MonadLogger m, MonadCatch m)                      => SourceMap+                     -> InstalledMap                      -> [PackageName]                      -> Path Abs File                      -> m (Map NamedComponent (Set ModuleName)@@ -215,7 +218,10 @@      , lpDir            :: !(Path Abs Dir)  -- ^ Directory of the package.     , lpCabalFile      :: !(Path Abs File) -- ^ The .cabal file-    , lpDirtyFiles     :: !Bool            -- ^ are there files that have changed since the last build?+    , lpDirtyFiles     :: !(Maybe (Set FilePath))+    -- ^ Nothing == not dirty, Just == dirty. Note that the Set may be empty if+    -- we forced the build to treat packages as dirty. Also, the Set may not+    -- include all modified files.     , lpNewBuildCache  :: !(Map FilePath FileCacheInfo) -- ^ current state of the files     , lpFiles          :: !(Set (Path Abs File)) -- ^ all files used by this package     , lpComponents     :: !(Set NamedComponent)@@ -249,6 +255,9 @@     mappend _ Local = Local     mappend Snap Snap = Snap +data InstalledPackageLocation = InstalledTo InstallLocation | ExtraGlobal+    deriving (Show, Eq)+ data FileCacheInfo = FileCacheInfo     { fciModTime :: !ModTime     , fciSize :: !Word64@@ -322,3 +331,8 @@         DotCabalMainPath fp -> fp         DotCabalFilePath fp -> fp         DotCabalCFilePath fp -> fp++type InstalledMap = Map PackageName (Version, InstallLocation, Installed) -- TODO Version is now redundant and can be gleaned from Installed++data Installed = Library PackageIdentifier GhcPkgId | Executable PackageIdentifier+    deriving (Show, Eq, Ord)
src/Stack/Types/StackT.hs view
@@ -89,7 +89,7 @@ runStackTGlobal :: (MonadIO m,MonadBaseControl IO m)                 => Manager -> config -> GlobalOpts -> StackT config m a -> m a runStackTGlobal manager config GlobalOpts{..} m =-    runStackT manager globalLogLevel config globalTerminal globalReExec m+    runStackT manager globalLogLevel config globalTerminal (isJust globalReExecVersion) m  -- | Run a Stack action. runStackT :: (MonadIO m,MonadBaseControl IO m)@@ -170,7 +170,7 @@ runStackLoggingTGlobal :: MonadIO m                        => Manager -> GlobalOpts -> StackLoggingT m a -> m a runStackLoggingTGlobal manager GlobalOpts{..} m =-    runStackLoggingT manager globalLogLevel globalTerminal globalReExec m+    runStackLoggingT manager globalLogLevel globalTerminal (isJust globalReExecVersion) m  -- | Run the logging monad. runStackLoggingT :: MonadIO m
src/Stack/Upgrade.hs view
@@ -18,6 +18,7 @@ import           Development.GitRev          (gitHash) import           Network.HTTP.Client.Conduit (HasHttpManager, getHttpManager) import           Path+import           Path.IO import qualified Paths_stack as Paths import           Stack.Build import           Stack.Types.Build@@ -28,7 +29,6 @@ import           Stack.Types import           Stack.Types.Internal import           Stack.Types.StackT-import           System.IO.Temp              (withSystemTempDirectory) import           System.Process              (readProcess) import           System.Process.Run @@ -36,9 +36,8 @@         => Maybe String -- ^ git repository to use         -> Maybe AbstractResolver         -> m ()-upgrade gitRepo mresolver = withSystemTempDirectory "stack-upgrade" $ \tmp' -> do+upgrade gitRepo mresolver = withCanonicalizedSystemTempDirectory "stack-upgrade" $ \tmp -> do     menv <- getMinimalEnvOverride-    tmp <- parseAbsDir tmp'     mdir <- case gitRepo of       Just repo -> do         remote <- liftIO $ readProcess "git" ["ls-remote", repo, "master"] []
src/System/Process/Read.hs view
@@ -13,10 +13,12 @@   (readProcessStdout   ,tryProcessStdout   ,sinkProcessStdout+  ,sinkProcessStderrStdout   ,readProcess   ,EnvOverride(..)   ,unEnvOverride   ,mkEnvOverride+  ,modifyEnvOverride   ,envHelper   ,doesExecutableExist   ,findExecutable@@ -76,6 +78,7 @@     , eoPath :: [FilePath]     , eoExeCache :: IORef (Map FilePath (Either ReadProcessException (Path Abs File)))     , eoExeExtension :: String+    , eoPlatform :: Platform     }  -- | Get the environment variables from @EnvOverride@@@ -86,6 +89,15 @@ envSearchPath :: EnvOverride -> [FilePath] envSearchPath = eoPath +-- | Modify an EnvOverride+modifyEnvOverride :: MonadIO m+                  => EnvOverride+                  -> (Map Text Text -> Map Text Text)+                  -> m EnvOverride+modifyEnvOverride eo f = mkEnvOverride+    (eoPlatform eo)+    (f $ eoTextMap eo)+ -- | Create a new @EnvOverride@ mkEnvOverride :: MonadIO m               => Platform@@ -99,6 +111,7 @@         , eoPath = maybe [] (FP.splitSearchPath . T.unpack) (Map.lookup "PATH" tm)         , eoExeCache = ref         , eoExeExtension = if isWindows then ".exe" else ""+        , eoPlatform = platform         }   where     -- Fix case insensitivity of the PATH environment variable on Windows.@@ -233,7 +246,7 @@                menv                name                args-               (CL.mapM_ (\bytes -> liftIO (modifyIORef' stdoutBuffer (<> byteString bytes))))+               (CL.mapM_ (\bytes -> liftIO (modifyIORef' stderrBuffer (<> byteString bytes))))                (CL.iterM (\bytes -> liftIO (modifyIORef' stdoutBuffer (<> byteString bytes))) $=                 sinkStdout))           (\(ProcessExitedUnsuccessfully cp ec) ->
src/main/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-}@@ -13,7 +14,6 @@ import           Control.Exception import qualified Control.Exception.Lifted as EL import           Control.Monad hiding (mapM, forM)-import qualified Control.Monad.Catch as Catch import           Control.Monad.IO.Class import           Control.Monad.Logger import           Control.Monad.Reader (ask, asks, runReaderT)@@ -31,8 +31,10 @@ import qualified Data.Text as T import qualified Data.Text.IO as T import           Data.Traversable+import           Data.Typeable (Typeable) import           Data.Version (showVersion) import           Distribution.System (buildArch)+import           Distribution.Text (display) import           Development.GitRev (gitCommitCount) import           GHC.IO.Encoding (mkTextEncoding, textEncodingName) import           Network.HTTP.Client@@ -78,51 +80,6 @@ import           System.IO (hIsTerminalDevice, stderr, stdin, stdout, hSetBuffering, BufferMode(..), hPutStrLn, Handle, hGetEncoding, hSetEncoding) import           System.Process.Read -#ifdef WINDOWS-import System.Win32.Console (setConsoleCP, setConsoleOutputCP, getConsoleCP, getConsoleOutputCP)-#endif---- | Set the code page for this process as necessary. Only applies to Windows.--- See: https://github.com/commercialhaskell/stack/issues/738-fixCodePage :: (MonadIO m, Catch.MonadMask m, MonadLogger m) => m a -> m a-#ifdef WINDOWS-fixCodePage inner = do-    origCPI <- liftIO getConsoleCP-    origCPO <- liftIO getConsoleOutputCP--    let setInput = origCPI /= expected-        setOutput = origCPO /= expected-        fixInput-            | setInput = Catch.bracket_-                (liftIO $ do-                    setConsoleCP expected)-                (liftIO $ setConsoleCP origCPI)-            | otherwise = id-        fixOutput-            | setInput = Catch.bracket_-                (liftIO $ do-                    setConsoleOutputCP expected)-                (liftIO $ setConsoleOutputCP origCPO)-            | otherwise = id--    case (setInput, setOutput) of-        (False, False) -> return ()-        (True, True) -> warn ""-        (True, False) -> warn " input"-        (False, True) -> warn " output"--    fixInput $ fixOutput inner-  where-    expected = 65001 -- UTF-8-    warn typ = $logInfo $ T.concat-        [ "Setting"-        , typ-        , " codepage to UTF-8 (65001) to ensure correct output from GHC"-        ]-#else-fixCodePage = id-#endif- -- | Change the character encoding of the given Handle to transliterate -- on unsupported characters instead of throwing an exception hSetTranslit :: Handle -> IO ()@@ -157,7 +114,7 @@               -- See https://github.com/commercialhaskell/stack/issues/792             , [" (" ++ $gitCommitCount ++ " commits)" | $gitCommitCount /= ("1"::String) &&                                                         $gitCommitCount /= ("UNKNOWN" :: String)]-            , [" ", show buildArch]+            , [" ", display buildArch]             ]       let numericVersion :: Parser (a -> a)@@ -284,6 +241,10 @@                         "Run runghc"                         execCmd                         (execOptsParser $ Just "runghc")+             addCommand "eval"+                        "Evaluate some haskell code inline. Shortcut for 'stack exec ghc -- -e CODE'"+                        evalCmd+                        (evalOptsParser $ Just "CODE") -- metavar = "CODE"              addCommand "clean"                         "Clean the local packages"                         cleanCmd@@ -297,6 +258,10 @@                                            "and package version.") <>                                      value " " <>                                      showDefault))+             addCommand "query"+                        "Query general build information (experimental)"+                        queryCmd+                        (many $ strArgument $ metavar "SELECTOR...")              addSubCommands                  "ide"                  "IDE-specific commands"@@ -316,7 +281,13 @@                          "packages"                          "List all available local loadable packages"                          packagesCmd-                         (pure ()))+                         (pure ())+                     addCommand+                         "load-targets"+                         "List all load targets for a package target"+                         targetsCmd+                         (textArgument+                            (metavar "TARGET")))              addSubCommands                Docker.dockerCmdName                "Subcommands specific to Docker use"@@ -349,10 +320,15 @@              , " as a script interpreter, a\n'-- "              , stackProgName              , " [options] runghc [options]' comment is required."-             , "\nSee https://github.com/commercialhaskell/stack/blob/master/doc/GUIDE.md#ghcrunghc" ]+             , "\nSee https://github.com/commercialhaskell/stack/blob/release/doc/GUIDE.md#ghcrunghc" ]          throwIO exitCode        Right (global,run) -> do          when (globalLogLevel global == LevelDebug) $ hPutStrLn stderr versionString'+         case globalReExecVersion global of+             Just expectVersion+                 | expectVersion /= showVersion Meta.version ->+                     throwIO $ InvalidReExecVersion expectVersion (showVersion Meta.version)+             _ -> return ()          run global `catch` \e -> do             -- This special handler stops "stack: " from being printed before the             -- exception@@ -368,10 +344,9 @@ -- support others later). pathCmd :: [Text] -> GlobalOpts -> IO () pathCmd keys go =-    withBuildConfigAndLock+    withBuildConfig         go-        (\_ ->-         do env <- ask+        (do env <- ask             let cfg = envConfig env                 bc = envConfigBuildConfig cfg             menv <- getMinimalEnvOverride@@ -533,13 +508,16 @@     readVersion = do         s <- readerAsk         case parseCompilerVersion ("ghc-" <> T.pack s) of-            Nothing -> readerError $ "Invalid version: " ++ s+            Nothing ->+                case parseCompilerVersion (T.pack s) of+                    Nothing -> readerError $ "Invalid version: " ++ s+                    Just x -> return x             Just x -> return x  setupCmd :: SetupCmdOpts -> GlobalOpts -> IO () setupCmd SetupCmdOpts{..} go@GlobalOpts{..} = do   (manager,lc) <- loadConfigWithOpts go-  withUserFileLock (configStackRoot $ lcConfig lc) $ \lk ->+  withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->    runStackTGlobal manager (lcConfig lc) go $       Docker.reexecWithOptionalContainer           (lcProjectRoot lc)@@ -556,7 +534,7 @@                                  )               miniConfig <- loadMiniConfig (lcConfig lc)               mpaths <- runStackTGlobal manager miniConfig go $-                  ensureGHC SetupOpts+                  ensureCompiler SetupOpts                   { soptsInstallIfMissing = True                   , soptsUseSystem =                     (configSystemGHC $ lcConfig lc)@@ -573,11 +551,14 @@                   , soptsStackSetupYaml = scoStackSetupYaml                   , soptsGHCBindistURL = scoGHCBindistURL                   }+              let compiler = case wantedCompiler of+                      GhcVersion _ -> "GHC"+                      GhcjsVersion {} -> "GHCJS"               case mpaths of-                  Nothing -> $logInfo "stack will use the GHC on your PATH"-                  Just _ -> $logInfo "stack will use a locally installed GHC"+                  Nothing -> $logInfo $ "stack will use the " <> compiler <> " on your PATH"+                  Just _ -> $logInfo $ "stack will use a locally installed " <> compiler               $logInfo "For more information on paths, see 'stack path' and 'stack exec env'"-              $logInfo "To use this GHC and packages outside of a project, consider using:"+              $logInfo $ "To use this " <> compiler <> " and packages outside of a project, consider using:"               $logInfo "stack ghc, stack ghci, stack runghc, or stack exec"               )           Nothing@@ -596,10 +577,11 @@ -- this to an even more fine-grain locking approach. -- withUserFileLock :: (MonadBaseControl IO m, MonadIO m)-                 => Path Abs Dir+                 => GlobalOpts+                 -> Path Abs Dir                  -> (Maybe FileLock -> m a)                  -> m a-withUserFileLock dir act = do+withUserFileLock go@GlobalOpts{} dir act = do     env <- liftIO getEnvironment     let toLock = lookup "STACK_LOCK" env == Just "true"     if toLock@@ -615,12 +597,15 @@                         case fstTry of                           Just lk -> EL.finally (act $ Just lk) (liftIO $ unlockFile lk)                           Nothing ->-                            do liftIO $ hPutStrLn stderr $ "Failed to grab lock ("++show pth++-                                                   "); other stack instance running.  Waiting..."+                            do let chatter = globalLogLevel go /= LevelOther "silent"+                               when chatter $+                                 liftIO $ hPutStrLn stderr $ "Failed to grab lock ("++show pth+++                                                     "); other stack instance running.  Waiting..."                                EL.bracket (liftIO $ lockFile (toFilePath pth) Exclusive)                                           (liftIO . unlockFile)                                           (\lk -> do-                                            liftIO $ hPutStrLn stderr "Lock acquired, proceeding."+                                            when chatter $+                                              liftIO $ hPutStrLn stderr "Lock acquired, proceeding."                                             act $ Just lk))         else act Nothing @@ -629,7 +614,7 @@            -> IO () withConfigAndLock go@GlobalOpts{..} inner = do     (manager, lc) <- loadConfigWithOpts go-    withUserFileLock (configStackRoot $ lcConfig lc) $ \lk ->+    withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->      runStackTGlobal manager (lcConfig lc) go $         Docker.reexecWithOptionalContainer (lcProjectRoot lc)             Nothing@@ -671,7 +656,7 @@ withBuildConfigExt go@GlobalOpts{..} mbefore inner mafter = do     (manager, lc) <- loadConfigWithOpts go -    withUserFileLock (configStackRoot $ lcConfig lc) $ \lk0 -> do+    withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk0 -> do       -- A local bit of state for communication between callbacks:       curLk <- newIORef lk0       let inner' lk =@@ -680,7 +665,7 @@             -- trade in the lock here.             do dir <- installationRootDeps                -- Hand-over-hand locking:-               withUserFileLock dir $ \lk2 -> do+               withUserFileLock go dir $ \lk2 -> do                  liftIO $ writeIORef curLk lk2                  liftIO $ munlockFile lk                  inner lk2@@ -721,7 +706,7 @@     NoFileWatch -> inner $ const $ return ()   where     inner setLocalFiles = withBuildConfigAndLock go $ \lk ->-        globalFixCodePage go $ Stack.Build.build setLocalFiles lk opts+        Stack.Build.build setLocalFiles lk opts     getProjectRoot = do         (manager, lc) <- loadConfigWithOpts go         bconfig <-@@ -729,14 +714,6 @@             lcLoadBuildConfig lc (globalResolver go)         return (bcRoot bconfig) -globalFixCodePage :: (Catch.MonadMask m, MonadIO m, MonadLogger m)-                  => GlobalOpts-                  -> m a-                  -> m a-globalFixCodePage go-    | globalModifyCodePage go = fixCodePage-    | otherwise = id- uninstallCmd :: [String] -> GlobalOpts -> IO () uninstallCmd _ go = withConfigAndLock go $ do     $logError "stack does not manage installations in global locations"@@ -755,7 +732,7 @@     getMinimalEnvOverride >>= Stack.PackageIndex.updateAllIndices  upgradeCmd :: (Bool, String) -> GlobalOpts -> IO ()-upgradeCmd (fromGit, repo) go = withConfigAndLock go $ globalFixCodePage go $+upgradeCmd (fromGit, repo) go = withConfigAndLock go $     upgrade (if fromGit then Just repo else Nothing) (globalResolver go)  -- | Upload to Hackage@@ -818,11 +795,11 @@     case eoExtra of         ExecOptsPlain -> do             (manager,lc) <- liftIO $ loadConfigWithOpts go-            withUserFileLock (configStackRoot $ lcConfig lc) $ \lk ->+            withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->              runStackTGlobal manager (lcConfig lc) go $                 Docker.execWithOptionalContainer                     (lcProjectRoot lc)-                    (return (cmd, args, [], id))+                    (\_ _ -> return (cmd, args, [], []))                     -- Unlock before transferring control away, whether using docker or not:                     (Just $ munlockFile lk)                     (runStackTGlobal manager (lcConfig lc) go $ do@@ -832,19 +809,29 @@         ExecOptsEmbellished {..} ->            withBuildConfigAndLock go $ \lk -> do                let targets = concatMap words eoPackages-               unless (null targets) $ globalFixCodePage go $+               unless (null targets) $                    Stack.Build.build (const $ return ()) lk defaultBuildOpts                        { boptsTargets = map T.pack targets                        }                munlockFile lk -- Unlock before transferring control away.                exec eoEnvSettings cmd args +-- | Evaluate some haskell code inline.+evalCmd :: EvalOpts -> GlobalOpts -> IO ()+evalCmd EvalOpts {..} go@GlobalOpts {..} = execCmd execOpts go+    where+      execOpts =+          ExecOpts { eoCmd = Just "ghc"+                   , eoArgs = ["-e", evalArg]+                   , eoExtra = evalExtra+                   }+ -- | Run GHCi in the context of a project. ghciCmd :: GhciOpts -> GlobalOpts -> IO () ghciCmd ghciOpts go@GlobalOpts{..} =   withBuildConfigAndLock go $ \lk -> do     let packageTargets = concatMap words (ghciAdditionalPackages ghciOpts)-    unless (null packageTargets) $ globalFixCodePage go $+    unless (null packageTargets) $        Stack.Build.build (const $ return ()) lk defaultBuildOpts            { boptsTargets = map T.pack packageTargets            }@@ -857,7 +844,7 @@     withBuildConfig go $ -- No locking needed.       ide targets args --- | Run ide-backend in the context of a project.+-- | List packages in the project. packagesCmd :: () -> GlobalOpts -> IO () packagesCmd () go@GlobalOpts{..} =     withBuildConfig go $@@ -869,12 +856,24 @@                      parsePackageNameFromFilePath cabalfp          forM_ locals (liftIO . putStrLn . packageNameString) +-- | List load targets for a package target.+targetsCmd :: Text -> GlobalOpts -> IO ()+targetsCmd target go@GlobalOpts{..} =+    withBuildConfig go $+    do (_realTargets,_,pkgs) <- ghciSetup Nothing [target]+       pwd <- getWorkingDir+       targets <-+           fmap+               (concat . snd . unzip)+               (mapM (getPackageOptsAndTargetFiles pwd) pkgs)+       forM_ targets (liftIO . putStrLn)+ -- | Pull the current Docker image. dockerPullCmd :: () -> GlobalOpts -> IO () dockerPullCmd _ go@GlobalOpts{..} = do     (manager,lc) <- liftIO $ loadConfigWithOpts go     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->      runStackTGlobal manager (lcConfig lc) go $        Docker.preventInContainer Docker.pull @@ -883,7 +882,7 @@ dockerResetCmd keepHome go@GlobalOpts{..} = do     (manager,lc) <- liftIO (loadConfigWithOpts go)     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->      runStackLoggingTGlobal manager go $         Docker.preventInContainer $ Docker.reset (lcProjectRoot lc) keepHome @@ -892,7 +891,7 @@ dockerCleanupCmd cleanupOpts go@GlobalOpts{..} = do     (manager,lc) <- liftIO $ loadConfigWithOpts go     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->      runStackTGlobal manager (lcConfig lc) go $         Docker.preventInContainer $             Docker.cleanup cleanupOpts@@ -903,8 +902,7 @@         go         Nothing         (\lk ->-              do globalFixCodePage go $-                     Stack.Build.build+              do Stack.Build.build                          (const (return ()))                          lk                          defaultBuildOpts@@ -965,3 +963,19 @@ listDependenciesCmd :: Text -> GlobalOpts -> IO () listDependenciesCmd sep go = withBuildConfig go (listDependencies sep')   where sep' = T.replace "\\t" "\t" (T.replace "\\n" "\n" sep)++-- | Query build information+queryCmd :: [String] -> GlobalOpts -> IO ()+queryCmd selectors go = withBuildConfig go $ queryBuildInfo $ map T.pack selectors++data MainException = InvalidReExecVersion String String+     deriving (Typeable)+instance Exception MainException+instance Show MainException where+    show (InvalidReExecVersion expected actual) = concat+        [ "When re-executing '"+        , stackProgName+        , "' in a container, the incorrect version was found\nExpected: "+        , expected+        , "; found: "+        , actual]
src/test/Network/HTTP/Download/VerifiedSpec.hs view
@@ -9,16 +9,14 @@ import Network.HTTP.Client.Conduit import Network.HTTP.Download.Verified import Path+import Path.IO import System.Directory-import System.IO.Temp import Test.Hspec hiding (shouldNotBe, shouldNotReturn)   -- TODO: share across test files withTempDir :: (Path Abs Dir -> IO a) -> IO a-withTempDir f = withSystemTempDirectory "NHD_VerifiedSpec" $ \dirFp -> do-  dir <- parseAbsDir dirFp-  f dir+withTempDir = withCanonicalizedSystemTempDirectory "NHD_VerifiedSpec"   -- | An example path to download the exampleReq.
src/test/Stack/BuildPlanSpec.hs view
@@ -14,8 +14,8 @@ import Network.HTTP.Conduit (Manager) import Prelude -- Fix redundant import warnings import System.Directory-import System.IO.Temp import System.Environment+import System.IO.Temp (withSystemTempDirectory) import Test.Hspec import Stack.Config import Stack.Types
src/test/Stack/ConfigSpec.hs view
@@ -10,11 +10,12 @@ import Data.Monoid import Network.HTTP.Conduit (Manager) import Path+import Path.IO --import System.FilePath import Prelude -- Fix redundant import warnings import System.Directory-import System.IO.Temp import System.Environment+import System.IO.Temp (withSystemTempDirectory) import Test.Hspec  import Stack.Config@@ -85,8 +86,7 @@       bcRoot bc `shouldBe` parentDir      it "respects the STACK_YAML env variable" $ \T{..} -> inTempDir $ do-      withSystemTempDirectory "config-is-here" $ \dirFilePath -> do-        dir <- parseAbsDir dirFilePath+      withCanonicalizedSystemTempDirectory "config-is-here" $ \dir -> do         let stackYamlFp = toFilePath (dir </> stackDotYaml)         writeFile stackYamlFp sampleConfig         withEnvVar "STACK_YAML" stackYamlFp $ do
src/test/Stack/PackageDumpSpec.hs view
@@ -158,7 +158,7 @@         menv' <- getEnvOverride buildPlatform         menv <- mkEnvOverride buildPlatform $ Map.delete "GHC_PACKAGE_PATH" $ unEnvOverride menv'         icache <- newInstalledCache-        ghcPkgDump menv Ghc Nothing+        ghcPkgDump menv Ghc []             $  conduitDumpPackage             =$ addProfiling icache             =$ addHaddock icache@@ -168,7 +168,7 @@         menv' <- getEnvOverride buildPlatform         menv <- mkEnvOverride buildPlatform $ Map.delete "GHC_PACKAGE_PATH" $ unEnvOverride menv'         icache <- newInstalledCache-        m <- runNoLoggingT $ ghcPkgDump menv Ghc Nothing+        m <- runNoLoggingT $ ghcPkgDump menv Ghc []             $  conduitDumpPackage             =$ addProfiling icache             =$ addHaddock icache
stack.cabal view
@@ -1,5 +1,5 @@ name:                stack-version:             0.1.5.0+version:             0.1.6.0 synopsis:            The Haskell Tool Stack description:         Please see the README.md for usage information, and                      the wiki on Github for more details.  Also, note that@@ -14,7 +14,21 @@ build-type:          Simple cabal-version:       >=1.10 homepage:            https://github.com/commercialhaskell/stack-extra-source-files:  README.md ChangeLog.md+extra-source-files:  README.md+                     ChangeLog.md+                     CONTRIBUTING.md+                     doc/GUIDE.md+                     doc/build_command.md+                     doc/install_and_upgrade.md+                     doc/MAINTAINER_GUIDE.md+                     doc/dependency_visualization.md+                     doc/nonstandard_project_init.md+                     doc/SIGNING_KEY.md+                     doc/docker_integration.md+                     doc/shell_autocompletion.md+                     doc/architecture.md+                     doc/faq.md+                     doc/yaml_configuration.md                       -- Glob would be nice, but apparently Cabal doesn't support it:                      --     cabal: filepath wildcard 'test/package-dump/*.txt' does not match any files.@@ -37,6 +51,7 @@                      Options.Applicative.Args                      Stack.BuildPlan                      Stack.Config+                     Stack.Config.Docker                      Stack.Constants                      Stack.Docker                      Stack.Docker.GlobalDB@@ -56,6 +71,7 @@                      Stack.Image                      Stack.SDist                      Stack.Setup+                     Stack.Setup.Installed                      Stack.Solver                      Stack.Types                      Stack.Types.Internal@@ -104,6 +120,7 @@                      Distribution.Version.Extra   build-depends:     Cabal >= 1.18.1.5                    , aeson >= 0.8.0.2+                   , ansi-terminal >= 0.6.2.3                    , async >= 2.0.2                    , attoparsec >= 0.12.1.5                    , base >= 4 && <5@@ -131,6 +148,7 @@                    , fsnotify >= 0.2.1                    , gitrev >= 1.1                    , hashable >= 1.2.3.2+                   , hpc                    , http-client >= 0.4.17                    , http-client-tls >= 0.2.2                    , http-conduit >= 2.1.7@@ -177,6 +195,7 @@                    , project-template >= 0.2   if os(windows)     cpp-options:     -DWINDOWS+    build-depends:   Win32   else     build-depends:   unix >= 2.7.0.1   default-language:  Haskell2010@@ -185,7 +204,7 @@   hs-source-dirs: src/main   main-is:        Main.hs   ghc-options:    -Wall -threaded -rtsopts-  other-modules:     Paths_stack+  other-modules:  Paths_stack    build-depends:  base >=4.7 && < 5                 , bytestring >= 0.10.4.0
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-3.0+resolver: lts-3.7 extra-deps: - ignore-0.1.1.0 - binary-tagged-0.1.1.0@@ -8,7 +8,5 @@ image:   container:     base: "fpco/ubuntu-with-libgmp:14.04"-    add:-      man/: /usr/local/share/man/     entrypoints:       - stack