Merge branch 'incremental' into new-upload

Conflicts:
	ChangeLog.md
	stackage.cabal
This commit is contained in:
Michael Snoyman 2015-03-13 14:45:55 +02:00
commit 51f3aa1d10
22 changed files with 1316 additions and 194 deletions

3
.dir-locals.el Normal file
View File

@ -0,0 +1,3 @@
((haskell-mode . ((haskell-process-type . cabal-repl)
(haskell-indent-spaces . 4)
(hindent-style . "johan-tibell"))))

8
.dockerignore Normal file
View File

@ -0,0 +1,8 @@
dist
builds
logs
.cabal-sandbox
cabal.sandbox.config
tarballs
*.yaml
.git

24
.travis.yml Normal file
View File

@ -0,0 +1,24 @@
env:
- CABALVER=1.20 GHCVER=7.8.4
cache:
directories:
- $HOME/.ghc
- $HOME/.cabal
# Note: the distinction between `before_install` and `install` is not important.
before_install:
- travis_retry sudo add-apt-repository -y ppa:hvr/ghc
- travis_retry sudo apt-get update
- travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER # see note about happy/alex
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
install:
- cabal --version
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
- travis_retry cabal update
- cabal install -j
# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
script:
- ./dist/build/stackage/stackage check

View File

@ -1,7 +1,28 @@
## 0.4.0 ## Unreleased
* Upload bundle V2 stuff * Upload bundle V2 stuff
## 0.5.2
* Upload LTS to Hackage with the name LTSHaskell
## 0.5.1
* `loadBuildConstraints`
* More command line options
## 0.5.0
* Print "Still Alive" while checking, to avoid Travis timeouts
* Include `stackage upload-nightly` command
* Optional plan checking
## 0.4.0
* Command line uses optparse-applicative with additional options
* Library profiling support during build
* Remove cfGlobalFlags (just use package-specific flags)
## 0.3.1 ## 0.3.1
* Added `justCheck` and `stackage check` command line. * Added `justCheck` and `stackage check` command line.

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM ubuntu:12.04
ENV HOME /home/stackage
ENV LANG en_US.UTF-8
RUN mkdir /home/stackage -p
RUN locale-gen en_US.UTF-8
RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common python-software-properties
RUN DEBIAN_FRONTEND=noninteractive add-apt-repository ppa:hvr/ghc -y
ADD debian-bootstrap.sh /tmp/debian-bootstrap.sh
RUN DEBIAN_FRONTEND=noninteractive bash /tmp/debian-bootstrap.sh
RUN rm /tmp/debian-bootstrap.sh
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y cabal-install-1.20 ghc-7.8.4 alex-3.1.3 happy-1.19.4
ENV PATH /home/stackage/.cabal/bin:/usr/local/sbin:/usr/local/bin:/opt/ghc/7.8.4/bin:/opt/cabal/1.20/bin:/opt/alex/3.1.3/bin:/opt/happy/1.19.4/bin:/usr/sbin:/usr/bin:/sbin:/bin
RUN cabal update
ADD . /tmp/stackage
RUN cd /tmp/stackage && cabal install . hscolour cabal-install --constraint "Cabal < 1.22" && cp $HOME/.cabal/bin/* /usr/local/bin && rm -rf $HOME/.cabal $HOME/.ghc /tmp/stackage
RUN cd /home/stackage && cabal update && stackage check

View File

@ -49,6 +49,28 @@ build by running:
cabal install stackage cabal install stackage
stackage nightly stackage nightly
### Docker
Note: This method is currently considered experimental.
If you'd like to check a build plan, or perform an entire build, without
specially configuring your system, Docker may be a good approach. To check if
some modifications to `build-constraints.yaml` are valid, try the following:
1. Create a local clone of the `stackage` repo
2. Make modifications to your local `build-constraints.yaml`
3. Inside the `stackage` working directory, run the following:
```
$ docker run -it --rm -v $(pwd):/stackage -w /stackage snoyberg/stackage /bin/bash -c 'cabal update && stackage check'
```
Similarly, if you'd like to perform an entire build, you can replace the last step with:
```
$ docker run -it --rm -v $(pwd):/stackage -w /stackage snoyberg/stackage /bin/bash -c 'cabal update && stackage nightly --skip-upload'
```
## Processing ## Processing
The following describes at a high level the series of steps for processing The following describes at a high level the series of steps for processing

View File

@ -10,6 +10,9 @@ module Stackage.BuildConstraints
, SystemInfo (..) , SystemInfo (..)
, getSystemInfo , getSystemInfo
, defaultBuildConstraints , defaultBuildConstraints
, toBC
, BuildConstraintsSource (..)
, loadBuildConstraints
) where ) where
import Control.Monad.Writer.Strict (execWriter, tell) import Control.Monad.Writer.Strict (execWriter, tell)
@ -21,7 +24,7 @@ import Distribution.System (Arch, OS)
import qualified Distribution.System import qualified Distribution.System
import Distribution.Version (anyVersion) import Distribution.Version (anyVersion)
import Filesystem (isFile) import Filesystem (isFile)
import Network.HTTP.Client (Manager, httpLbs, responseBody) import Network.HTTP.Client (Manager, httpLbs, responseBody, Request)
import Stackage.CorePackages import Stackage.CorePackages
import Stackage.Prelude import Stackage.Prelude
@ -88,12 +91,13 @@ data BuildConstraints = BuildConstraints
} }
data PackageConstraints = PackageConstraints data PackageConstraints = PackageConstraints
{ pcVersionRange :: VersionRange { pcVersionRange :: VersionRange
, pcMaintainer :: Maybe Maintainer , pcMaintainer :: Maybe Maintainer
, pcTests :: TestState , pcTests :: TestState
, pcHaddocks :: TestState , pcHaddocks :: TestState
, pcBuildBenchmarks :: Bool , pcBuildBenchmarks :: Bool
, pcFlagOverrides :: Map FlagName Bool , pcFlagOverrides :: Map FlagName Bool
, pcEnableLibProfile :: Bool
} }
deriving (Show, Eq) deriving (Show, Eq)
instance ToJSON PackageConstraints where instance ToJSON PackageConstraints where
@ -103,6 +107,7 @@ instance ToJSON PackageConstraints where
, "haddocks" .= pcHaddocks , "haddocks" .= pcHaddocks
, "build-benchmarks" .= pcBuildBenchmarks , "build-benchmarks" .= pcBuildBenchmarks
, "flags" .= Map.mapKeysWith const unFlagName pcFlagOverrides , "flags" .= Map.mapKeysWith const unFlagName pcFlagOverrides
, "library-profiling" .= pcEnableLibProfile
] ]
where where
addMaintainer = maybe id (\m -> (("maintainer" .= m):)) pcMaintainer addMaintainer = maybe id (\m -> (("maintainer" .= m):)) pcMaintainer
@ -115,6 +120,7 @@ instance FromJSON PackageConstraints where
pcBuildBenchmarks <- o .: "build-benchmarks" pcBuildBenchmarks <- o .: "build-benchmarks"
pcFlagOverrides <- Map.mapKeysWith const mkFlagName <$> o .: "flags" pcFlagOverrides <- Map.mapKeysWith const mkFlagName <$> o .: "flags"
pcMaintainer <- o .:? "maintainer" pcMaintainer <- o .:? "maintainer"
pcEnableLibProfile <- fmap (fromMaybe True) (o .:? "library-profiling")
return PackageConstraints {..} return PackageConstraints {..}
-- | The proposed plan from the requirements provided by contributors. -- | The proposed plan from the requirements provided by contributors.
@ -122,15 +128,32 @@ instance FromJSON PackageConstraints where
-- Checks the current directory for a build-constraints.yaml file and uses it -- Checks the current directory for a build-constraints.yaml file and uses it
-- if present. If not, downloads from Github. -- if present. If not, downloads from Github.
defaultBuildConstraints :: Manager -> IO BuildConstraints defaultBuildConstraints :: Manager -> IO BuildConstraints
defaultBuildConstraints man = do defaultBuildConstraints = loadBuildConstraints BCSDefault
e <- isFile fp
if e data BuildConstraintsSource
then decodeFileEither (fpToString fp) >>= either throwIO toBC = BCSDefault
else httpLbs req man >>= | BCSFile FilePath
either throwIO toBC . decodeEither' . toStrict . responseBody | BCSWeb Request
deriving (Show)
loadBuildConstraints :: BuildConstraintsSource -> Manager -> IO BuildConstraints
loadBuildConstraints bcs man = do
case bcs of
BCSDefault -> do
e <- isFile fp0
if e
then loadFile fp0
else loadReq req0
BCSFile fp -> loadFile fp
BCSWeb req -> loadReq req
where where
fp = "build-constraints.yaml" fp0 = "build-constraints.yaml"
req = "https://raw.githubusercontent.com/fpco/stackage/master/build-constraints.yaml" req0 = "https://raw.githubusercontent.com/fpco/stackage/master/build-constraints.yaml"
loadFile fp = decodeFileEither (fpToString fp) >>= either throwIO toBC
loadReq req = httpLbs req man >>=
either throwIO toBC . decodeEither' . toStrict . responseBody
getSystemInfo :: IO SystemInfo getSystemInfo :: IO SystemInfo
getSystemInfo = do getSystemInfo = do
@ -144,24 +167,24 @@ getSystemInfo = do
siArch = Distribution.System.X86_64 siArch = Distribution.System.X86_64
data ConstraintFile = ConstraintFile data ConstraintFile = ConstraintFile
{ cfGlobalFlags :: Map FlagName Bool { cfPackageFlags :: Map PackageName (Map FlagName Bool)
, cfPackageFlags :: Map PackageName (Map FlagName Bool)
, cfSkippedTests :: Set PackageName , cfSkippedTests :: Set PackageName
, cfExpectedTestFailures :: Set PackageName , cfExpectedTestFailures :: Set PackageName
, cfExpectedHaddockFailures :: Set PackageName , cfExpectedHaddockFailures :: Set PackageName
, cfSkippedBenchmarks :: Set PackageName , cfSkippedBenchmarks :: Set PackageName
, cfPackages :: Map Maintainer (Vector Dependency) , cfPackages :: Map Maintainer (Vector Dependency)
, cfGithubUsers :: Map Text (Set Text) , cfGithubUsers :: Map Text (Set Text)
, cfSkippedLibProfiling :: Set PackageName
} }
instance FromJSON ConstraintFile where instance FromJSON ConstraintFile where
parseJSON = withObject "ConstraintFile" $ \o -> do parseJSON = withObject "ConstraintFile" $ \o -> do
cfGlobalFlags <- goFlagMap <$> o .: "global-flags"
cfPackageFlags <- (goPackageMap . fmap goFlagMap) <$> o .: "package-flags" cfPackageFlags <- (goPackageMap . fmap goFlagMap) <$> o .: "package-flags"
cfSkippedTests <- getPackages o "skipped-tests" cfSkippedTests <- getPackages o "skipped-tests"
cfExpectedTestFailures <- getPackages o "expected-test-failures" cfExpectedTestFailures <- getPackages o "expected-test-failures"
cfExpectedHaddockFailures <- getPackages o "expected-haddock-failures" cfExpectedHaddockFailures <- getPackages o "expected-haddock-failures"
cfSkippedBenchmarks <- getPackages o "skipped-benchmarks" cfSkippedBenchmarks <- getPackages o "skipped-benchmarks"
cfSkippedLibProfiling <- getPackages o "skipped-profiling"
cfPackages <- o .: "packages" cfPackages <- o .: "packages"
>>= mapM (mapM toDep) >>= mapM (mapM toDep)
. Map.mapKeysWith const Maintainer . Map.mapKeysWith const Maintainer
@ -196,6 +219,7 @@ toBC ConstraintFile {..} = do
mpair = lookup name revmap mpair = lookup name revmap
pcMaintainer = fmap fst mpair pcMaintainer = fmap fst mpair
pcVersionRange = maybe anyVersion snd mpair pcVersionRange = maybe anyVersion snd mpair
pcEnableLibProfile = not (name `member` cfSkippedLibProfiling)
pcTests pcTests
| name `member` cfSkippedTests = Don'tBuild | name `member` cfSkippedTests = Don'tBuild
| name `member` cfExpectedTestFailures = ExpectFailure | name `member` cfExpectedTestFailures = ExpectFailure
@ -205,7 +229,6 @@ toBC ConstraintFile {..} = do
| name `member` cfExpectedHaddockFailures = ExpectFailure | name `member` cfExpectedHaddockFailures = ExpectFailure
| otherwise = ExpectSuccess | otherwise = ExpectSuccess
pcFlagOverrides = fromMaybe mempty (lookup name cfPackageFlags) ++ pcFlagOverrides = fromMaybe mempty $ lookup name cfPackageFlags
cfGlobalFlags
bcGithubUsers = cfGithubUsers bcGithubUsers = cfGithubUsers

View File

@ -14,6 +14,7 @@ module Stackage.BuildPlan
, PackagePlan (..) , PackagePlan (..)
, newBuildPlan , newBuildPlan
, makeToolMap , makeToolMap
, getLatestAllowedPlans
) where ) where
import Control.Monad.State.Strict (execState, get, put) import Control.Monad.State.Strict (execState, get, put)
@ -90,9 +91,9 @@ instance FromJSON PackagePlan where
ppDesc <- o .: "description" ppDesc <- o .: "description"
return PackagePlan {..} return PackagePlan {..}
newBuildPlan :: MonadIO m => BuildConstraints -> m BuildPlan -- | Make a build plan given these package set and build constraints.
newBuildPlan bc@BuildConstraints {..} = liftIO $ do newBuildPlan :: MonadIO m => Map PackageName PackagePlan -> BuildConstraints -> m BuildPlan
packagesOrig <- getLatestDescriptions (isAllowed bc) (mkPackagePlan bc) newBuildPlan packagesOrig bc@BuildConstraints {..} = liftIO $ do
let toolMap = makeToolMap packagesOrig let toolMap = makeToolMap packagesOrig
packages = populateUsers $ removeUnincluded bc toolMap packagesOrig packages = populateUsers $ removeUnincluded bc toolMap packagesOrig
toolNames :: [ExeName] toolNames :: [ExeName]
@ -205,3 +206,9 @@ mkPackagePlan bc gpd = do
getFlag MkFlag {..} = getFlag MkFlag {..} =
(flagName, fromMaybe flagDefault $ lookup flagName overrides) (flagName, fromMaybe flagDefault $ lookup flagName overrides)
flags = mapFromList $ map getFlag $ genPackageFlags gpd flags = mapFromList $ map getFlag $ genPackageFlags gpd
getLatestAllowedPlans :: MonadIO m => BuildConstraints -> m (Map PackageName PackagePlan)
getLatestAllowedPlans bc =
getLatestDescriptions
(isAllowed bc)
(mkPackagePlan bc)

View File

@ -1,3 +1,4 @@
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE NoImplicitPrelude #-}
@ -7,28 +8,38 @@
-- | Confirm that a build plan has a consistent set of dependencies. -- | Confirm that a build plan has a consistent set of dependencies.
module Stackage.CheckBuildPlan module Stackage.CheckBuildPlan
( checkBuildPlan ( checkBuildPlan
, BadBuildPlan
) where ) where
import Control.Monad.Writer.Strict (Writer, execWriter, tell) import Control.Monad.Writer.Strict (Writer, execWriter, tell)
import qualified Data.Text as T import qualified Data.Map.Strict as M
import qualified Data.Text as T
import Stackage.BuildConstraints import Stackage.BuildConstraints
import Stackage.BuildPlan import Stackage.BuildPlan
import Stackage.PackageDescription import Stackage.PackageDescription
import Stackage.Prelude import Stackage.Prelude
-- FIXME check cycles in dependencies, only looking at libraries and -- | Check the build plan for missing deps, wrong versions, etc.
-- executables checkBuildPlan :: (MonadThrow m) => BuildPlan -> m ()
checkBuildPlan :: MonadThrow m => BuildPlan -> m ()
checkBuildPlan BuildPlan {..} checkBuildPlan BuildPlan {..}
| null errs' = return () | null errs' = return ()
| otherwise = throwM errs | otherwise = throwM errs
where where
allPackages = siCorePackages bpSystemInfo ++ map ppVersion bpPackages allPackages = map (,mempty) (siCorePackages bpSystemInfo) ++
map (ppVersion &&& M.keys . M.filter libAndExe . sdPackages . ppDesc) bpPackages
errs@(BadBuildPlan errs') = errs@(BadBuildPlan errs') =
execWriter $ mapM_ (checkDeps allPackages) $ mapToList bpPackages execWriter $ mapM_ (checkDeps allPackages) $ mapToList bpPackages
-- Only looking at libraries and executables, benchmarks and tests
-- are allowed to create cycles (e.g. test-framework depends on
-- text, which uses test-framework in its test-suite).
libAndExe (DepInfo cs _) = any (flip elem [CompLibrary,CompExecutable]) cs
checkDeps :: Map PackageName Version -- | For a given package name and plan, check that its dependencies are:
--
-- 1. Existent (existing in the provided package map)
-- 2. Within version range
-- 3. Check for dependency cycles.
checkDeps :: Map PackageName (Version,[PackageName])
-> (PackageName, PackagePlan) -> (PackageName, PackagePlan)
-> Writer BadBuildPlan () -> Writer BadBuildPlan ()
checkDeps allPackages (user, pb) = checkDeps allPackages (user, pb) =
@ -37,8 +48,16 @@ checkDeps allPackages (user, pb) =
go (dep, diRange -> range) = go (dep, diRange -> range) =
case lookup dep allPackages of case lookup dep allPackages of
Nothing -> tell $ BadBuildPlan $ singletonMap (dep, Nothing) errMap Nothing -> tell $ BadBuildPlan $ singletonMap (dep, Nothing) errMap
Just version Just (version,deps)
| version `withinRange` range -> return () | version `withinRange` range ->
occursCheck allPackages
(\d v ->
tell $ BadBuildPlan $ singletonMap
(d,v)
errMap)
dep
deps
[]
| otherwise -> tell $ BadBuildPlan $ singletonMap | otherwise -> tell $ BadBuildPlan $ singletonMap
(dep, Just version) (dep, Just version)
errMap errMap
@ -51,6 +70,38 @@ checkDeps allPackages (user, pb) =
, puGithubPings = ppGithubPings pb , puGithubPings = ppGithubPings pb
} }
-- | Check whether the package(s) occurs within its own dependency
-- tree.
occursCheck
:: Monad m
=> Map PackageName (Version,[PackageName])
-- ^ All packages.
-> (PackageName -> Maybe Version -> m ())
-- ^ Report an erroneous package.
-> PackageName
-- ^ Starting package to check for cycles in.
-> [PackageName]
-- ^ Dependencies of the package.
-> [PackageName]
-- ^ Previously seen packages up the dependency tree.
-> m ()
occursCheck allPackages reportError =
go
where
go pkg deps seen =
case find (flip elem seen) deps of
Just cyclic ->
reportError cyclic $
fmap fst (lookup cyclic allPackages)
Nothing ->
forM_ deps $
\pkg' ->
case lookup pkg' allPackages of
Just (_v,deps')
| pkg' /= pkg -> go pkg' deps' seen'
_ -> return ()
where seen' = pkg : seen
data PkgUser = PkgUser data PkgUser = PkgUser
{ puName :: PackageName { puName :: PackageName
, puVersion :: Version , puVersion :: Version

View File

@ -4,9 +4,14 @@
module Stackage.CompleteBuild module Stackage.CompleteBuild
( BuildType (..) ( BuildType (..)
, BumpType (..) , BumpType (..)
, BuildFlags (..)
, completeBuild , completeBuild
, justCheck , justCheck
, justUploadNightly
) where ) where
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (withAsync)
import Data.Default.Class (def) import Data.Default.Class (def)
import Data.Semigroup (Max (..), Option (..)) import Data.Semigroup (Max (..), Option (..))
import Data.Text.Read (decimal) import Data.Text.Read (decimal)
@ -22,8 +27,20 @@ import Stackage.Prelude
import Stackage.ServerBundle import Stackage.ServerBundle
import Stackage.UpdateBuildPlan import Stackage.UpdateBuildPlan
import Stackage.Upload import Stackage.Upload
import System.Environment (lookupEnv)
import System.IO (BufferMode (LineBuffering), hSetBuffering) import System.IO (BufferMode (LineBuffering), hSetBuffering)
-- | Flags passed in from the command line.
data BuildFlags = BuildFlags
{ bfEnableTests :: !Bool
, bfEnableHaddock :: !Bool
, bfDoUpload :: !Bool
, bfEnableLibProfile :: !Bool
, bfEnableExecDyn :: !Bool
, bfVerbose :: !Bool
, bfSkipCheck :: !Bool
} deriving (Show)
data BuildType = Nightly | LTS BumpType data BuildType = Nightly | LTS BumpType
deriving (Show, Read, Eq, Ord) deriving (Show, Read, Eq, Ord)
@ -39,28 +56,42 @@ data Settings = Settings
, slug :: Text , slug :: Text
, setArgs :: Text -> UploadBundle -> UploadBundle , setArgs :: Text -> UploadBundle -> UploadBundle
, postBuild :: IO () , postBuild :: IO ()
, distroName :: Text -- ^ distro name on Hackage
} }
nightlyPlanFile :: Text -- ^ day
-> FilePath
nightlyPlanFile day = fpFromText ("nightly-" ++ day) <.> "yaml"
nightlySettings :: Text -- ^ day
-> BuildPlan
-> Settings
nightlySettings day plan' = Settings
{ planFile = nightlyPlanFile day
, buildDir = fpFromText $ "builds/nightly"
, logDir = fpFromText $ "logs/stackage-nightly-" ++ day
, title = \ghcVer -> concat
[ "Stackage Nightly "
, day
, ", GHC "
, ghcVer
]
, slug = slug'
, setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
, plan = plan'
, postBuild = return ()
, distroName = "Stackage"
}
where
slug' = "nightly-" ++ day
getSettings :: Manager -> BuildType -> IO Settings getSettings :: Manager -> BuildType -> IO Settings
getSettings man Nightly = do getSettings man Nightly = do
day <- tshow . utctDay <$> getCurrentTime day <- tshow . utctDay <$> getCurrentTime
let slug' = "nightly-" ++ day bc <- defaultBuildConstraints man
plan' <- defaultBuildConstraints man >>= newBuildPlan pkgs <- getLatestAllowedPlans bc
return Settings plan' <- newBuildPlan pkgs bc
{ planFile = fpFromText ("nightly-" ++ day) <.> "yaml" return $ nightlySettings day plan'
, buildDir = fpFromText $ "builds/stackage-nightly-" ++ day
, logDir = fpFromText $ "logs/stackage-nightly-" ++ day
, title = \ghcVer -> concat
[ "Stackage Nightly "
, day
, ", GHC "
, ghcVer
]
, slug = slug'
, setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
, plan = plan'
, postBuild = return ()
}
getSettings man (LTS bumpType) = do getSettings man (LTS bumpType) = do
Option mlts <- fmap (fmap getMax) $ runResourceT Option mlts <- fmap (fmap getMax) $ runResourceT
$ sourceDirectory "." $ sourceDirectory "."
@ -72,21 +103,25 @@ getSettings man (LTS bumpType) = do
case mlts of case mlts of
Nothing -> LTSVer 0 0 Nothing -> LTSVer 0 0
Just (LTSVer x _) -> LTSVer (x + 1) 0 Just (LTSVer x _) -> LTSVer (x + 1) 0
plan' <- defaultBuildConstraints man >>= newBuildPlan bc <- defaultBuildConstraints man
pkgs <- getLatestAllowedPlans bc
plan' <- newBuildPlan pkgs bc
return (new, plan') return (new, plan')
Minor -> do Minor -> do
old <- maybe (error "No LTS plans found in current directory") return mlts old <- maybe (error "No LTS plans found in current directory") return mlts
oldplan <- decodeFileEither (fpToString $ renderLTSVer old) oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
>>= either throwM return >>= either throwM return
let new = incrLTSVer old let new = incrLTSVer old
plan' <- updateBuildPlan oldplan let bc = updateBuildConstraints oldplan
pkgs <- getLatestAllowedPlans bc
plan' <- newBuildPlan pkgs bc
return (new, plan') return (new, plan')
let newfile = renderLTSVer new let newfile = renderLTSVer new
return Settings return Settings
{ planFile = newfile { planFile = newfile
, buildDir = fpFromText $ "builds/stackage-lts-" ++ tshow new , buildDir = fpFromText $ "builds/lts"
, logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new , logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
, title = \ghcVer -> concat , title = \ghcVer -> concat
[ "LTS Haskell " [ "LTS Haskell "
@ -106,6 +141,7 @@ getSettings man (LTS bumpType) = do
git ["commit", "-m", "Added new LTS release: " ++ show new] git ["commit", "-m", "Added new LTS release: " ++ show new]
putStrLn "Pushing to Git repository" putStrLn "Pushing to Git repository"
git ["push"] git ["push"]
, distroName = "LTSHaskell"
} }
data LTSVer = LTSVer !Int !Int data LTSVer = LTSVer !Int !Int
@ -130,16 +166,27 @@ renderLTSVer lts = fpFromText $ concat
, ".yaml" , ".yaml"
] ]
-- | Just print a message saying "still alive" every minute, to appease Travis.
stillAlive :: IO () -> IO ()
stillAlive inner =
withAsync (printer 1) $ const inner
where
printer i = forever $ do
threadDelay 60000000
putStrLn $ "Still alive: " ++ tshow i
printer $! i + 1
-- | Generate and check a new build plan, but do not execute it. -- | Generate and check a new build plan, but do not execute it.
-- --
-- Since 0.3.1 -- Since 0.3.1
justCheck :: IO () justCheck :: IO ()
justCheck = withManager tlsManagerSettings $ \man -> do justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
putStrLn "Loading build constraints" putStrLn "Loading build constraints"
bc <- defaultBuildConstraints man bc <- defaultBuildConstraints man
putStrLn "Creating build plan" putStrLn "Creating build plan"
plan <- newBuildPlan bc plans <- getLatestAllowedPlans bc
plan <- newBuildPlan plans bc
putStrLn $ "Writing build plan to check-plan.yaml" putStrLn $ "Writing build plan to check-plan.yaml"
encodeFile "check-plan.yaml" plan encodeFile "check-plan.yaml" plan
@ -149,37 +196,71 @@ justCheck = withManager tlsManagerSettings $ \man -> do
putStrLn "Plan seems valid!" putStrLn "Plan seems valid!"
completeBuild :: BuildType -> IO () getPerformBuild :: BuildFlags -> Settings -> PerformBuild
completeBuild buildType = withManager tlsManagerSettings $ \man -> do getPerformBuild buildFlags Settings {..} = PerformBuild
{ pbPlan = plan
, pbInstallDest = buildDir
, pbLogDir = logDir
, pbLog = hPut stdout
, pbJobs = 8
, pbGlobalInstall = False
, pbEnableTests = bfEnableTests buildFlags
, pbEnableHaddock = bfEnableHaddock buildFlags
, pbEnableLibProfiling = bfEnableLibProfile buildFlags
, pbEnableExecDyn = bfEnableExecDyn buildFlags
, pbVerbose = bfVerbose buildFlags
, pbAllowNewer = bfSkipCheck buildFlags
}
-- | Make a complete plan, build, test and upload bundle, docs and
-- distro.
completeBuild :: BuildType -> BuildFlags -> IO ()
completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
hSetBuffering stdout LineBuffering hSetBuffering stdout LineBuffering
putStrLn $ "Loading settings for: " ++ tshow buildType putStrLn $ "Loading settings for: " ++ tshow buildType
Settings {..} <- getSettings man buildType settings@Settings {..} <- getSettings man buildType
putStrLn $ "Writing build plan to: " ++ fpToText planFile putStrLn $ "Writing build plan to: " ++ fpToText planFile
encodeFile (fpToString planFile) plan encodeFile (fpToString planFile) plan
putStrLn "Checking build plan" if bfSkipCheck buildFlags
checkBuildPlan plan then putStrLn "Skipping build plan check"
else do
putStrLn "Checking build plan"
checkBuildPlan plan
putStrLn "Performing build" putStrLn "Performing build"
let pb = PerformBuild performBuild (getPerformBuild buildFlags settings) >>= mapM_ putStrLn
{ pbPlan = plan
, pbInstallDest = buildDir
, pbLogDir = logDir
, pbLog = hPut stdout
, pbJobs = 8
, pbGlobalInstall = False
}
performBuild pb >>= mapM_ putStrLn
when (bfDoUpload buildFlags) $
finallyUpload settings man
justUploadNightly
:: Text -- ^ nightly date
-> IO ()
justUploadNightly day = do
plan <- decodeFileEither (fpToString $ nightlyPlanFile day)
>>= either throwM return
withManager tlsManagerSettings $ finallyUpload $ nightlySettings day plan
-- | The final part of the complete build process: uploading a bundle,
-- docs and a distro to hackage.
finallyUpload :: Settings -> Manager -> IO ()
finallyUpload settings@Settings{..} man = do
putStrLn "Uploading bundle to Stackage Server" putStrLn "Uploading bundle to Stackage Server"
token <- readFile "/auth-token"
mtoken <- lookupEnv "STACKAGE_AUTH_TOKEN"
token <-
case mtoken of
Nothing -> decodeUtf8 <$> readFile "/auth-token"
Just token -> return $ pack token
now <- epochTime now <- epochTime
let ghcVer = display $ siGhcVersion $ bpSystemInfo plan let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
(ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def (ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
{ ubContents = serverBundle now (title ghcVer) slug plan { ubContents = serverBundle now (title ghcVer) slug plan
, ubAuthToken = decodeUtf8 token , ubAuthToken = token
} }
putStrLn $ "New ident: " ++ unSnapshotIdent ident putStrLn $ "New ident: " ++ unSnapshotIdent ident
forM_ mloc $ \loc -> forM_ mloc $ \loc ->
@ -190,7 +271,7 @@ completeBuild buildType = withManager tlsManagerSettings $ \man -> do
putStrLn "Uploading docs to Stackage Server" putStrLn "Uploading docs to Stackage Server"
res1 <- uploadDocs UploadDocs res1 <- uploadDocs UploadDocs
{ udServer = def { udServer = def
, udAuthToken = decodeUtf8 token , udAuthToken = token
, udDocs = pbDocDir pb , udDocs = pbDocDir pb
, udSnapshot = ident , udSnapshot = ident
} man } man
@ -200,15 +281,17 @@ completeBuild buildType = withManager tlsManagerSettings $ \man -> do
case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
[username, password] -> do [username, password] -> do
putStrLn "Uploading as Hackage distro" putStrLn "Uploading as Hackage distro"
res2 <- uploadHackageDistro plan username password man res2 <- uploadHackageDistroNamed distroName plan username password man
putStrLn $ "Distro upload response: " ++ tshow res2 putStrLn $ "Distro upload response: " ++ tshow res2
_ -> putStrLn "No creds found, skipping Hackage distro upload" _ -> putStrLn "No creds found, skipping Hackage distro upload"
putStrLn "Uploading doc map" putStrLn "Uploading doc map"
uploadDocMap UploadDocMap uploadDocMap UploadDocMap
{ udmServer = def { udmServer = def
, udmAuthToken = decodeUtf8 token , udmAuthToken = token
, udmSnapshot = ident , udmSnapshot = ident
, udmDocDir = pbDocDir pb , udmDocDir = pbDocDir pb
, udmPlan = plan , udmPlan = plan
} man >>= print } man >>= print
where
pb = getPerformBuild (error "finallyUpload.buildFlags") settings

90
Stackage/GhcPkg.hs Normal file
View File

@ -0,0 +1,90 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
-- | General commands related to ghc-pkg.
module Stackage.GhcPkg
( setupPackageDatabase
) where
import Data.Conduit
import qualified Data.Conduit.List as CL
import Data.Conduit.Process
import qualified Data.Conduit.Text as CT
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T
import Distribution.Compat.ReadP
import Distribution.Package
import Distribution.Text (parse)
import Filesystem.Path.CurrentOS (FilePath)
import qualified Filesystem.Path.CurrentOS as FP
import Data.Map (Map)
import Data.Version (Version)
import Stackage.Prelude
import Filesystem (removeTree)
setupPackageDatabase
:: Maybe FilePath -- ^ database location, Nothing if using global DB
-> FilePath -- ^ documentation root
-> (ByteString -> IO ()) -- ^ logging
-> Map PackageName Version -- ^ packages and versions to be installed
-> IO (Set PackageName) -- ^ packages remaining in the database after cleanup
setupPackageDatabase mdb docDir log' toInstall = do
registered1 <- getRegisteredPackages flags
forM_ registered1 $ \pi@(PackageIdentifier name version) ->
case lookup name toInstall of
Just version' | version /= version' -> unregisterPackage log' docDir flags pi
_ -> return ()
broken <- getBrokenPackages flags
forM_ broken $ unregisterPackage log' docDir flags
foldMap (\(PackageIdentifier name _) -> singletonSet name)
<$> getRegisteredPackages flags
where
flags = ghcPkgFlags mdb
ghcPkgFlags :: Maybe FilePath -> [String]
ghcPkgFlags mdb =
"--no-user-package-db" :
case mdb of
Nothing -> ["--global"]
Just fp -> ["--package-db=" ++ fpToString fp]
-- | Get broken packages.
getBrokenPackages :: [String] -> IO [PackageIdentifier]
getBrokenPackages flags = do
(_,ps) <- sourceProcessWithConsumer
(proc
"ghc-pkg"
("check" : "--simple-output" : flags))
(CT.decodeUtf8 $= CT.lines $= CL.consume)
return (mapMaybe parsePackageIdent (T.words (T.unlines ps)))
-- | Get available packages.
getRegisteredPackages :: [String] -> IO [PackageIdentifier]
getRegisteredPackages flags = do
(_,ps) <- sourceProcessWithConsumer
(proc
"ghc-pkg"
("list" : "--simple-output" : flags))
(CT.decodeUtf8 $= CT.lines $= CL.consume)
return (mapMaybe parsePackageIdent (T.words (T.unlines ps)))
-- | Parse a package identifier: foo-1.2.3
parsePackageIdent :: Text -> Maybe PackageIdentifier
parsePackageIdent = fmap fst .
listToMaybe .
filter (null . snd) .
readP_to_S parse . T.unpack
-- | Unregister a package.
unregisterPackage :: (ByteString -> IO ()) -- ^ log func
-> FilePath -- ^ doc directory
-> [String] -> PackageIdentifier -> IO ()
unregisterPackage log' docDir flags ident@(PackageIdentifier name _) = do
log' $ "Unregistering " ++ encodeUtf8 (display ident) ++ "\n"
void (readProcessWithExitCode
"ghc-pkg"
("unregister": flags ++ ["--force", unpack $ display name])
"")
void $ tryIO $ removeTree $ docDir </> fpFromText (display ident)

100
Stackage/InstallBuild.hs Normal file
View File

@ -0,0 +1,100 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Stackage.InstallBuild
( InstallFlags (..)
, BuildPlanSource (..)
, installBuild
) where
import qualified Codec.Archive.Tar as Tar
import qualified Codec.Compression.GZip as GZip
import qualified Data.Yaml as Yaml
import Network.HTTP.Client
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Stackage.BuildPlan
import Stackage.CheckBuildPlan
import Stackage.PerformBuild
import Stackage.Prelude
import System.IO (BufferMode (LineBuffering), hSetBuffering)
-- | Flags passed in from the command line.
data InstallFlags = InstallFlags
{ ifPlanSource :: !BuildPlanSource
, ifInstallDest :: !FilePath
, ifLogDir :: !(Maybe FilePath)
, ifJobs :: !Int
, ifGlobalInstall :: !Bool
, ifEnableTests :: !Bool
, ifEnableHaddock :: !Bool
, ifEnableLibProfiling :: !Bool
, ifEnableExecDyn :: !Bool
, ifVerbose :: !Bool
, ifSkipCheck :: !Bool
} deriving (Show)
-- | Source for build plan.
data BuildPlanSource = BPSBundleWeb String
| BPSFile FilePath
deriving (Show)
getPerformBuild :: BuildPlan -> InstallFlags -> PerformBuild
getPerformBuild plan InstallFlags{..} =
PerformBuild
{ pbPlan = plan
, pbInstallDest = ifInstallDest
, pbLogDir = fromMaybe (ifInstallDest </> "logs") ifLogDir
, pbLog = hPut stdout
, pbJobs = ifJobs
, pbGlobalInstall = ifGlobalInstall
, pbEnableTests = ifEnableTests
, pbEnableHaddock = ifEnableHaddock
, pbEnableLibProfiling = ifEnableLibProfiling
, pbEnableExecDyn = ifEnableExecDyn
, pbVerbose = ifVerbose
, pbAllowNewer = ifSkipCheck
}
-- | Install stackage from an existing build plan.
installBuild :: InstallFlags -> IO ()
installBuild installFlags@InstallFlags{..} = do
hSetBuffering stdout LineBuffering
putStrLn $ "Loading build plan"
plan <- case ifPlanSource of
BPSBundleWeb url -> withManager tlsManagerSettings $ \man -> do
req <- parseUrl url
res <- httpLbs req man
planBSL <- getPlanEntry $ Tar.read $ GZip.decompress (responseBody res)
decodeBuildPlan planBSL
BPSFile path -> Yaml.decodeFileEither (fpToString path) >>= either throwM return
if ifSkipCheck
then putStrLn "Skipping build plan check"
else do
putStrLn "Checking build plan"
checkBuildPlan plan
putStrLn "Performing build"
performBuild (getPerformBuild plan installFlags) >>= mapM_ putStrLn
where
getPlanEntry Tar.Done = throwIO NoBuildPlanException
getPlanEntry (Tar.Fail e) = throwIO e
getPlanEntry (Tar.Next entry entries)
| Tar.entryPath entry == "build-plan.yaml" =
case Tar.entryContent entry of
Tar.NormalFile bs _ -> return bs
_ -> throwIO NoBuildPlanException
| otherwise = getPlanEntry entries
decodeBuildPlan =
either throwIO return . Yaml.decodeEither' . toStrict
data InstallBuildException = NoBuildPlanException
deriving (Typeable)
instance Exception InstallBuildException
instance Show InstallBuildException where
show NoBuildPlanException = "Bundle has missing or invalid build-plan.yaml"

View File

@ -19,11 +19,12 @@ import qualified Data.Map as Map
import Data.NonNull (fromNullable) import Data.NonNull (fromNullable)
import Filesystem (canonicalizePath, createTree, import Filesystem (canonicalizePath, createTree,
getWorkingDirectory, isDirectory, getWorkingDirectory, isDirectory,
removeTree, rename) removeTree, rename, isFile, removeFile)
import Filesystem.Path (parent) import Filesystem.Path (parent)
import qualified Filesystem.Path as F import qualified Filesystem.Path as F
import Stackage.BuildConstraints import Stackage.BuildConstraints
import Stackage.BuildPlan import Stackage.BuildPlan
import Stackage.GhcPkg
import Stackage.PackageDescription import Stackage.PackageDescription
import Stackage.Prelude hiding (pi) import Stackage.Prelude hiding (pi)
import System.Directory (findExecutable) import System.Directory (findExecutable)
@ -61,6 +62,13 @@ data PerformBuild = PerformBuild
, pbJobs :: Int , pbJobs :: Int
, pbGlobalInstall :: Bool , pbGlobalInstall :: Bool
-- ^ Register packages in the global database -- ^ Register packages in the global database
, pbEnableTests :: Bool
, pbEnableHaddock :: Bool
, pbEnableLibProfiling :: Bool
, pbEnableExecDyn :: Bool
, pbVerbose :: Bool
, pbAllowNewer :: Bool
-- ^ Pass --allow-newer to cabal configure
} }
data PackageInfo = PackageInfo data PackageInfo = PackageInfo
@ -83,7 +91,9 @@ waitForDeps toolMap packageMap activeComps bp pi action = do
case lookup exe toolMap >>= fromNullable . map checkPackage . setToList of case lookup exe toolMap >>= fromNullable . map checkPackage . setToList of
Nothing Nothing
| isCoreExe exe -> return () | isCoreExe exe -> return ()
| otherwise -> throwSTM $ ToolMissing exe -- https://github.com/jgm/zip-archive/issues/23
-- | otherwise -> throwSTM $ ToolMissing exe
| otherwise -> return ()
Just packages -> ofoldl1' (<|>) packages Just packages -> ofoldl1' (<|>) packages
action action
where where
@ -126,6 +136,10 @@ pbLibDir pb = pbInstallDest pb </> "lib"
pbDataDir pb = pbInstallDest pb </> "share" pbDataDir pb = pbInstallDest pb </> "share"
pbDocDir pb = pbInstallDest pb </> "doc" pbDocDir pb = pbInstallDest pb </> "doc"
-- | Directory keeping previous result info
pbPrevResDir :: PerformBuild -> FilePath
pbPrevResDir pb = pbInstallDest pb </> "prevres"
performBuild :: PerformBuild -> IO [Text] performBuild :: PerformBuild -> IO [Text]
performBuild pb = do performBuild pb = do
cwd <- getWorkingDirectory cwd <- getWorkingDirectory
@ -153,12 +167,13 @@ performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
$ \ClosedStream Inherited Inherited -> return () $ \ClosedStream Inherited Inherited -> return ()
let removeTree' fp = whenM (isDirectory fp) (removeTree fp) let removeTree' fp = whenM (isDirectory fp) (removeTree fp)
mapM_ removeTree' [pbInstallDest, pbLogDir] removeTree' pbLogDir
forM_ (pbDatabase pb) $ \db -> do forM_ (pbDatabase pb) $ \db ->
createTree $ parent db unlessM (isFile $ db </> "package.cache") $ do
withCheckedProcess (proc "ghc-pkg" ["init", fpToString db]) createTree $ parent db
$ \ClosedStream Inherited Inherited -> return () withCheckedProcess (proc "ghc-pkg" ["init", fpToString db])
$ \ClosedStream Inherited Inherited -> return ()
pbLog $ encodeUtf8 "Copying built-in Haddocks\n" pbLog $ encodeUtf8 "Copying built-in Haddocks\n"
copyBuiltInHaddocks (pbDocDir pb) copyBuiltInHaddocks (pbDocDir pb)
@ -178,7 +193,14 @@ performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
env <- getEnvironment env <- getEnvironment
haddockFiles <- newTVarIO mempty haddockFiles <- newTVarIO mempty
forM_ packageMap $ \pi -> void $ async $ singleBuild pb SingleBuild registeredPackages <- setupPackageDatabase
(pbDatabase pb)
(pbDocDir pb)
pbLog
(ppVersion <$> bpPackages pbPlan)
forM_ packageMap $ \pi -> void $ async $ singleBuild pb registeredPackages
SingleBuild
{ sbSem = sem { sbSem = sem
, sbErrsVar = errsVar , sbErrsVar = errsVar
, sbWarningsVar = warningsVar , sbWarningsVar = warningsVar
@ -192,7 +214,7 @@ performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
id id
(\db -> (("HASKELL_PACKAGE_SANDBOX", fpToString db):)) (\db -> (("HASKELL_PACKAGE_SANDBOX", fpToString db):))
(pbDatabase pb) (pbDatabase pb)
(map fixEnv env) (filter allowedEnv $ map fixEnv env)
, sbHaddockFiles = haddockFiles , sbHaddockFiles = haddockFiles
} }
@ -210,6 +232,8 @@ performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
| toUpper p == "PATH" = (p, fpToString (pbBinDir pb) ++ pathSep : x) | toUpper p == "PATH" = (p, fpToString (pbBinDir pb) ++ pathSep : x)
| otherwise = (p, x) | otherwise = (p, x)
allowedEnv (k, _) = k `notMember` bannedEnvs
-- | Separate for the PATH environment variable -- | Separate for the PATH environment variable
pathSep :: Char pathSep :: Char
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
@ -218,6 +242,12 @@ performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
pathSep = ':' pathSep = ':'
#endif #endif
-- | Environment variables we don't allow to be passed on to child processes.
bannedEnvs :: Set String
bannedEnvs = setFromList
[ "STACKAGE_AUTH_TOKEN"
]
data SingleBuild = SingleBuild data SingleBuild = SingleBuild
{ sbSem :: TSem { sbSem :: TSem
, sbErrsVar :: TVar (Map PackageName BuildFailure) , sbErrsVar :: TVar (Map PackageName BuildFailure)
@ -232,8 +262,10 @@ data SingleBuild = SingleBuild
, sbHaddockFiles :: TVar (Map Text FilePath) -- ^ package-version, .haddock file , sbHaddockFiles :: TVar (Map Text FilePath) -- ^ package-version, .haddock file
} }
singleBuild :: PerformBuild -> SingleBuild -> IO () singleBuild :: PerformBuild
singleBuild pb@PerformBuild {..} SingleBuild {..} = -> Set PackageName -- ^ registered packages
-> SingleBuild -> IO ()
singleBuild pb@PerformBuild {..} registeredPackages SingleBuild {..} =
withCounter sbActive withCounter sbActive
$ handle updateErrs $ handle updateErrs
$ (`finally` void (atomically $ tryPutTMVar (piResult sbPackageInfo) False)) $ (`finally` void (atomically $ tryPutTMVar (piResult sbPackageInfo) False))
@ -245,11 +277,13 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
let wfd comps = let wfd comps =
waitForDeps sbToolMap sbPackageMap comps pbPlan sbPackageInfo waitForDeps sbToolMap sbPackageMap comps pbPlan sbPackageInfo
. withTSem sbSem . withTSem sbSem
wfd libComps buildLibrary withUnpacked <- wfd libComps buildLibrary
wfd testComps runTests wfd testComps (runTests withUnpacked)
name = display $ piName sbPackageInfo pname = piName sbPackageInfo
pident = PackageIdentifier pname (ppVersion $ piPlan sbPackageInfo)
name = display pname
namever = concat namever = concat
[ name [ name
, "-" , "-"
@ -290,6 +324,7 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
withBinaryFile (fpToString fp) WriteMode inner' withBinaryFile (fpToString fp) WriteMode inner'
configArgs = ($ []) $ execWriter $ do configArgs = ($ []) $ execWriter $ do
when pbAllowNewer $ tell' "--allow-newer"
tell' "--package-db=clear" tell' "--package-db=clear"
tell' "--package-db=global" tell' "--package-db=global"
forM_ (pbDatabase pb) $ \db -> tell' $ "--package-db=" ++ fpToText db forM_ (pbDatabase pb) $ \db -> tell' $ "--package-db=" ++ fpToText db
@ -298,6 +333,9 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
tell' $ "--datadir=" ++ fpToText (pbDataDir pb) tell' $ "--datadir=" ++ fpToText (pbDataDir pb)
tell' $ "--docdir=" ++ fpToText (pbDocDir pb) tell' $ "--docdir=" ++ fpToText (pbDocDir pb)
tell' $ "--flags=" ++ flags tell' $ "--flags=" ++ flags
when (pbEnableLibProfiling && pcEnableLibProfile) $
tell' "--enable-library-profiling"
when pbEnableExecDyn $ tell' "--enable-executable-dynamic"
where where
tell' x = tell (x:) tell' x = tell (x:)
@ -312,20 +350,39 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
PackageConstraints {..} = ppConstraints $ piPlan sbPackageInfo PackageConstraints {..} = ppConstraints $ piPlan sbPackageInfo
buildLibrary = wf libOut $ \outH -> do buildLibrary = wf libOut $ \outH -> do
let run = runChild outH let run a b = do when pbVerbose $ log' (unwords (a : b))
log' $ "Unpacking " ++ namever runChild outH a b
runParent outH "cabal" ["unpack", namever]
log' $ "Configuring " ++ namever isUnpacked <- newIORef False
run "cabal" $ "configure" : configArgs let withUnpacked inner = do
unlessM (readIORef isUnpacked) $ do
log' $ "Unpacking " ++ namever
runParent outH "cabal" ["unpack", namever]
writeIORef isUnpacked True
inner
log' $ "Building " ++ namever isConfiged <- newIORef False
run "cabal" ["build"] let withConfiged inner = withUnpacked $ do
unlessM (readIORef isConfiged) $ do
log' $ "Configuring " ++ namever
run "cabal" $ "configure" : configArgs
writeIORef isConfiged True
inner
log' $ "Copying/registering " ++ namever prevBuildResult <- getPreviousResult pb Build pident
run "cabal" ["copy"] unless (prevBuildResult == PRSuccess) $ withConfiged $ do
withMVar sbRegisterMutex $ const $ assert (pname `notMember` registeredPackages) $ do
run "cabal" ["register"] deletePreviousResults pb pident
log' $ "Building " ++ namever
run "cabal" ["build"]
log' $ "Copying/registering " ++ namever
run "cabal" ["copy"]
withMVar sbRegisterMutex $ const $
run "cabal" ["register"]
savePreviousResult pb Build pident True
-- Even if the tests later fail, we can allow other libraries to build -- Even if the tests later fail, we can allow other libraries to build
-- on top of our successful results -- on top of our successful results
@ -335,7 +392,11 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
-- dependency's haddocks before this finishes -- dependency's haddocks before this finishes
atomically $ putTMVar (piResult sbPackageInfo) True atomically $ putTMVar (piResult sbPackageInfo) True
when (pcHaddocks /= Don'tBuild && not (null $ sdModules $ ppDesc $ piPlan sbPackageInfo)) $ do prevHaddockResult <- getPreviousResult pb Haddock pident
let needHaddock = pbEnableHaddock
&& checkPrevResult prevHaddockResult pcHaddocks
&& not (null $ sdModules $ ppDesc $ piPlan sbPackageInfo)
when needHaddock $ withConfiged $ do
log' $ "Haddocks " ++ namever log' $ "Haddocks " ++ namever
hfs <- readTVarIO sbHaddockFiles hfs <- readTVarIO sbHaddockFiles
let hfsOpts = flip map (mapToList hfs) $ \(pkgVer, hf) -> concat let hfsOpts = flip map (mapToList hfs) $ \(pkgVer, hf) -> concat
@ -370,15 +431,21 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
$ modifyTVar sbHaddockFiles $ modifyTVar sbHaddockFiles
$ insertMap namever newPath $ insertMap namever newPath
savePreviousResult pb Haddock pident $ either (const False) (const True) eres
case (eres, pcHaddocks) of case (eres, pcHaddocks) of
(Left e, ExpectSuccess) -> throwM e (Left e, ExpectSuccess) -> throwM e
(Right (), ExpectFailure) -> warn $ namever ++ ": unexpected Haddock success" (Right (), ExpectFailure) -> warn $ namever ++ ": unexpected Haddock success"
_ -> return () _ -> return ()
runTests = wf testOut $ \outH -> do return withUnpacked
runTests withUnpacked = wf testOut $ \outH -> do
let run = runChild outH let run = runChild outH
when (pcTests /= Don'tBuild) $ do prevTestResult <- getPreviousResult pb Test pident
let needTest = pbEnableTests
&& checkPrevResult prevTestResult pcTests
when needTest $ withUnpacked $ do
log' $ "Test configure " ++ namever log' $ "Test configure " ++ namever
run "cabal" $ "configure" : "--enable-tests" : configArgs run "cabal" $ "configure" : "--enable-tests" : configArgs
@ -389,6 +456,7 @@ singleBuild pb@PerformBuild {..} SingleBuild {..} =
log' $ "Test run " ++ namever log' $ "Test run " ++ namever
run "cabal" ["test", "--log=" ++ fpToText testRunOut] run "cabal" ["test", "--log=" ++ fpToText testRunOut]
savePreviousResult pb Test pident $ either (const False) (const True) eres
case (eres, pcTests) of case (eres, pcTests) of
(Left e, ExpectSuccess) -> throwM e (Left e, ExpectSuccess) -> throwM e
(Right (), ExpectFailure) -> warn $ namever ++ ": unexpected test success" (Right (), ExpectFailure) -> warn $ namever ++ ": unexpected test success"
@ -421,3 +489,52 @@ copyBuiltInHaddocks docdir = do
src <- canonicalizePath src <- canonicalizePath
(parent (fpFromString ghc) </> "../share/doc/ghc/html/libraries") (parent (fpFromString ghc) </> "../share/doc/ghc/html/libraries")
copyDir src docdir copyDir src docdir
------------- Previous results
-- | The previous actions that can be run
data ResultType = Build | Haddock | Test
deriving (Show, Enum, Eq, Ord, Bounded, Read)
-- | The result generated on a previous run
data PrevResult = PRNoResult | PRSuccess | PRFailure
deriving (Show, Enum, Eq, Ord, Bounded, Read)
-- | Check if we should rerun based on a PrevResult and the expected status
checkPrevResult :: PrevResult -> TestState -> Bool
checkPrevResult _ Don'tBuild = False
checkPrevResult PRNoResult _ = True
checkPrevResult PRSuccess _ = False
checkPrevResult PRFailure ExpectSuccess = True
checkPrevResult PRFailure _ = False
withPRPath :: PerformBuild -> ResultType -> PackageIdentifier -> (FilePath -> IO a) -> IO a
withPRPath pb rt ident inner = do
createTree $ parent fp
inner fp
where
fp = pbPrevResDir pb </> fpFromString (show rt) </> fpFromText (display ident)
successBS, failureBS :: ByteString
successBS = "success"
failureBS = "failure"
getPreviousResult :: PerformBuild -> ResultType -> PackageIdentifier -> IO PrevResult
getPreviousResult w x y = withPRPath w x y $ \fp -> do
eres <- tryIO $ readFile fp
return $ case eres of
Right bs
| bs == successBS -> PRSuccess
| bs == failureBS -> PRFailure
_ -> PRNoResult
savePreviousResult :: PerformBuild -> ResultType -> PackageIdentifier -> Bool -> IO ()
savePreviousResult pb rt ident res =
withPRPath pb rt ident $ \fp -> writeFile fp $
if res then successBS else failureBS
deletePreviousResults :: PerformBuild -> PackageIdentifier -> IO ()
deletePreviousResults pb name =
forM_ [minBound..maxBound] $ \rt ->
withPRPath pb rt name $ \fp ->
void $ tryIO $ removeFile fp

View File

@ -15,8 +15,9 @@ import Stackage.BuildConstraints
import Stackage.BuildPlan import Stackage.BuildPlan
import Stackage.Prelude import Stackage.Prelude
updateBuildPlan :: BuildPlan -> IO BuildPlan updateBuildPlan :: Map PackageName PackagePlan -> BuildPlan -> IO BuildPlan
updateBuildPlan = newBuildPlan . updateBuildConstraints updateBuildPlan packagesOrig
= newBuildPlan packagesOrig . updateBuildConstraints
updateBuildConstraints :: BuildPlan -> BuildConstraints updateBuildConstraints :: BuildPlan -> BuildConstraints
updateBuildConstraints BuildPlan {..} = updateBuildConstraints BuildPlan {..} =
@ -33,6 +34,7 @@ updateBuildConstraints BuildPlan {..} =
, pcHaddocks = maybe ExpectSuccess pcHaddocks moldPC , pcHaddocks = maybe ExpectSuccess pcHaddocks moldPC
, pcBuildBenchmarks = maybe True pcBuildBenchmarks moldPC , pcBuildBenchmarks = maybe True pcBuildBenchmarks moldPC
, pcFlagOverrides = maybe mempty pcFlagOverrides moldPC , pcFlagOverrides = maybe mempty pcFlagOverrides moldPC
, pcEnableLibProfile = maybe False pcEnableLibProfile moldPC
} }
where where
moldBP = lookup name bpPackages moldBP = lookup name bpPackages

View File

@ -11,6 +11,7 @@ module Stackage.Upload
, UploadDocs (..) , UploadDocs (..)
, uploadDocs , uploadDocs
, uploadHackageDistro , uploadHackageDistro
, uploadHackageDistroNamed
, UploadDocMap (..) , UploadDocMap (..)
, uploadDocMap , uploadDocMap
, uploadBundleV2 , uploadBundleV2
@ -145,8 +146,28 @@ uploadHackageDistro :: BuildPlan
-> ByteString -- ^ Hackage password -> ByteString -- ^ Hackage password
-> Manager -> Manager
-> IO (Response LByteString) -> IO (Response LByteString)
uploadHackageDistro bp username password = uploadHackageDistro = uploadHackageDistroNamed "Stackage"
httpLbs (applyBasicAuth username password req)
uploadHackageDistroNamed
:: Text -- ^ distro name
-> BuildPlan
-> ByteString -- ^ Hackage username
-> ByteString -- ^ Hackage password
-> Manager
-> IO (Response LByteString)
uploadHackageDistroNamed name bp username password manager = do
req1 <- parseUrl $ concat
[ "http://hackage.haskell.org/distro/"
, unpack name
, "/packages.csv"
]
let req2 = req1
{ requestHeaders = [("Content-Type", "text/csv")]
, requestBody = RequestBodyLBS csv
, checkStatus = \_ _ _ -> Nothing
, method = "PUT"
}
httpLbs (applyBasicAuth username password req2) manager
where where
csv = encodeUtf8 csv = encodeUtf8
$ builderToLazy $ builderToLazy
@ -164,13 +185,6 @@ uploadHackageDistro bp username password =
(toBuilder $ display name) ++ (toBuilder $ display name) ++
"\"" "\""
req = "http://hackage.haskell.org/distro/Stackage/packages.csv"
{ requestHeaders = [("Content-Type", "text/csv")]
, requestBody = RequestBodyLBS csv
, checkStatus = \_ _ _ -> Nothing
, method = "PUT"
}
data UploadDocMap = UploadDocMap data UploadDocMap = UploadDocMap
{ udmServer :: StackageServer { udmServer :: StackageServer
, udmAuthToken :: Text , udmAuthToken :: Text

View File

@ -1,16 +1,163 @@
{-# LANGUAGE TupleSections #-}
module Main where
import Control.Monad
import Data.Monoid
import Data.String (fromString)
import Data.Version
import Options.Applicative
import Filesystem.Path.CurrentOS (decodeString)
import Paths_stackage (version)
import Stackage.CompleteBuild import Stackage.CompleteBuild
import System.Environment (getArgs) import Stackage.InstallBuild
main :: IO () main :: IO ()
main = do main =
args <- getArgs join $
case args of execParser $
[x] | Just y <- lookup x m -> y info
_ -> error $ "Expected one argument, one of: " ++ unwords (map fst m) (helpOption <*> versionOption <*> config)
(header "Stackage" <>
fullDesc)
where where
m = helpOption =
[ ("nightly", completeBuild Nightly) abortOption ShowHelpText $
, ("lts-major", completeBuild $ LTS Major) long "help" <>
, ("lts-minor", completeBuild $ LTS Minor) help "Show this help text"
, ("check", justCheck) versionOption =
] infoOption
("stackage version " ++ showVersion version)
(long "version" <>
help "Show stackage version")
config =
subparser $
mconcat
[ cmnd
(uncurry completeBuild)
(fmap (Nightly, ) buildFlags)
"nightly"
"Build, test and upload the Nightly snapshot"
, cmnd
(uncurry completeBuild)
(fmap (LTS Major, ) buildFlags)
"lts-major"
"Build, test and upload the LTS (major) snapshot"
, cmnd
(uncurry completeBuild)
(fmap (LTS Minor, ) buildFlags)
"lts-minor"
"Build, test and upload the LTS (minor) snapshot"
, cmnd
justUploadNightly
nightlyUploadFlags
"upload-nightly"
"Upload an already-built nightly snapshot"
, cmnd
(const justCheck)
(pure ())
"check"
"Just check that the build plan is ok"
, cmnd
installBuild
installFlags
"install"
"Install a snapshot from an existing build plan"]
cmnd exec parse name desc =
command name $
info
(fmap exec (parse <**> helpOption))
(progDesc desc)
buildFlags =
BuildFlags <$>
fmap
not
(switch
(long "skip-tests" <>
help "Skip build and running the test suites")) <*>
fmap
not
(switch
(long "skip-haddock" <>
help "Skip generating haddock documentation")) <*>
fmap
not
(switch
(long "skip-upload" <>
help "Skip uploading bundle, docs, etc.")) <*>
switch
(long "enable-library-profiling" <>
help "Enable profiling when building") <*>
switch
(long "enable-executable-dynamic" <>
help "Enable dynamic executables when building") <*>
switch
(long "verbose" <> short 'v' <>
help "Output verbose detail about the build steps") <*>
switch
(long "skip-check" <>
help "Skip the check phase, and pass --allow-newer to cabal configure")
nightlyUploadFlags = fromString <$> strArgument
(metavar "DATE" <>
help "Date, in YYYY-MM-DD format")
installFlags =
InstallFlags <$>
(fmap
BPSBundleWeb
(strOption
(long "bundle" <>
metavar "URL" <>
help "Stackage bundle containing build plan")) <|>
fmap
(BPSFile . decodeString)
(strOption
(long "build-plan" <>
metavar "PATH" <>
help "Build-plan YAML file"))) <*>
fmap
decodeString
(strArgument
(metavar "DESTINATION-PATH" <>
help "Destination directory path")) <*>
(fmap
(Just . decodeString)
(strOption
(long "log-dir" <>
metavar "PATH" <>
help "Location of log files (default DESTINATION-PATH/logs)")) <|>
pure Nothing) <*>
option
auto
(long "jobs" <>
metavar "NUMBER" <>
showDefault <> value 8 <>
help "Number of threads") <*>
switch
(long "global" <>
help "Install in global package database") <*>
fmap
not
(switch
(long "skip-tests" <>
help "Skip build and running the test suites")) <*>
fmap
not
(switch
(long "skip-haddock" <>
help "Skip generating haddock documentation")) <*>
switch
(long "enable-library-profiling" <>
help "Enable profiling when building") <*>
switch
(long "enable-executable-dynamic" <>
help "Enable dynamic executables when building") <*>
switch
(long "verbose" <> short 'v' <>
help "Output verbose detail about the build steps") <*>
switch
(long "skip-check" <>
help "Skip the check phase, and pass --allow-newer to cabal configure")

View File

@ -2,7 +2,7 @@
packages: packages:
"Michael Snoyman michael@snoyman.com @snoyberg": "Michael Snoyman michael@snoyman.com @snoyberg":
- bzlib-conduit - bzlib-conduit
- cabal-install < 1.19 - cabal-install < 1.19 # GHC 7.10 bumpd to 1.22
- cabal-src - cabal-src
- case-insensitive - case-insensitive
- classy-prelude-yesod - classy-prelude-yesod
@ -27,7 +27,10 @@ packages:
- warp-tls - warp-tls
- yackage - yackage
- yesod - yesod
- yesod-auth
- yesod-auth-oauth
- yesod-auth-deskcom - yesod-auth-deskcom
- authenticate-oauth
- yesod-bin - yesod-bin
- yesod-eventsource - yesod-eventsource
- yesod-fay - yesod-fay
@ -42,6 +45,11 @@ packages:
- repa-algorithms - repa-algorithms
- repa-devil - repa-devil
- JuicyPixels-repa - JuicyPixels-repa
- cereal-conduit
- binary-conduit
- lzma-conduit
- mutable-containers
- hpc-coveralls
"FP Complete michael@fpcomplete.com @snoyberg": "FP Complete michael@fpcomplete.com @snoyberg":
- alex - alex
@ -64,7 +72,7 @@ packages:
- fixed-list - fixed-list
- foreign-store - foreign-store
- formatting - formatting
- fpco-api #- fpco-api
- gtk2hs-buildtools - gtk2hs-buildtools
- happy - happy
- histogram-fill - histogram-fill
@ -105,18 +113,18 @@ packages:
- distributed-process-async - distributed-process-async
- distributed-process-client-server - distributed-process-client-server
- distributed-process-supervisor - distributed-process-supervisor
- distributed-process-task
# https://github.com/fpco/stackage/issues/381 - distributed-process-execution
#- distributed-process-task
#- distributed-process-execution
- kure - kure
"Omari Norman <omari@smileystation.com>": "Omari Norman <omari@smileystation.com>":
- barecheck - barecheck
- rainbow - rainbow
- rainbow-tests
- quickpull - quickpull
- multiarg
- prednote
- cartel
"Neil Mitchell": "Neil Mitchell":
- hlint - hlint
@ -144,6 +152,7 @@ packages:
"Jasper Van der Jeugt": "Jasper Van der Jeugt":
- blaze-html - blaze-html
- blaze-markup - blaze-markup
- hakyll
- stylish-haskell - stylish-haskell
"Antoine Latter": "Antoine Latter":
@ -175,7 +184,6 @@ packages:
- crypto-random-api - crypto-random-api
- hit - hit
- language-java - language-java
- language-java
- libgit - libgit
- pem - pem
- siphash - siphash
@ -202,8 +210,11 @@ packages:
- scrobble - scrobble
- shell-conduit - shell-conduit
- sourcemap - sourcemap
- hindent
- descriptive
- wrap
# requires old haddock currently - haskell-docs # requires old haddock currently - haskell-docs
# TODO: Add hindent and structured-haskell-mode once they've been ported to HSE 1.16. # TODO: Add structured-haskell-mode once they've been ported to HSE 1.16.
# GHC 7.6 # GHC 7.6
# "Alberto G. Corona <agocorona@gmail.com>": # "Alberto G. Corona <agocorona@gmail.com>":
@ -253,7 +264,7 @@ packages:
- monad-products - monad-products
- monad-st - monad-st
- monad-st - monad-st
- mtl < 2.2 - mtl < 2.2 # GHC 7.10 bump
- nats - nats
- numeric-extras - numeric-extras
- parsers - parsers
@ -304,8 +315,9 @@ packages:
"Brent Yorgey <byorgey@gmail.com>": "Brent Yorgey <byorgey@gmail.com>":
- active - active
- BlogLiterately # Temporarily disabled due to restrictive lens upper bound
- BlogLiterately-diagrams #- BlogLiterately
#- BlogLiterately-diagrams
- diagrams - diagrams
- diagrams-builder - diagrams-builder
- diagrams-contrib - diagrams-contrib
@ -325,6 +337,8 @@ packages:
- JuicyPixels - JuicyPixels
- FontyFruity - FontyFruity
- Rasterific - Rasterific
- svg-tree
- rasterific-svg
"Patrick Brisbin": "Patrick Brisbin":
- gravatar - gravatar
@ -365,6 +379,7 @@ packages:
- pipes - pipes
- pipes-parse - pipes-parse
- pipes-concurrency - pipes-concurrency
- pipes-safe
"Chris Allen <cma@bitemyapp.com>": "Chris Allen <cma@bitemyapp.com>":
- bloodhound - bloodhound
@ -378,6 +393,10 @@ packages:
- fay-uri - fay-uri
- snaplet-fay - snaplet-fay
"Sebastiaan Visser <haskell@fvisser.nl>":
- clay
- fclabels
"Rodrigo Setti <rodrigosetti@gmail.com>": "Rodrigo Setti <rodrigosetti@gmail.com>":
- messagepack - messagepack
- messagepack-rpc - messagepack-rpc
@ -399,9 +418,11 @@ packages:
- hPDB - hPDB
- hPDB-examples - hPDB-examples
# https://github.com/fpco/stackage/pull/382#issuecomment-68182467 - wordpass
# - wordpass - json-autotype
# - json-autotype
"Dominic Steinitz <dominic@steinitz.org>":
- yarr
"Roman Cheplyaka <roma@ro-che.info>": "Roman Cheplyaka <roma@ro-che.info>":
- action-permutations - action-permutations
@ -431,6 +452,7 @@ packages:
"George Giorgidze <giorgidze@gmail.com>": "George Giorgidze <giorgidze@gmail.com>":
- HCodecs - HCodecs
- YampaSynth - YampaSynth
- set-monad
"Phil Hargett <phil@haphazardhouse.net>": "Phil Hargett <phil@haphazardhouse.net>":
- courier - courier
@ -444,6 +466,8 @@ packages:
- circle-packing - circle-packing
- arbtt - arbtt
- ghc-heap-view - ghc-heap-view
- tttool
- gipeda
"Aditya Bhargava <adit@adit.io": "Aditya Bhargava <adit@adit.io":
- HandsomeSoup - HandsomeSoup
@ -453,7 +477,8 @@ packages:
- openpgp-asciiarmor - openpgp-asciiarmor
- MusicBrainz - MusicBrainz
- DAV - DAV
- hopenpgp-tools # https://github.com/fpco/stackage/issues/463
#- hopenpgp-tools
# https://github.com/fpco/stackage/issues/160 # https://github.com/fpco/stackage/issues/160
"Ketil Malde": "Ketil Malde":
@ -483,9 +508,9 @@ packages:
- code-builder - code-builder
- fay-builder - fay-builder
- generic-aeson - generic-aeson
- generic-xmlpickler
- hxt-pickle-utils - hxt-pickle-utils
- imagesize-conduit - imagesize-conduit
- imagesize-conduit
- json-schema - json-schema
- multipart - multipart
- regular-xmlpickler - regular-xmlpickler
@ -498,8 +523,6 @@ packages:
- rest-types - rest-types
- rest-wai - rest-wai
- tostring - tostring
- tostring
- uri-encode
- uri-encode - uri-encode
"Simon Michael <simon@joyful.com>": "Simon Michael <simon@joyful.com>":
@ -509,7 +532,10 @@ packages:
- io-manager - io-manager
"Dimitri Sabadie <dimitri.sabadie@gmail.com": "Dimitri Sabadie <dimitri.sabadie@gmail.com":
# https://github.com/fpco/stackage/pull/461#issuecomment-76914158
# - al
- monad-journal - monad-journal
- smoothie
"Thomas Schilling <nominolo@googlemail.com>": "Thomas Schilling <nominolo@googlemail.com>":
- ghc-syb-utils - ghc-syb-utils
@ -543,6 +569,7 @@ packages:
"Emanuel Borsobom <manny@fpcomplete.com>": "Emanuel Borsobom <manny@fpcomplete.com>":
- BoundedChan - BoundedChan
- broadcast-chan
- bytestring-lexing - bytestring-lexing
- bytestring-trie - bytestring-trie
- data-accessor - data-accessor
@ -553,6 +580,7 @@ packages:
- haddock-api - haddock-api
- here - here
- hlibgit2 - hlibgit2
- gitlib-libgit2
- hostname-validate - hostname-validate
- interpolatedstring-perl6 - interpolatedstring-perl6
- iproute - iproute
@ -561,6 +589,7 @@ packages:
- multimap - multimap
- parallel-io - parallel-io
- text-binary - text-binary
- wl-pprint-text
"Michael Sloan <mgsloan@gmail.com": "Michael Sloan <mgsloan@gmail.com":
- th-orphans - th-orphans
@ -574,7 +603,7 @@ packages:
- hasql-backend - hasql-backend
- hasql-postgres - hasql-postgres
- list-t - list-t
- mtl-prelude < 2 - mtl-prelude < 2 # GHC 7.10 bump
- neat-interpolation - neat-interpolation
- partial-handler - partial-handler
- postgresql-binary - postgresql-binary
@ -588,6 +617,11 @@ packages:
- graph-core - graph-core
- reroute - reroute
- Spock - Spock
- Spock-digestive
- Spock-worker
- users
- users-test
- users-postgresql-simple
"Joey Eremondi <joey@eremondi.com>": "Joey Eremondi <joey@eremondi.com>":
- aeson-pretty - aeson-pretty
@ -618,42 +652,137 @@ packages:
- shake-language-c - shake-language-c
"Marcin Mrotek <marcin.jan.mrotek@gmail.com>": "Marcin Mrotek <marcin.jan.mrotek@gmail.com>":
- diagrams-hsqml
- type-list - type-list
- vinyl-utils
"Marcin Mrotek <marcin.jan.mrotek@gmail.com>":
- type-list
"David Turner <dave.c.turner@gmail.com>": "David Turner <dave.c.turner@gmail.com>":
- alarmclock - alarmclock
- bank-holidays-england - bank-holidays-england
"Haskell Servant jkarni@gmail.com @jkarni":
- servant
- servant-client
- servant-docs
- servant-jquery
- servant-server
"Alexandr Ruchkin voidex@live.com @mvoidex":
- hdocs
- hsdev
"Aleksey Kliger aleksey@lambdageek.org @lambdageek":
- unbound-generics
"Alois Cochard alois.cochard@gmail.com @aloiscochard":
- codex
- machines-directory
- machines-io
- machines-process
# on behalf of Bryan O'Sullivan @bos
- wreq
"Andraz Bajt andraz@bajt.me @edofic":
- effect-handlers
- koofr-client
- snowflake
"Leza M. Lutonda lemol-c@hotmail.com @lemol":
- HaskellNet
"Jens Petersen juhpetersen@gmail.com @juhp":
- cabal-rpm
"Renzo Carbonara renzocarbonara@gmail.com @k0001":
- network-simple
- pipes-aeson
- pipes-attoparsec
- pipes-binary
- pipes-network
"Tomas Carnecky":
- rethinkdb-client-driver
"Alexandr Kurilin alex@kurilin.net @alex_kurilin":
- bcrypt
"Jeffrey Rosenbluth jeffrey.rosenbluth@gmail.com":
- palette
- diagrams-canvas
- diagrams-rasterific
- lucid-svg
"Gabríel Arthúr Pétursson gabriel@system.is":
- sdl2
"Leon Mergen leon@solatis.com @solatis":
- network-attoparsec
- network-anonymous-i2p
"Timothy Jones git@zmthy.io @zmthy":
- cabal-test-quickcheck
- http-media
"Greg V greg@unrelenting.technology @myfreeweb":
- gitson
- pcre-heavy
"Francesco Mazzoli f@mazzo.li @bitonic":
- language-c-quote
"Sönke Hahn soenkehahn@gmail.com @soenkehahn":
- string-conversions
"Oleg Grenrus oleg.grenrus@iki.fi @phadej":
- waitra
"Stackage upper bounds": "Stackage upper bounds":
# Force a specific version that's compatible with transformers 0.3 # Force a specific version that's compatible with transformers 0.3
- transformers-compat == 0.3.3.3 - transformers-compat == 0.4.0.3
# https://github.com/fpco/stackage/issues/291 # https://github.com/fpco/stackage/issues/390
- random < 1.0.1.3 # NOTE: When this issue is resolved, remove the expected test failure
# for language-ecmascript as well.
- language-ecmascript < 0.17
# https://github.com/fpco/stackage/issues/318 # https://github.com/fpco/stackage/issues/407
- HaXml < 1.25 - HStringTemplate < 0.8
# https://github.com/fpco/stackage/issues/319 # https://github.com/fpco/stackage/issues/410
- polyparse < 1.10 - elm-package < 0.4
# https://github.com/fpco/stackage/issues/370 # https://github.com/fpco/stackage/issues/415
- monad-control < 1 - hackage-db < 1.12
- hasql < 0.5
- list-t < 0.4
# Global flags are applied to all packages # https://github.com/fpco/stackage/issues/424
global-flags: - control-monad-free < 0.6
blaze_html_0_5: true
small_base: true # https://github.com/fpco/stackage/issues/426
https: true - utf8-string < 1
splitbase: true
old-locale: true # https://github.com/fpco/stackage/issues/440
new-base: true - th-orphans < 0.9
bytestring-in-base: false - file-location < 0.4.7
test-hlint: false
network-uri: true # https://github.com/fpco/stackage/issues/442
- blaze-builder < 0.4
- blaze-markup < 0.7
- blaze-html < 0.8
# https://github.com/fpco/stackage/issues/443
- exceptions < 0.7
- rest-client < 0.5
- rest-types < 1.13
- rest-core < 0.35
- rest-gen < 0.17
- rest-wai < 0.1.0.7
# https://github.com/fpco/stackage/issues/467
- lens < 4.8
# Package flags are applied to individual packages, and override the values of # Package flags are applied to individual packages, and override the values of
# global-flags # global-flags
@ -672,6 +801,44 @@ package-flags:
simplelocalnet: true simplelocalnet: true
p2p: true p2p: true
# GHC 7.10: Remove this
# Note that the flag is lower-cased, because that's what Cabal does
# Perhaps the codebase should automatically lower case flag names?
storable-complex:
instanceinbase: false
logfloat:
splitbase: true
curl:
new-base: true
# GHC 7.10 remove
aeson:
old-locale: true
tttool:
old-locale: true
hxt:
network-uri: true
hxt-http:
network-uri: true
hxt-relaxng:
network-uri: true
pandoc:
https: true
text:
integer-simple: false
tar:
old-time: false
mtl-compat:
two-point-one: true
two-point-two: false
# By skipping a test suite, we do not pull in the build dependencies # By skipping a test suite, we do not pull in the build dependencies
skipped-tests: skipped-tests:
- ReadArgs # old version of hspec - ReadArgs # old version of hspec
@ -718,17 +885,15 @@ skipped-tests:
# https://github.com/fpco/stackage/pull/380#issuecomment-68060871 # https://github.com/fpco/stackage/pull/380#issuecomment-68060871
- Rasterific - Rasterific
# https://github.com/Soostone/retry/issues/18
- retry
# Tests which we should build and run, but which are expected to fail. We # Tests which we should build and run, but which are expected to fail. We
# should not fail a build based on a test failure for one of these packages. # should not fail a build based on a test failure for one of these packages.
expected-test-failures: expected-test-failures:
# Requires an old version of WAI and Warp for tests # Requires an old version of WAI and Warp for tests
- HTTP - HTTP
# text and setenv have recursive dependencies in their tests, which
# cabal can't (yet) handle
- text
- setenv
# https://github.com/bos/statistics/issues/42 # https://github.com/bos/statistics/issues/42
- statistics - statistics
@ -852,6 +1017,61 @@ expected-test-failures:
- crypto-numbers - crypto-numbers
- distributed-process-task - distributed-process-task
# https://github.com/vincenthz/hs-crypto-pubkey/issues/17
- crypto-pubkey
# https://github.com/jswebtools/language-ecmascript/issues/60
- language-ecmascript
# https://github.com/kazu-yamamoto/unix-time/issues/29
- unix-time
# Tests can fail when the build plan fails, which happens arbitrarily.
- stackage
# https://github.com/TomMD/DRBG/issues/7
- DRBG
# https://github.com/bos/wreq/issues/53
- wreq
# Requires local database running
- rethinkdb-client-driver
# https://github.com/haskell-distributed/distributed-process-execution/issues/2
- distributed-process-execution
# Seems to depend on mtl being installed in user package database, which
# isn't always the case (e.g., build server)
- happy
# https://github.com/jberryman/directory-tree/issues/4
- directory-tree
# https://github.com/zmthy/http-media/issues/11
- http-media
# https://github.com/ekmett/semigroupoids/issues/18
- semigroupoids
# https://github.com/ndmitchell/hoogle/issues/101
- hoogle
# https://github.com/myfreeweb/gitson/issues/1
- gitson
# https://github.com/jcristovao/enclosed-exceptions/issues/6
- enclosed-exceptions
# Expects a running PostgreSQL server
- users-postgresql-simple
# Problems with linking with system libraries on Ubuntu 12.04
- nettle
# Requires locally running services
- network-anonymous-i2p
# Haddocks which are expected to fail. Same concept as expected test failures. # Haddocks which are expected to fail. Same concept as expected test failures.
expected-haddock-failures: expected-haddock-failures:
# https://github.com/acw/bytestring-progress/issues/4 # https://github.com/acw/bytestring-progress/issues/4
@ -860,6 +1080,12 @@ expected-haddock-failures:
# https://github.com/ekmett/gl/issues/4 # https://github.com/ekmett/gl/issues/4
- gl - gl
# https://github.com/leventov/yarr/issues/5
- yarr
# https://github.com/wereHamster/rethinkdb-client-driver/issues/1
- rethinkdb-client-driver
# Benchmarks which should not be built. Note that Stackage does *not* generally # Benchmarks which should not be built. Note that Stackage does *not* generally
# build benchmarks. The difference here will be whether dependencies for these # build benchmarks. The difference here will be whether dependencies for these
# benchmarks are included or not. # benchmarks are included or not.
@ -886,6 +1112,10 @@ skipped-benchmarks:
# sometimes falls out-of-sync on hasql-postgres # sometimes falls out-of-sync on hasql-postgres
- hasql - hasql
skipped-profiling:
# https://github.com/nomeata/ghc-heap-view/commit/8d198eb8fbbad2ce0c4527c781659f35b8909c04#diff-8288955e209cfbead5b318a8598be9c0R10
- ghc-heap-view
# Mapping from Github account holding a package to the Github users who should # Mapping from Github account holding a package to the Github users who should
# be pinged on failure. If no value is specified here, then the owning account # be pinged on failure. If no value is specified here, then the owning account
# will be pinged. # will be pinged.
@ -908,3 +1138,5 @@ github-users:
- mightybyte - mightybyte
haskell-ro: haskell-ro:
- mihaimaruseac - mihaimaruseac
elm-lang:
- JoeyEremondi

View File

@ -647,7 +647,7 @@ constraints: abstract-deque ==0.3,
semigroups ==0.16.0.1, semigroups ==0.16.0.1,
sendfile ==0.7.9, sendfile ==0.7.9,
seqloc ==0.6, seqloc ==0.6,
setenv ==0.1.1.1, setenv ==0.1.1.2,
SHA ==1.6.4.1, SHA ==1.6.4.1,
shake ==0.14.2, shake ==0.14.2,
shake-language-c ==0.6.3, shake-language-c ==0.6.3,

View File

@ -10,13 +10,17 @@
# instructions, see: # instructions, see:
# http://www.stackage.org/install # http://www.stackage.org/install
sudo add-apt-repository -y ppa:chris-lea/zeromq add-apt-repository -y ppa:chris-lea/zeromq
sudo add-apt-repository -y ppa:floe/libtisch add-apt-repository -y ppa:floe/libtisch
sudo apt-get update add-apt-repository -y ppa:zoogie/sdl2-snapshots
sudo apt-get install -y \ apt-get update
apt-get install -y \
build-essential \ build-essential \
libncurses-dev \ libncurses-dev \
git \ git \
wget \
m4 \
texlive-full \
libgmp3c2 \ libgmp3c2 \
libgmp3-dev \ libgmp3-dev \
zlib1g-dev \ zlib1g-dev \
@ -33,11 +37,11 @@ sudo apt-get install -y \
llvm \ llvm \
libbz2-dev \ libbz2-dev \
libjudy-dev \ libjudy-dev \
libsqlite3-dev \
libmysqlclient-dev \ libmysqlclient-dev \
libpq-dev \ libpq-dev \
libicu-dev \ libicu-dev \
libssl-dev \ libssl-dev \
nettle-dev \
libgsl0-dev \ libgsl0-dev \
libblas-dev \ libblas-dev \
liblapack-dev \ liblapack-dev \
@ -46,4 +50,22 @@ sudo apt-get install -y \
libnotify-dev \ libnotify-dev \
libgd2-xpm-dev \ libgd2-xpm-dev \
libyaml-dev \ libyaml-dev \
liblzma-dev \
libsdl2-dev \
libxss-dev \
libzmq3-dev libzmq3-dev
mkdir /tmp/nettle-build
(
cd /tmp/nettle-build
wget https://ftp.gnu.org/gnu/nettle/nettle-2.7.1.tar.gz
tar zxf nettle-2.7.1.tar.gz
cd nettle-2.7.1
./configure --prefix=/usr
make
make install
mkdir -p /usr/lib/x86_64-linux-gnu/
ln -sfv /usr/lib/libnettle.so.4.7 /usr/lib/x86_64-linux-gnu/libnettle.so.4
)
rm -rf /tmp/nettle-build

View File

@ -1,5 +1,5 @@
name: stackage name: stackage
version: 0.4.0 version: 0.5.2
synopsis: "Stable Hackage," tools for creating a vetted set of packages from Hackage. synopsis: "Stable Hackage," tools for creating a vetted set of packages from Hackage.
description: Please see <http://www.stackage.org/package/stackage> for a description and documentation. description: Please see <http://www.stackage.org/package/stackage> for a description and documentation.
homepage: https://github.com/fpco/stackage homepage: https://github.com/fpco/stackage
@ -12,6 +12,7 @@ build-type: Simple
cabal-version: >=1.10 cabal-version: >=1.10
extra-source-files: README.md extra-source-files: README.md
ChangeLog.md ChangeLog.md
test/test-build-constraints.yaml
library library
default-language: Haskell2010 default-language: Haskell2010
@ -22,7 +23,9 @@ library
Stackage.BuildPlan Stackage.BuildPlan
Stackage.CheckBuildPlan Stackage.CheckBuildPlan
Stackage.UpdateBuildPlan Stackage.UpdateBuildPlan
Stackage.GhcPkg
Stackage.GithubPings Stackage.GithubPings
Stackage.InstallBuild
Stackage.PackageDescription Stackage.PackageDescription
Stackage.ServerBundle Stackage.ServerBundle
Stackage.Upload Stackage.Upload
@ -62,6 +65,7 @@ library
, streaming-commons >= 0.1.7.1 , streaming-commons >= 0.1.7.1
, semigroups , semigroups
, xml-conduit , xml-conduit
, conduit
executable stackage executable stackage
default-language: Haskell2010 default-language: Haskell2010
@ -69,6 +73,8 @@ executable stackage
main-is: stackage.hs main-is: stackage.hs
build-depends: base build-depends: base
, stackage , stackage
, optparse-applicative >= 0.11
, system-filepath
ghc-options: -rtsopts -threaded -with-rtsopts=-N ghc-options: -rtsopts -threaded -with-rtsopts=-N
test-suite spec test-suite spec

View File

@ -1,21 +1,66 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
module Stackage.BuildPlanSpec (spec) where module Stackage.BuildPlanSpec (spec) where
import Stackage.BuildPlan
import Stackage.Prelude
import Stackage.BuildConstraints
import Stackage.UpdateBuildPlan
import Test.Hspec
import qualified Data.Yaml as Y
import Distribution.Version (anyVersion)
import qualified Data.Map as Map import qualified Data.Map as Map
import Network.HTTP.Client (withManager) import qualified Data.Map.Strict as M
import Network.HTTP.Client.TLS (tlsManagerSettings) import qualified Data.Set as S
import Data.Yaml
import qualified Data.Yaml as Y
import Distribution.Version
import Network.HTTP.Client
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Stackage.BuildConstraints
import Stackage.BuildPlan
import Stackage.CheckBuildPlan
import Stackage.PackageDescription
import Stackage.Prelude
import Stackage.UpdateBuildPlan
import Test.Hspec
spec :: Spec spec :: Spec
spec = it "works" $ withManager tlsManagerSettings $ \man -> do spec = do
bc <- defaultBuildConstraints man it "simple package set" $ check testBuildConstraints $ makePackageSet
bp <- newBuildPlan bc [("foo", [0, 0, 0], [("bar", thisV [0, 0, 0])])
,("bar", [0, 0, 0], [])]
it "bad version range on depdendency fails" $ badBuildPlan $ makePackageSet
[("foo", [0, 0, 0], [("bar", thisV [1, 1, 0])])
,("bar", [0, 0, 0], [])]
it "nonexistent package fails to check" $ badBuildPlan $ makePackageSet
[("foo", [0, 0, 0], [("nonexistent", thisV [0, 0, 0])])
,("bar", [0, 0, 0], [])]
it "mutual cycles fail to check" $ badBuildPlan $ makePackageSet
[("foo", [0, 0, 0], [("bar", thisV [0, 0, 0])])
,("bar", [0, 0, 0], [("foo", thisV [0, 0, 0])])]
it "nested cycles fail to check" $ badBuildPlan $ makePackageSet
[("foo", [0, 0, 0], [("bar", thisV [0, 0, 0])])
,("bar", [0, 0, 0], [("mu", thisV [0, 0, 0])])
,("mu", [0, 0, 0], [("foo", thisV [0, 0, 0])])]
{- Shouldn't be testing this actually
it "default package set checks ok" $
check defaultBuildConstraints getLatestAllowedPlans
-}
-- | Checking should be considered a bad build plan.
badBuildPlan :: (BuildConstraints -> IO (Map PackageName PackagePlan))
-> void
-> IO ()
badBuildPlan m _ = do
mu <- try (check testBuildConstraints m)
case mu of
Left (_ :: BadBuildPlan) ->
return ()
Right () ->
error "Expected bad build plan."
-- | Check build plan with the given package set getter.
check :: (Manager -> IO BuildConstraints)
-> (BuildConstraints -> IO (Map PackageName PackagePlan))
-> IO ()
check readPlanFile getPlans = withManager tlsManagerSettings $ \man -> do
bc <- readPlanFile man
plans <- getPlans bc
bp <- newBuildPlan plans bc
let bs = Y.encode bp let bs = Y.encode bp
ebp' = Y.decodeEither bs ebp' = Y.decodeEither bs
@ -25,14 +70,74 @@ spec = it "works" $ withManager tlsManagerSettings $ \man -> do
forM_ allPackages $ \name -> forM_ allPackages $ \name ->
(name, lookup name (bpPackages bp')) `shouldBe` (name, lookup name (bpPackages bp')) `shouldBe`
(name, lookup name (bpPackages bp)) (name, lookup name (bpPackages bp))
bpGithubUsers bp' `shouldBe` bpGithubUsers bp bpGithubUsers bp' `shouldBe` bpGithubUsers bp
when (bp' /= bp) $ error "bp' /= bp" when (bp' /= bp) $ error "bp' /= bp"
bp2 <- updateBuildPlan bp bp2 <- updateBuildPlan plans bp
when (dropVersionRanges bp2 /= dropVersionRanges bp) $ error "bp2 /= bp" when (dropVersionRanges bp2 /= dropVersionRanges bp) $ error "bp2 /= bp"
checkBuildPlan bp
where where
dropVersionRanges bp = dropVersionRanges bp =
bp { bpPackages = map go $ bpPackages bp } bp { bpPackages = map go $ bpPackages bp }
where where
go pb = pb { ppConstraints = go' $ ppConstraints pb } go pb = pb { ppConstraints = go' $ ppConstraints pb }
go' pc = pc { pcVersionRange = anyVersion } go' pc = pc { pcVersionRange = anyVersion }
-- | Make a package set from a convenient data structure.
makePackageSet
:: [(String,[Int],[(String,VersionRange)])]
-> BuildConstraints
-> IO (Map PackageName PackagePlan)
makePackageSet ps _ =
return $
M.fromList $
map
(\(name,ver,deps) ->
( PackageName name
, dummyPackage ver $
M.fromList $
map
(\(dname,dver) ->
( PackageName dname
, DepInfo {diComponents = S.fromList
[CompLibrary]
,diRange = dver}))
deps))
ps
where
dummyPackage v deps =
PackagePlan
{ppVersion = Version v []
,ppGithubPings = mempty
,ppUsers = mempty
,ppConstraints =
PackageConstraints
{pcVersionRange = anyV
,pcMaintainer = Nothing
,pcTests = Don'tBuild
,pcHaddocks = Don'tBuild
,pcBuildBenchmarks = False
,pcFlagOverrides = mempty
,pcEnableLibProfile = False}
,ppDesc =
SimpleDesc
{sdPackages = deps
,sdTools = mempty
,sdProvidedExes = mempty
,sdModules = mempty}}
-- | This exact version is required.
thisV :: [Int] -> VersionRange
thisV ver = thisVersion (Version ver [])
-- | Accept any version.
anyV :: VersionRange
anyV = anyVersion
-- | Test plan.
testBuildConstraints :: void -> IO BuildConstraints
testBuildConstraints _ =
decodeFileEither
(fpToString fp) >>=
either throwIO toBC
where fp = "test/test-build-constraints.yaml"

View File

@ -0,0 +1,20 @@
packages:
"Test":
- foo
- bar
global-flags: []
skipped-tests: []
expected-test-failures: []
expected-haddock-failures: []
skipped-benchmarks: []
skipped-profiling: []
github-users:
bar:
- demo
package-flags:
foo:
demo: true