mirror of
https://github.com/commercialhaskell/stackage.git
synced 2026-01-11 23:08:30 +01:00
Merge branch 'master' of https://github.com/fpco/stackage
This commit is contained in:
commit
8b8b3a87ec
@ -5,3 +5,4 @@ logs
|
||||
cabal.sandbox.config
|
||||
tarballs
|
||||
*.yaml
|
||||
.git
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,13 +1,4 @@
|
||||
dist
|
||||
*.o
|
||||
*.hi
|
||||
*.chi
|
||||
*.chs.h
|
||||
*.swp
|
||||
/builds/
|
||||
/logs/
|
||||
/.cabal-sandbox/
|
||||
cabal.sandbox.config
|
||||
nightly-*.yaml
|
||||
lts-*.yaml
|
||||
/tarballs/
|
||||
|
||||
11
.travis.yml
11
.travis.yml
@ -1,11 +1,6 @@
|
||||
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
|
||||
@ -17,8 +12,10 @@ install:
|
||||
- cabal --version
|
||||
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||
- travis_retry cabal update
|
||||
- cabal install -j
|
||||
- wget https://s3.amazonaws.com/stackage-travis/stackage-curator/stackage-curator.bz2
|
||||
- bunzip2 stackage-curator.bz2
|
||||
- chmod +x stackage-curator
|
||||
|
||||
# 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
|
||||
- ./stackage-curator check
|
||||
|
||||
55
ChangeLog.md
55
ChangeLog.md
@ -1,55 +0,0 @@
|
||||
## 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
|
||||
|
||||
* Added `justCheck` and `stackage check` command line.
|
||||
|
||||
## 0.3.0.1
|
||||
|
||||
Pre-fetch all packages from Hackage to catch Hackage downtime early.
|
||||
|
||||
## 0.3.0.0
|
||||
|
||||
* Return progress URL from uploadBundle
|
||||
|
||||
## 0.2.1.4
|
||||
|
||||
Generate a `core` file in bundles.
|
||||
|
||||
## 0.2.1.1
|
||||
|
||||
Run postBuild earlier to avoid problems from broken doc uploads.
|
||||
|
||||
## 0.2.1.0
|
||||
|
||||
* Use TLS manager (to download from Github)
|
||||
|
||||
## 0.2.0.0
|
||||
|
||||
* Minor fixes
|
||||
* `pbGlobalInstall`
|
||||
|
||||
## 0.1.0.0
|
||||
|
||||
First version of Stackage which is made available as its own package. The
|
||||
codebase has been completely rewritten at this point, to be ready for generated
|
||||
both Stackage Nightly and LTS Haskell distributions.
|
||||
12
Dockerfile
12
Dockerfile
@ -14,14 +14,12 @@ 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
|
||||
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 /opt/ghc/7.8.4/bin:/opt/cabal/1.20/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
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
|
||||
RUN cp $HOME/.cabal/bin/* /usr/local/bin
|
||||
RUN rm -rf $HOME/.cabal $HOME/.ghc /tmp/stackage
|
||||
RUN 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 wget https://s3.amazonaws.com/stackage-travis/stackage-curator/stackage-curator.bz2 && bunzip2 stackage-curator.bz2 && chmod +x stackage-curator && mv stackage-curator /usr/local/bin
|
||||
|
||||
RUN cd /home/stackage && cabal update && stackage check
|
||||
RUN cd /home/stackage && cabal update && stackage-curator check
|
||||
|
||||
75
README.md
75
README.md
@ -1,16 +1,22 @@
|
||||
stackage
|
||||
========
|
||||
|
||||
[](https://travis-ci.org/fpco/stackage)
|
||||
|
||||
"Stable Hackage," tools for creating a vetted set of packages from Hackage.
|
||||
|
||||
__NOTE__ This repository is for package authors to get their code into
|
||||
Stackage. If you simply want to use Stackage as an end user, please follow the
|
||||
instructions on [http://www.stackage.org/](http://www.stackage.org).
|
||||
|
||||
A note about the codebase: the goal is to minimize dependencies and have
|
||||
the maximum range of supported compiler versions. Therefore, we avoid
|
||||
anything "complicated." For example, instead of using the text package,
|
||||
we use Strings everywhere.
|
||||
The Stackage project consists of multiple repositories. This repository
|
||||
contains the metadata on packages to be included in future builds and some
|
||||
project information. In addition, we have the following repositories:
|
||||
|
||||
* [stackage-server](https://github.com/fpco/stackage-server) [](https://travis-ci.org/fpco/stackage-server)
|
||||
* [stackage-curator](https://github.com/fpco/stackage-curator) [](https://travis-ci.org/fpco/stackage-curator)
|
||||
* [stackage-types](https://github.com/fpco/stackage-types) [](https://travis-ci.org/fpco/stackage-types)
|
||||
* [lts-haskell](https://github.com/fpco/lts-haskell)
|
||||
|
||||
Get your package included
|
||||
-------------------------
|
||||
@ -37,6 +43,23 @@ dependencies, you may send a pull request without testing first.
|
||||
You should also read the [maintainers
|
||||
agreement](https://github.com/fpco/stackage/wiki/Maintainers-Agreement).
|
||||
|
||||
Package Author Guidelines
|
||||
-------------------------
|
||||
|
||||
There are some basic rules to get your package to play nice with Stackage. Here
|
||||
are some quick guidelines to hopefully make this easier:
|
||||
|
||||
* Make sure that your code is buildability and testable from Hackage. Often
|
||||
times, authors test their builds locally, but the tarball that gets uploaded
|
||||
to Hackage is missing some necessary files. The best way to do this is to
|
||||
set up a Travis job to do it for you. We recommend the
|
||||
[multi-ghc-travis](https://github.com/hvr/multi-ghc-travis) approach.
|
||||
* Make your code compatible with the newest versions of all dependencies.
|
||||
* Make your code compatible with the versions of libraries that ship with GHC ([more information on lenient lower bounds](https://www.fpcomplete.com/blog/2014/05/lenient-lower-bounds)).
|
||||
|
||||
There are certainly many other tips that could be added here. If you think of
|
||||
any, please send a pull request!
|
||||
|
||||
Build the package set
|
||||
---------------------
|
||||
|
||||
@ -51,7 +74,7 @@ build by running:
|
||||
|
||||
### Docker
|
||||
|
||||
Note: This method is currently considered experimental.
|
||||
Note: This method has been disabled for now, but may be enabled again in the future.
|
||||
|
||||
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
|
||||
@ -90,45 +113,3 @@ The following describes at a high level the series of steps for processing
|
||||
1. Load up most recent build plan
|
||||
2. Convert build plan into constraints for next build
|
||||
3. Continue from step (3) above
|
||||
|
||||
## Code explanation
|
||||
|
||||
We start off with *constraints*. Constraints state things like "package X has a
|
||||
given version range," who the maintainer is for a package, the description of
|
||||
the system/compiler being used, etc. `BuildConstraints` describes the build as
|
||||
a whole, whereas `PackageConstraints` describes the constraints on an
|
||||
individual package.
|
||||
|
||||
There are two primary ways of getting a `BuildConstraints`.
|
||||
`defaultBuildConstraints` inspects the first GHC in the PATH environment variable to
|
||||
determine GHC version, core packages, core tools, etc. It then uses the
|
||||
`Stackage.Config` module to extract information on additional packages to be
|
||||
installed. The secondary approach is in `Stackage2.UpdateBuildPlan`, which will be
|
||||
discussed later.
|
||||
|
||||
`BuildConstraints` does not specify a build completely. That is given by a
|
||||
`BuildPlan`, which is similarly broken down into `BuildPlan` and `PackagePlan`.
|
||||
In order to get a `BuildPlan`, we need two pieces of information: the
|
||||
`BuildConstraints`, and a package index. The package index (usually downloaded
|
||||
from Hackage) is a collection of all of the cabal files available.
|
||||
|
||||
By applying a `BuildConstraints` to a package index (via `newBuildPlan`), we
|
||||
get a proposed `BuildPlan`. There is no guarantee that this `BuildPlan` is
|
||||
valid. To validate it, we use `checkBuildPlan`. A `BuildPlan` is an instance of
|
||||
both `ToJSON` and `FromJSON`, and therefore can be serialized to a file for
|
||||
later use.
|
||||
|
||||
When dealing with LTS Haskell, we want to be able to take a `BuildPlan`, and
|
||||
update to a newer `BuildPlan` that keeps all packages at the same major
|
||||
version. `updateBuildConstraints` turns a `BuildPlan` into a new
|
||||
`BuildConstraints` with that restriction, and `updateBuildPlan` applies
|
||||
`newBuildPlan` to that result. As mentioned previously: this is *not* a
|
||||
validated result, and therefore `checkBuildPlan` must be used.
|
||||
|
||||
A `BuildPlan` can be acted on. This is done to check that all packages compile
|
||||
together, run relevant test suites, test Haddock documentation is correct, and
|
||||
produce as artifacts both a self-contained GHC binary package database and a
|
||||
set of Haddock documentation. (Not yet implemented.)
|
||||
|
||||
A `BuildPlan` may be converted into a bundle to be uploaded to Stackage Server.
|
||||
(Not yet implemented.)
|
||||
|
||||
@ -1,234 +0,0 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
-- | The constraints on package selection for a new build plan.
|
||||
module Stackage.BuildConstraints
|
||||
( BuildConstraints (..)
|
||||
, PackageConstraints (..)
|
||||
, TestState (..)
|
||||
, SystemInfo (..)
|
||||
, getSystemInfo
|
||||
, defaultBuildConstraints
|
||||
, toBC
|
||||
, BuildConstraintsSource (..)
|
||||
, loadBuildConstraints
|
||||
) where
|
||||
|
||||
import Control.Monad.Writer.Strict (execWriter, tell)
|
||||
import Data.Aeson
|
||||
import qualified Data.Map as Map
|
||||
import Data.Yaml (decodeEither', decodeFileEither)
|
||||
import Distribution.Package (Dependency (..))
|
||||
import Distribution.System (Arch, OS)
|
||||
import qualified Distribution.System
|
||||
import Distribution.Version (anyVersion)
|
||||
import Filesystem (isFile)
|
||||
import Network.HTTP.Client (Manager, httpLbs, responseBody, Request)
|
||||
import Stackage.CorePackages
|
||||
import Stackage.Prelude
|
||||
|
||||
data TestState = ExpectSuccess
|
||||
| ExpectFailure
|
||||
| Don'tBuild -- ^ when the test suite will pull in things we don't want
|
||||
deriving (Show, Eq, Ord, Bounded, Enum)
|
||||
|
||||
testStateToText :: TestState -> Text
|
||||
testStateToText ExpectSuccess = "expect-success"
|
||||
testStateToText ExpectFailure = "expect-failure"
|
||||
testStateToText Don'tBuild = "do-not-build"
|
||||
|
||||
instance ToJSON TestState where
|
||||
toJSON = toJSON . testStateToText
|
||||
instance FromJSON TestState where
|
||||
parseJSON = withText "TestState" $ \t ->
|
||||
case lookup t states of
|
||||
Nothing -> fail $ "Invalid state: " ++ unpack t
|
||||
Just v -> return v
|
||||
where
|
||||
states = asHashMap $ mapFromList
|
||||
$ map (\x -> (testStateToText x, x)) [minBound..maxBound]
|
||||
|
||||
data SystemInfo = SystemInfo
|
||||
{ siGhcVersion :: Version
|
||||
, siOS :: OS
|
||||
, siArch :: Arch
|
||||
, siCorePackages :: Map PackageName Version
|
||||
, siCoreExecutables :: Set ExeName
|
||||
}
|
||||
deriving (Show, Eq, Ord)
|
||||
instance ToJSON SystemInfo where
|
||||
toJSON SystemInfo {..} = object
|
||||
[ "ghc-version" .= display siGhcVersion
|
||||
, "os" .= display siOS
|
||||
, "arch" .= display siArch
|
||||
, "core-packages" .= Map.mapKeysWith const unPackageName (map display siCorePackages)
|
||||
, "core-executables" .= siCoreExecutables
|
||||
]
|
||||
instance FromJSON SystemInfo where
|
||||
parseJSON = withObject "SystemInfo" $ \o -> do
|
||||
let helper name = (o .: name) >>= either (fail . show) return . simpleParse
|
||||
siGhcVersion <- helper "ghc-version"
|
||||
siOS <- helper "os"
|
||||
siArch <- helper "arch"
|
||||
siCorePackages <- (o .: "core-packages") >>= goPackages
|
||||
siCoreExecutables <- o .: "core-executables"
|
||||
return SystemInfo {..}
|
||||
where
|
||||
goPackages = either (fail . show) return
|
||||
. mapM simpleParse
|
||||
. Map.mapKeysWith const mkPackageName
|
||||
|
||||
data BuildConstraints = BuildConstraints
|
||||
{ bcPackages :: Set PackageName
|
||||
-- ^ This does not include core packages.
|
||||
, bcPackageConstraints :: PackageName -> PackageConstraints
|
||||
|
||||
, bcSystemInfo :: SystemInfo
|
||||
|
||||
, bcGithubUsers :: Map Text (Set Text)
|
||||
-- ^ map an account to set of pingees
|
||||
}
|
||||
|
||||
data PackageConstraints = PackageConstraints
|
||||
{ pcVersionRange :: VersionRange
|
||||
, pcMaintainer :: Maybe Maintainer
|
||||
, pcTests :: TestState
|
||||
, pcHaddocks :: TestState
|
||||
, pcBuildBenchmarks :: Bool
|
||||
, pcFlagOverrides :: Map FlagName Bool
|
||||
, pcEnableLibProfile :: Bool
|
||||
}
|
||||
deriving (Show, Eq)
|
||||
instance ToJSON PackageConstraints where
|
||||
toJSON PackageConstraints {..} = object $ addMaintainer
|
||||
[ "version-range" .= display pcVersionRange
|
||||
, "tests" .= pcTests
|
||||
, "haddocks" .= pcHaddocks
|
||||
, "build-benchmarks" .= pcBuildBenchmarks
|
||||
, "flags" .= Map.mapKeysWith const unFlagName pcFlagOverrides
|
||||
, "library-profiling" .= pcEnableLibProfile
|
||||
]
|
||||
where
|
||||
addMaintainer = maybe id (\m -> (("maintainer" .= m):)) pcMaintainer
|
||||
instance FromJSON PackageConstraints where
|
||||
parseJSON = withObject "PackageConstraints" $ \o -> do
|
||||
pcVersionRange <- (o .: "version-range")
|
||||
>>= either (fail . show) return . simpleParse
|
||||
pcTests <- o .: "tests"
|
||||
pcHaddocks <- o .: "haddocks"
|
||||
pcBuildBenchmarks <- o .: "build-benchmarks"
|
||||
pcFlagOverrides <- Map.mapKeysWith const mkFlagName <$> o .: "flags"
|
||||
pcMaintainer <- o .:? "maintainer"
|
||||
pcEnableLibProfile <- fmap (fromMaybe False) (o .:? "library-profiling")
|
||||
return PackageConstraints {..}
|
||||
|
||||
-- | The proposed plan from the requirements provided by contributors.
|
||||
--
|
||||
-- Checks the current directory for a build-constraints.yaml file and uses it
|
||||
-- if present. If not, downloads from Github.
|
||||
defaultBuildConstraints :: Manager -> IO BuildConstraints
|
||||
defaultBuildConstraints = loadBuildConstraints BCSDefault
|
||||
|
||||
data BuildConstraintsSource
|
||||
= BCSDefault
|
||||
| BCSFile FilePath
|
||||
| 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
|
||||
fp0 = "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 = do
|
||||
siCorePackages <- getCorePackages
|
||||
siCoreExecutables <- getCoreExecutables
|
||||
siGhcVersion <- getGhcVersion
|
||||
return SystemInfo {..}
|
||||
where
|
||||
-- FIXME consider not hard-coding the next two values
|
||||
siOS = Distribution.System.Linux
|
||||
siArch = Distribution.System.X86_64
|
||||
|
||||
data ConstraintFile = ConstraintFile
|
||||
{ cfPackageFlags :: Map PackageName (Map FlagName Bool)
|
||||
, cfSkippedTests :: Set PackageName
|
||||
, cfExpectedTestFailures :: Set PackageName
|
||||
, cfExpectedHaddockFailures :: Set PackageName
|
||||
, cfSkippedBenchmarks :: Set PackageName
|
||||
, cfPackages :: Map Maintainer (Vector Dependency)
|
||||
, cfGithubUsers :: Map Text (Set Text)
|
||||
, cfSkippedLibProfiling :: Set PackageName
|
||||
}
|
||||
|
||||
instance FromJSON ConstraintFile where
|
||||
parseJSON = withObject "ConstraintFile" $ \o -> do
|
||||
cfPackageFlags <- (goPackageMap . fmap goFlagMap) <$> o .: "package-flags"
|
||||
cfSkippedTests <- getPackages o "skipped-tests"
|
||||
cfExpectedTestFailures <- getPackages o "expected-test-failures"
|
||||
cfExpectedHaddockFailures <- getPackages o "expected-haddock-failures"
|
||||
cfSkippedBenchmarks <- getPackages o "skipped-benchmarks"
|
||||
cfSkippedLibProfiling <- getPackages o "skipped-profiling"
|
||||
cfPackages <- o .: "packages"
|
||||
>>= mapM (mapM toDep)
|
||||
. Map.mapKeysWith const Maintainer
|
||||
cfGithubUsers <- o .: "github-users"
|
||||
return ConstraintFile {..}
|
||||
where
|
||||
goFlagMap = Map.mapKeysWith const FlagName
|
||||
goPackageMap = Map.mapKeysWith const PackageName
|
||||
getPackages o name = (setFromList . map PackageName) <$> o .: name
|
||||
|
||||
toDep :: Monad m => Text -> m Dependency
|
||||
toDep = either (fail . show) return . simpleParse
|
||||
|
||||
toBC :: ConstraintFile -> IO BuildConstraints
|
||||
toBC ConstraintFile {..} = do
|
||||
bcSystemInfo <- getSystemInfo
|
||||
return BuildConstraints {..}
|
||||
where
|
||||
combine (maintainer, range1) (_, range2) =
|
||||
(maintainer, intersectVersionRanges range1 range2)
|
||||
revmap = unionsWith combine $ ($ []) $ execWriter
|
||||
$ forM_ (mapToList cfPackages)
|
||||
$ \(maintainer, deps) -> forM_ deps
|
||||
$ \(Dependency name range) ->
|
||||
tell (singletonMap name (maintainer, range):)
|
||||
|
||||
bcPackages = Map.keysSet revmap
|
||||
|
||||
bcPackageConstraints name =
|
||||
PackageConstraints {..}
|
||||
where
|
||||
mpair = lookup name revmap
|
||||
pcMaintainer = fmap fst mpair
|
||||
pcVersionRange = maybe anyVersion snd mpair
|
||||
pcEnableLibProfile = not (name `member` cfSkippedLibProfiling)
|
||||
pcTests
|
||||
| name `member` cfSkippedTests = Don'tBuild
|
||||
| name `member` cfExpectedTestFailures = ExpectFailure
|
||||
| otherwise = ExpectSuccess
|
||||
pcBuildBenchmarks = name `notMember` cfSkippedBenchmarks
|
||||
pcHaddocks
|
||||
| name `member` cfExpectedHaddockFailures = ExpectFailure
|
||||
|
||||
| otherwise = ExpectSuccess
|
||||
pcFlagOverrides = fromMaybe mempty $ lookup name cfPackageFlags
|
||||
|
||||
bcGithubUsers = cfGithubUsers
|
||||
@ -1,214 +0,0 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
-- | Representation of a concrete build plan, and how to generate a new one
|
||||
-- based on constraints.
|
||||
module Stackage.BuildPlan
|
||||
( BuildPlan (..)
|
||||
, PackagePlan (..)
|
||||
, newBuildPlan
|
||||
, makeToolMap
|
||||
, getLatestAllowedPlans
|
||||
) where
|
||||
|
||||
import Control.Monad.State.Strict (execState, get, put)
|
||||
import Data.Aeson
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Set as Set
|
||||
import qualified Distribution.Compiler
|
||||
import Distribution.PackageDescription
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.GithubPings
|
||||
import Stackage.PackageDescription
|
||||
import Stackage.PackageIndex
|
||||
import Stackage.Prelude
|
||||
|
||||
data BuildPlan = BuildPlan
|
||||
{ bpSystemInfo :: SystemInfo
|
||||
, bpTools :: Vector (PackageName, Version)
|
||||
, bpPackages :: Map PackageName PackagePlan
|
||||
, bpGithubUsers :: Map Text (Set Text)
|
||||
}
|
||||
deriving (Show, Eq)
|
||||
|
||||
instance ToJSON BuildPlan where
|
||||
toJSON BuildPlan {..} = object
|
||||
[ "system-info" .= bpSystemInfo
|
||||
, "tools" .= map goTool bpTools
|
||||
, "packages" .= Map.mapKeysWith const unPackageName bpPackages
|
||||
, "github-users" .= bpGithubUsers
|
||||
]
|
||||
where
|
||||
goTool (k, v) = object
|
||||
[ "name" .= display k
|
||||
, "version" .= display v
|
||||
]
|
||||
instance FromJSON BuildPlan where
|
||||
parseJSON = withObject "BuildPlan" $ \o -> do
|
||||
bpSystemInfo <- o .: "system-info"
|
||||
bpTools <- (o .: "tools") >>= mapM goTool
|
||||
bpPackages <- Map.mapKeysWith const mkPackageName <$> (o .: "packages")
|
||||
bpGithubUsers <- o .:? "github-users" .!= mempty
|
||||
return BuildPlan {..}
|
||||
where
|
||||
goTool = withObject "Tool" $ \o -> (,)
|
||||
<$> ((o .: "name") >>=
|
||||
either (fail . show) return . simpleParse . asText)
|
||||
<*> ((o .: "version") >>=
|
||||
either (fail . show) return . simpleParse . asText)
|
||||
|
||||
data PackagePlan = PackagePlan
|
||||
{ ppVersion :: Version
|
||||
, ppGithubPings :: Set Text
|
||||
, ppUsers :: Set PackageName
|
||||
, ppConstraints :: PackageConstraints
|
||||
, ppDesc :: SimpleDesc
|
||||
}
|
||||
deriving (Show, Eq)
|
||||
|
||||
instance ToJSON PackagePlan where
|
||||
toJSON PackagePlan {..} = object
|
||||
[ "version" .= asText (display ppVersion)
|
||||
, "github-pings" .= ppGithubPings
|
||||
, "users" .= map unPackageName (unpack ppUsers)
|
||||
, "constraints" .= ppConstraints
|
||||
, "description" .= ppDesc
|
||||
]
|
||||
instance FromJSON PackagePlan where
|
||||
parseJSON = withObject "PackageBuild" $ \o -> do
|
||||
ppVersion <- o .: "version"
|
||||
>>= either (fail . show) return
|
||||
. simpleParse . asText
|
||||
ppGithubPings <- o .:? "github-pings" .!= mempty
|
||||
ppUsers <- Set.map PackageName <$> (o .:? "users" .!= mempty)
|
||||
ppConstraints <- o .: "constraints"
|
||||
ppDesc <- o .: "description"
|
||||
return PackagePlan {..}
|
||||
|
||||
-- | Make a build plan given these package set and build constraints.
|
||||
newBuildPlan :: MonadIO m => Map PackageName PackagePlan -> BuildConstraints -> m BuildPlan
|
||||
newBuildPlan packagesOrig bc@BuildConstraints {..} = liftIO $ do
|
||||
let toolMap = makeToolMap packagesOrig
|
||||
packages = populateUsers $ removeUnincluded bc toolMap packagesOrig
|
||||
toolNames :: [ExeName]
|
||||
toolNames = concatMap (Map.keys . sdTools . ppDesc) packages
|
||||
tools <- topologicalSortTools toolMap $ mapFromList $ do
|
||||
exeName <- toolNames
|
||||
guard $ exeName `notMember` siCoreExecutables
|
||||
packageName <- maybe mempty setToList $ lookup exeName toolMap
|
||||
packagePlan <- maybeToList $ lookup packageName packagesOrig
|
||||
return (packageName, packagePlan)
|
||||
-- FIXME topologically sort packages? maybe just leave that to the build phase
|
||||
return BuildPlan
|
||||
{ bpSystemInfo = bcSystemInfo
|
||||
, bpTools = tools
|
||||
, bpPackages = packages
|
||||
, bpGithubUsers = bcGithubUsers
|
||||
}
|
||||
where
|
||||
SystemInfo {..} = bcSystemInfo
|
||||
|
||||
makeToolMap :: Map PackageName PackagePlan
|
||||
-> Map ExeName (Set PackageName)
|
||||
makeToolMap =
|
||||
unionsWith (++) . map go . mapToList
|
||||
where
|
||||
go (packageName, pp) =
|
||||
foldMap go' $ sdProvidedExes $ ppDesc pp
|
||||
where
|
||||
go' exeName = singletonMap exeName (singletonSet packageName)
|
||||
|
||||
topologicalSortTools :: MonadThrow m
|
||||
=> Map ExeName (Set PackageName)
|
||||
-> Map PackageName PackagePlan
|
||||
-> m (Vector (PackageName, Version))
|
||||
topologicalSortTools toolMap = topologicalSort
|
||||
ppVersion
|
||||
(concatMap (fromMaybe mempty . flip lookup toolMap) . Map.keys . sdTools . ppDesc)
|
||||
|
||||
-- | Include only packages which are dependencies of the required packages and
|
||||
-- their build tools.
|
||||
removeUnincluded :: BuildConstraints
|
||||
-> Map ExeName (Set PackageName)
|
||||
-> Map PackageName PackagePlan
|
||||
-> Map PackageName PackagePlan
|
||||
removeUnincluded BuildConstraints {..} toolMap orig =
|
||||
mapFromList $ filter (\(x, _) -> x `member` included) $ mapToList orig
|
||||
where
|
||||
SystemInfo {..} = bcSystemInfo
|
||||
|
||||
included :: Set PackageName
|
||||
included = flip execState mempty $ mapM_ add bcPackages
|
||||
|
||||
add name = do
|
||||
inc <- get
|
||||
when (name `notMember` inc) $ do
|
||||
put $ insertSet name inc
|
||||
case lookup name orig of
|
||||
Nothing -> return ()
|
||||
Just pb -> do
|
||||
mapM_ add $ Map.keys $ sdPackages $ ppDesc pb
|
||||
forM_ (Map.keys $ sdTools $ ppDesc pb) $
|
||||
\exeName -> when (exeName `notMember` siCoreExecutables)
|
||||
$ mapM_ add $ fromMaybe mempty $ lookup exeName toolMap
|
||||
|
||||
populateUsers :: Map PackageName PackagePlan
|
||||
-> Map PackageName PackagePlan
|
||||
populateUsers orig =
|
||||
mapWithKey go orig
|
||||
where
|
||||
go name pb = pb { ppUsers = foldMap (go2 name) (mapToList orig) }
|
||||
|
||||
go2 dep (user, pb)
|
||||
| dep `member` sdPackages (ppDesc pb) = singletonSet user
|
||||
| otherwise = mempty
|
||||
|
||||
-- | Check whether the given package/version combo meets the constraints
|
||||
-- currently in place.
|
||||
isAllowed :: BuildConstraints
|
||||
-> PackageName -> Version -> Bool
|
||||
isAllowed bc = \name version ->
|
||||
case lookup name $ siCorePackages $ bcSystemInfo bc of
|
||||
Just _ -> False -- never reinstall a core package
|
||||
Nothing -> withinRange version $ pcVersionRange $ bcPackageConstraints bc name
|
||||
|
||||
mkPackagePlan :: MonadThrow m
|
||||
=> BuildConstraints
|
||||
-> GenericPackageDescription
|
||||
-> m PackagePlan
|
||||
mkPackagePlan bc gpd = do
|
||||
ppDesc <- toSimpleDesc CheckCond {..} gpd
|
||||
return PackagePlan {..}
|
||||
where
|
||||
PackageIdentifier name ppVersion = package $ packageDescription gpd
|
||||
ppGithubPings = getGithubPings bc gpd
|
||||
ppConstraints = bcPackageConstraints bc name
|
||||
ppUsers = mempty -- must be filled in later
|
||||
|
||||
ccPackageName = name
|
||||
ccOS = siOS
|
||||
ccArch = siArch
|
||||
ccCompilerFlavor = Distribution.Compiler.GHC
|
||||
ccCompilerVersion = siGhcVersion
|
||||
ccFlags = flags
|
||||
ccIncludeTests = pcTests ppConstraints /= Don'tBuild
|
||||
ccIncludeBenchmarks = pcBuildBenchmarks ppConstraints
|
||||
|
||||
SystemInfo {..} = bcSystemInfo bc
|
||||
|
||||
overrides = pcFlagOverrides ppConstraints
|
||||
getFlag MkFlag {..} =
|
||||
(flagName, fromMaybe flagDefault $ lookup flagName overrides)
|
||||
flags = mapFromList $ map getFlag $ genPackageFlags gpd
|
||||
|
||||
getLatestAllowedPlans :: MonadIO m => BuildConstraints -> m (Map PackageName PackagePlan)
|
||||
getLatestAllowedPlans bc =
|
||||
getLatestDescriptions
|
||||
(isAllowed bc)
|
||||
(mkPackagePlan bc)
|
||||
@ -1,162 +0,0 @@
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
-- | Confirm that a build plan has a consistent set of dependencies.
|
||||
module Stackage.CheckBuildPlan
|
||||
( checkBuildPlan
|
||||
, BadBuildPlan
|
||||
) where
|
||||
|
||||
import Control.Monad.Writer.Strict (Writer, execWriter, tell)
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.BuildPlan
|
||||
import Stackage.PackageDescription
|
||||
import Stackage.Prelude
|
||||
|
||||
-- | Check the build plan for missing deps, wrong versions, etc.
|
||||
checkBuildPlan :: (MonadThrow m) => BuildPlan -> m ()
|
||||
checkBuildPlan BuildPlan {..}
|
||||
| null errs' = return ()
|
||||
| otherwise = throwM errs
|
||||
where
|
||||
allPackages = map (,mempty) (siCorePackages bpSystemInfo) ++
|
||||
map (ppVersion &&& M.keys . M.filter libAndExe . sdPackages . ppDesc) bpPackages
|
||||
errs@(BadBuildPlan errs') =
|
||||
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
|
||||
|
||||
-- | 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)
|
||||
-> Writer BadBuildPlan ()
|
||||
checkDeps allPackages (user, pb) =
|
||||
mapM_ go $ mapToList $ sdPackages $ ppDesc pb
|
||||
where
|
||||
go (dep, diRange -> range) =
|
||||
case lookup dep allPackages of
|
||||
Nothing -> tell $ BadBuildPlan $ singletonMap (dep, Nothing) errMap
|
||||
Just (version,deps)
|
||||
| version `withinRange` range ->
|
||||
occursCheck allPackages
|
||||
(\d v ->
|
||||
tell $ BadBuildPlan $ singletonMap
|
||||
(d,v)
|
||||
errMap)
|
||||
dep
|
||||
deps
|
||||
[]
|
||||
| otherwise -> tell $ BadBuildPlan $ singletonMap
|
||||
(dep, Just version)
|
||||
errMap
|
||||
where
|
||||
errMap = singletonMap pu range
|
||||
pu = PkgUser
|
||||
{ puName = user
|
||||
, puVersion = ppVersion pb
|
||||
, puMaintainer = pcMaintainer $ ppConstraints 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
|
||||
{ puName :: PackageName
|
||||
, puVersion :: Version
|
||||
, puMaintainer :: Maybe Maintainer
|
||||
, puGithubPings :: Set Text
|
||||
}
|
||||
deriving (Eq, Ord)
|
||||
|
||||
pkgUserShow1 :: PkgUser -> Text
|
||||
pkgUserShow1 PkgUser {..} = concat
|
||||
[ display puName
|
||||
, "-"
|
||||
, display puVersion
|
||||
]
|
||||
|
||||
pkgUserShow2 :: PkgUser -> Text
|
||||
pkgUserShow2 PkgUser {..} = unwords
|
||||
$ (maybe "No maintainer" unMaintainer puMaintainer ++ ".")
|
||||
: map (cons '@') (setToList puGithubPings)
|
||||
|
||||
newtype BadBuildPlan =
|
||||
BadBuildPlan (Map (PackageName, Maybe Version) (Map PkgUser VersionRange))
|
||||
deriving Typeable
|
||||
instance Exception BadBuildPlan
|
||||
instance Show BadBuildPlan where
|
||||
show (BadBuildPlan errs) =
|
||||
unpack $ concatMap go $ mapToList errs
|
||||
where
|
||||
go ((dep, mdepVer), users) = unlines
|
||||
$ ""
|
||||
: showDepVer dep mdepVer
|
||||
: map showUser (mapToList users)
|
||||
|
||||
showDepVer :: PackageName -> Maybe Version -> Text
|
||||
showDepVer dep Nothing = display dep ++ " (not present) depended on by:"
|
||||
showDepVer dep (Just version) = concat
|
||||
[ display dep
|
||||
, "-"
|
||||
, display version
|
||||
, " depended on by:"
|
||||
]
|
||||
|
||||
showUser :: (PkgUser, VersionRange) -> Text
|
||||
showUser (pu, range) = concat
|
||||
[ "- "
|
||||
, pkgUserShow1 pu
|
||||
, " ("
|
||||
-- add a space after < to avoid confusing Markdown processors (like
|
||||
-- Github's issue tracker)
|
||||
, T.replace "<" "< " $ display range
|
||||
, "). "
|
||||
, pkgUserShow2 pu
|
||||
]
|
||||
|
||||
instance Monoid BadBuildPlan where
|
||||
mempty = BadBuildPlan mempty
|
||||
mappend (BadBuildPlan x) (BadBuildPlan y) =
|
||||
BadBuildPlan $ unionWith (unionWith intersectVersionRanges) x y
|
||||
@ -1,293 +0,0 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Stackage.CompleteBuild
|
||||
( BuildType (..)
|
||||
, BumpType (..)
|
||||
, BuildFlags (..)
|
||||
, completeBuild
|
||||
, justCheck
|
||||
, justUploadNightly
|
||||
) where
|
||||
|
||||
import Control.Concurrent (threadDelay)
|
||||
import Control.Concurrent.Async (withAsync)
|
||||
import Data.Default.Class (def)
|
||||
import Data.Semigroup (Max (..), Option (..))
|
||||
import Data.Text.Read (decimal)
|
||||
import Data.Time
|
||||
import Data.Yaml (decodeFileEither, encodeFile)
|
||||
import Network.HTTP.Client
|
||||
import Network.HTTP.Client.TLS (tlsManagerSettings)
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.BuildPlan
|
||||
import Stackage.CheckBuildPlan
|
||||
import Stackage.PerformBuild
|
||||
import Stackage.Prelude
|
||||
import Stackage.ServerBundle
|
||||
import Stackage.UpdateBuildPlan
|
||||
import Stackage.Upload
|
||||
import System.Environment (lookupEnv)
|
||||
import System.IO (BufferMode (LineBuffering), hSetBuffering)
|
||||
|
||||
-- | Flags passed in from the command line.
|
||||
data BuildFlags = BuildFlags
|
||||
{ bfEnableTests :: !Bool
|
||||
, bfDoUpload :: !Bool
|
||||
, bfEnableLibProfile :: !Bool
|
||||
, bfVerbose :: !Bool
|
||||
, bfSkipCheck :: !Bool
|
||||
} deriving (Show)
|
||||
|
||||
data BuildType = Nightly | LTS BumpType
|
||||
deriving (Show, Read, Eq, Ord)
|
||||
|
||||
data BumpType = Major | Minor
|
||||
deriving (Show, Read, Eq, Ord)
|
||||
|
||||
data Settings = Settings
|
||||
{ plan :: BuildPlan
|
||||
, planFile :: FilePath
|
||||
, buildDir :: FilePath
|
||||
, logDir :: FilePath
|
||||
, title :: Text -> Text -- ^ GHC version -> title
|
||||
, slug :: Text
|
||||
, setArgs :: Text -> UploadBundle -> UploadBundle
|
||||
, 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/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 ()
|
||||
, distroName = "Stackage"
|
||||
}
|
||||
where
|
||||
slug' = "nightly-" ++ day
|
||||
|
||||
getSettings :: Manager -> BuildType -> IO Settings
|
||||
getSettings man Nightly = do
|
||||
day <- tshow . utctDay <$> getCurrentTime
|
||||
bc <- defaultBuildConstraints man
|
||||
pkgs <- getLatestAllowedPlans bc
|
||||
plan' <- newBuildPlan pkgs bc
|
||||
return $ nightlySettings day plan'
|
||||
getSettings man (LTS bumpType) = do
|
||||
Option mlts <- fmap (fmap getMax) $ runResourceT
|
||||
$ sourceDirectory "."
|
||||
$$ foldMapC (Option . fmap Max . parseLTSVer . filename)
|
||||
|
||||
(new, plan') <- case bumpType of
|
||||
Major -> do
|
||||
let new =
|
||||
case mlts of
|
||||
Nothing -> LTSVer 0 0
|
||||
Just (LTSVer x _) -> LTSVer (x + 1) 0
|
||||
bc <- defaultBuildConstraints man
|
||||
pkgs <- getLatestAllowedPlans bc
|
||||
plan' <- newBuildPlan pkgs bc
|
||||
return (new, plan')
|
||||
Minor -> do
|
||||
old <- maybe (error "No LTS plans found in current directory") return mlts
|
||||
oldplan <- decodeFileEither (fpToString $ renderLTSVer old)
|
||||
>>= either throwM return
|
||||
let new = incrLTSVer old
|
||||
let bc = updateBuildConstraints oldplan
|
||||
pkgs <- getLatestAllowedPlans bc
|
||||
plan' <- newBuildPlan pkgs bc
|
||||
return (new, plan')
|
||||
|
||||
let newfile = renderLTSVer new
|
||||
|
||||
return Settings
|
||||
{ planFile = newfile
|
||||
, buildDir = fpFromText $ "builds/stackage-lts-" ++ tshow new
|
||||
, logDir = fpFromText $ "logs/stackage-lts-" ++ tshow new
|
||||
, title = \ghcVer -> concat
|
||||
[ "LTS Haskell "
|
||||
, tshow new
|
||||
, ", GHC "
|
||||
, ghcVer
|
||||
]
|
||||
, slug = "lts-" ++ tshow new
|
||||
, setArgs = \_ ub -> ub { ubLTS = Just $ tshow new }
|
||||
, plan = plan'
|
||||
, postBuild = do
|
||||
let git args = withCheckedProcess
|
||||
(proc "git" args) $ \ClosedStream Inherited Inherited ->
|
||||
return ()
|
||||
putStrLn "Committing new LTS file to Git"
|
||||
git ["add", fpToString newfile]
|
||||
git ["commit", "-m", "Added new LTS release: " ++ show new]
|
||||
putStrLn "Pushing to Git repository"
|
||||
git ["push"]
|
||||
, distroName = "LTSHaskell"
|
||||
}
|
||||
|
||||
data LTSVer = LTSVer !Int !Int
|
||||
deriving (Eq, Ord)
|
||||
instance Show LTSVer where
|
||||
show (LTSVer x y) = concat [show x, ".", show y]
|
||||
incrLTSVer :: LTSVer -> LTSVer
|
||||
incrLTSVer (LTSVer x y) = LTSVer x (y + 1)
|
||||
|
||||
parseLTSVer :: FilePath -> Maybe LTSVer
|
||||
parseLTSVer fp = do
|
||||
w <- stripPrefix "lts-" $ fpToText fp
|
||||
x <- stripSuffix ".yaml" w
|
||||
Right (major, y) <- Just $ decimal x
|
||||
z <- stripPrefix "." y
|
||||
Right (minor, "") <- Just $ decimal z
|
||||
return $ LTSVer major minor
|
||||
renderLTSVer :: LTSVer -> FilePath
|
||||
renderLTSVer lts = fpFromText $ concat
|
||||
[ "lts-"
|
||||
, tshow lts
|
||||
, ".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.
|
||||
--
|
||||
-- Since 0.3.1
|
||||
justCheck :: IO ()
|
||||
justCheck = stillAlive $ withManager tlsManagerSettings $ \man -> do
|
||||
putStrLn "Loading build constraints"
|
||||
bc <- defaultBuildConstraints man
|
||||
|
||||
putStrLn "Creating build plan"
|
||||
plans <- getLatestAllowedPlans bc
|
||||
plan <- newBuildPlan plans bc
|
||||
|
||||
putStrLn $ "Writing build plan to check-plan.yaml"
|
||||
encodeFile "check-plan.yaml" plan
|
||||
|
||||
putStrLn "Checking plan"
|
||||
checkBuildPlan plan
|
||||
|
||||
putStrLn "Plan seems valid!"
|
||||
|
||||
getPerformBuild :: BuildFlags -> Settings -> PerformBuild
|
||||
getPerformBuild buildFlags Settings {..} = PerformBuild
|
||||
{ pbPlan = plan
|
||||
, pbInstallDest = buildDir
|
||||
, pbLogDir = logDir
|
||||
, pbLog = hPut stdout
|
||||
, pbJobs = 8
|
||||
, pbGlobalInstall = False
|
||||
, pbEnableTests = bfEnableTests buildFlags
|
||||
, pbEnableLibProfiling = bfEnableLibProfile 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
|
||||
|
||||
putStrLn $ "Loading settings for: " ++ tshow buildType
|
||||
settings@Settings {..} <- getSettings man buildType
|
||||
|
||||
putStrLn $ "Writing build plan to: " ++ fpToText planFile
|
||||
encodeFile (fpToString planFile) plan
|
||||
|
||||
if bfSkipCheck buildFlags
|
||||
then putStrLn "Skipping build plan check"
|
||||
else do
|
||||
putStrLn "Checking build plan"
|
||||
checkBuildPlan plan
|
||||
|
||||
putStrLn "Performing build"
|
||||
performBuild (getPerformBuild buildFlags settings) >>= 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"
|
||||
|
||||
mtoken <- lookupEnv "STACKAGE_AUTH_TOKEN"
|
||||
token <-
|
||||
case mtoken of
|
||||
Nothing -> decodeUtf8 <$> readFile "/auth-token"
|
||||
Just token -> return $ pack token
|
||||
|
||||
now <- epochTime
|
||||
let ghcVer = display $ siGhcVersion $ bpSystemInfo plan
|
||||
(ident, mloc) <- flip uploadBundle man $ setArgs ghcVer def
|
||||
{ ubContents = serverBundle now (title ghcVer) slug plan
|
||||
, ubAuthToken = token
|
||||
}
|
||||
putStrLn $ "New ident: " ++ unSnapshotIdent ident
|
||||
forM_ mloc $ \loc ->
|
||||
putStrLn $ "Track progress at: " ++ loc
|
||||
|
||||
postBuild `catchAny` print
|
||||
|
||||
putStrLn "Uploading docs to Stackage Server"
|
||||
res1 <- uploadDocs UploadDocs
|
||||
{ udServer = def
|
||||
, udAuthToken = token
|
||||
, udDocs = pbDocDir pb
|
||||
, udSnapshot = ident
|
||||
} man
|
||||
putStrLn $ "Doc upload response: " ++ tshow res1
|
||||
|
||||
ecreds <- tryIO $ readFile "/hackage-creds"
|
||||
case map encodeUtf8 $ words $ decodeUtf8 $ either (const "") id ecreds of
|
||||
[username, password] -> do
|
||||
putStrLn "Uploading as Hackage distro"
|
||||
res2 <- uploadHackageDistroNamed distroName plan username password man
|
||||
putStrLn $ "Distro upload response: " ++ tshow res2
|
||||
_ -> putStrLn "No creds found, skipping Hackage distro upload"
|
||||
|
||||
putStrLn "Uploading doc map"
|
||||
uploadDocMap UploadDocMap
|
||||
{ udmServer = def
|
||||
, udmAuthToken = token
|
||||
, udmSnapshot = ident
|
||||
, udmDocDir = pbDocDir pb
|
||||
, udmPlan = plan
|
||||
} man >>= print
|
||||
where
|
||||
pb = getPerformBuild (error "finallyUpload.buildFlags") settings
|
||||
@ -1,53 +0,0 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Stackage.CorePackages
|
||||
( getCorePackages
|
||||
, getCoreExecutables
|
||||
, getGhcVersion
|
||||
) where
|
||||
|
||||
import qualified Data.Text as T
|
||||
import Filesystem (listDirectory)
|
||||
import Stackage.Prelude
|
||||
import System.Directory (findExecutable)
|
||||
|
||||
-- | Get a @Map@ of all of the core packages. Core packages are defined as
|
||||
-- packages which ship with GHC itself.
|
||||
--
|
||||
-- Precondition: GHC global package database has only core packages, and GHC
|
||||
-- ships with just a single version of each packages.
|
||||
getCorePackages :: IO (Map PackageName Version)
|
||||
getCorePackages =
|
||||
withCheckedProcess cp $ \ClosedStream src Inherited ->
|
||||
src $$ decodeUtf8C =$ linesUnboundedC =$ foldMapMC parsePackage
|
||||
where
|
||||
cp = proc "ghc-pkg" ["--no-user-package-conf", "list"]
|
||||
parsePackage t
|
||||
| ":" `isInfixOf` t = return mempty
|
||||
| Just p <- stripSuffix "-" p' = singletonMap
|
||||
<$> simpleParse p
|
||||
<*> simpleParse v
|
||||
| otherwise = return mempty
|
||||
where
|
||||
(p', v) = T.breakOnEnd "-" $ dropParens $ T.strip t
|
||||
|
||||
dropParens s
|
||||
| length s > 2 && headEx s == '(' && lastEx s == ')' =
|
||||
initEx $ tailEx s
|
||||
| otherwise = s
|
||||
|
||||
-- | A list of executables that are shipped with GHC.
|
||||
getCoreExecutables :: IO (Set ExeName)
|
||||
getCoreExecutables = do
|
||||
mfp <- findExecutable "ghc"
|
||||
dir <-
|
||||
case mfp of
|
||||
Nothing -> error "No ghc executable found on PATH"
|
||||
Just fp -> return $ directory $ fpFromString fp
|
||||
(setFromList . map (ExeName . fpToText . filename)) <$> listDirectory dir
|
||||
|
||||
getGhcVersion :: IO Version
|
||||
getGhcVersion = do
|
||||
withCheckedProcess (proc "ghc" ["--numeric-version"]) $
|
||||
\ClosedStream src Inherited ->
|
||||
(src $$ decodeUtf8C =$ foldC) >>= simpleParse
|
||||
@ -1,36 +0,0 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
module Stackage.GithubPings
|
||||
( getGithubPings
|
||||
) where
|
||||
|
||||
import Distribution.PackageDescription
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.Prelude
|
||||
|
||||
-- | Determine accounts to be pinged on Github based on various metadata in the
|
||||
-- package description.
|
||||
getGithubPings :: BuildConstraints -- ^ for mapping to pingees
|
||||
-> GenericPackageDescription -> Set Text
|
||||
getGithubPings bc gpd =
|
||||
foldMap (\(pack -> name) -> fromMaybe (singletonSet name) (lookup name (bcGithubUsers bc))) $
|
||||
goHomepage (homepage $ packageDescription gpd) ++
|
||||
concatMap goRepo (sourceRepos $ packageDescription gpd)
|
||||
where
|
||||
goHomepage t = do
|
||||
prefix <-
|
||||
[ "http://github.com/"
|
||||
, "https://github.com/"
|
||||
, "git://github.com/"
|
||||
, "git@github.com:"
|
||||
]
|
||||
t' <- maybeToList $ stripPrefix prefix t
|
||||
let t'' = takeWhile (/= '/') t'
|
||||
guard $ not $ null t''
|
||||
return t''
|
||||
|
||||
goRepo sr =
|
||||
case (repoType sr, repoLocation sr) of
|
||||
(Just Git, Just s) -> goHomepage s
|
||||
_ -> []
|
||||
@ -1,200 +0,0 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE DeriveFoldable #-}
|
||||
{-# LANGUAGE DeriveFunctor #-}
|
||||
{-# LANGUAGE DeriveTraversable #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
-- | Manipulate @GenericPackageDescription@ from Cabal into something more
|
||||
-- useful for us.
|
||||
module Stackage.PackageDescription
|
||||
( SimpleDesc (..)
|
||||
, toSimpleDesc
|
||||
, CheckCond (..)
|
||||
, Component (..)
|
||||
, DepInfo (..)
|
||||
) where
|
||||
|
||||
import Control.Monad.Writer.Strict (MonadWriter, execWriterT,
|
||||
tell)
|
||||
import Data.Aeson
|
||||
import qualified Data.Map as Map
|
||||
import Distribution.Compiler (CompilerFlavor)
|
||||
import Distribution.Package (Dependency (..))
|
||||
import Distribution.PackageDescription
|
||||
import Distribution.System (Arch, OS)
|
||||
import Stackage.Prelude
|
||||
|
||||
data Component = CompLibrary
|
||||
| CompExecutable
|
||||
| CompTestSuite
|
||||
| CompBenchmark
|
||||
deriving (Show, Read, Eq, Ord, Enum, Bounded)
|
||||
|
||||
compToText :: Component -> Text
|
||||
compToText CompLibrary = "library"
|
||||
compToText CompExecutable = "executable"
|
||||
compToText CompTestSuite = "test-suite"
|
||||
compToText CompBenchmark = "benchmark"
|
||||
|
||||
instance ToJSON Component where
|
||||
toJSON = toJSON . compToText
|
||||
instance FromJSON Component where
|
||||
parseJSON = withText "Component" $ \t -> maybe
|
||||
(fail $ "Invalid component: " ++ unpack t)
|
||||
return
|
||||
(lookup t comps)
|
||||
where
|
||||
comps = asHashMap $ mapFromList $ map (compToText &&& id) [minBound..maxBound]
|
||||
|
||||
data DepInfo = DepInfo
|
||||
{ diComponents :: Set Component
|
||||
, diRange :: VersionRange
|
||||
}
|
||||
deriving (Show, Eq)
|
||||
|
||||
instance Semigroup DepInfo where
|
||||
DepInfo a x <> DepInfo b y = DepInfo
|
||||
(a <> b)
|
||||
(intersectVersionRanges x y)
|
||||
instance ToJSON DepInfo where
|
||||
toJSON DepInfo {..} = object
|
||||
[ "components" .= diComponents
|
||||
, "range" .= display diRange
|
||||
]
|
||||
instance FromJSON DepInfo where
|
||||
parseJSON = withObject "DepInfo" $ \o -> do
|
||||
diComponents <- o .: "components"
|
||||
diRange <- o .: "range" >>= either (fail . show) return . simpleParse
|
||||
return DepInfo {..}
|
||||
|
||||
-- | A simplified package description that tracks:
|
||||
--
|
||||
-- * Package dependencies
|
||||
--
|
||||
-- * Build tool dependencies
|
||||
--
|
||||
-- * Provided executables
|
||||
--
|
||||
-- It has fully resolved all conditionals
|
||||
data SimpleDesc = SimpleDesc
|
||||
{ sdPackages :: Map PackageName DepInfo
|
||||
, sdTools :: Map ExeName DepInfo
|
||||
, sdProvidedExes :: Set ExeName
|
||||
, sdModules :: Set Text
|
||||
-- ^ modules exported by the library
|
||||
}
|
||||
deriving (Show, Eq)
|
||||
instance Monoid SimpleDesc where
|
||||
mempty = SimpleDesc mempty mempty mempty mempty
|
||||
mappend (SimpleDesc a b c d) (SimpleDesc w x y z) = SimpleDesc
|
||||
(unionWith (<>) a w)
|
||||
(unionWith (<>) b x)
|
||||
(c ++ y)
|
||||
(d ++ z)
|
||||
instance ToJSON SimpleDesc where
|
||||
toJSON SimpleDesc {..} = object
|
||||
[ "packages" .= Map.mapKeysWith const unPackageName sdPackages
|
||||
, "tools" .= Map.mapKeysWith const unExeName sdTools
|
||||
, "provided-exes" .= sdProvidedExes
|
||||
, "modules" .= sdModules
|
||||
]
|
||||
instance FromJSON SimpleDesc where
|
||||
parseJSON = withObject "SimpleDesc" $ \o -> do
|
||||
sdPackages <- Map.mapKeysWith const mkPackageName <$> (o .: "packages")
|
||||
sdTools <- Map.mapKeysWith const ExeName <$> (o .: "tools")
|
||||
sdProvidedExes <- o .: "provided-exes"
|
||||
sdModules <- o .: "modules"
|
||||
return SimpleDesc {..}
|
||||
|
||||
-- | Convert a 'GenericPackageDescription' into a 'SimpleDesc' by following the
|
||||
-- constraints in the provided 'CheckCond'.
|
||||
toSimpleDesc :: MonadThrow m
|
||||
=> CheckCond
|
||||
-> GenericPackageDescription
|
||||
-> m SimpleDesc
|
||||
toSimpleDesc cc gpd = execWriterT $ do
|
||||
forM_ (condLibrary gpd) $ tellTree cc CompLibrary libBuildInfo getModules
|
||||
forM_ (condExecutables gpd) $ tellTree cc CompExecutable buildInfo noModules . snd
|
||||
tell mempty { sdProvidedExes = setFromList
|
||||
$ map (fromString . fst)
|
||||
$ condExecutables gpd
|
||||
}
|
||||
when (ccIncludeTests cc) $ forM_ (condTestSuites gpd)
|
||||
$ tellTree cc CompTestSuite testBuildInfo noModules . snd
|
||||
when (ccIncludeBenchmarks cc) $ forM_ (condBenchmarks gpd)
|
||||
$ tellTree cc CompBenchmark benchmarkBuildInfo noModules . snd
|
||||
where
|
||||
noModules = const mempty
|
||||
getModules = setFromList . map display . exposedModules
|
||||
|
||||
-- | Convert a single CondTree to a 'SimpleDesc'.
|
||||
tellTree :: (MonadWriter SimpleDesc m, MonadThrow m)
|
||||
=> CheckCond
|
||||
-> Component
|
||||
-> (a -> BuildInfo)
|
||||
-> (a -> Set Text) -- ^ get module names
|
||||
-> CondTree ConfVar [Dependency] a
|
||||
-> m ()
|
||||
tellTree cc component getBI getModules =
|
||||
loop
|
||||
where
|
||||
loop (CondNode dat deps comps) = do
|
||||
tell mempty
|
||||
{ sdPackages = unionsWith (<>) $ flip map deps
|
||||
$ \(Dependency x y) -> singletonMap x DepInfo
|
||||
{ diComponents = singletonSet component
|
||||
, diRange = simplifyVersionRange y
|
||||
}
|
||||
, sdTools = unionsWith (<>) $ flip map (buildTools $ getBI dat)
|
||||
$ \(Dependency name range) -> singletonMap
|
||||
-- In practice, cabal files refer to the exe name, not the
|
||||
-- package name.
|
||||
(ExeName $ unPackageName name)
|
||||
DepInfo
|
||||
{ diComponents = singletonSet component
|
||||
, diRange = simplifyVersionRange range
|
||||
}
|
||||
, sdModules = getModules dat
|
||||
}
|
||||
forM_ comps $ \(cond, ontrue, onfalse) -> do
|
||||
b <- checkCond cc cond
|
||||
if b
|
||||
then loop ontrue
|
||||
else maybe (return ()) loop onfalse
|
||||
|
||||
-- | Resolve a condition to a boolean based on the provided 'CheckCond'.
|
||||
checkCond :: MonadThrow m => CheckCond -> Condition ConfVar -> m Bool
|
||||
checkCond CheckCond {..} cond0 =
|
||||
go cond0
|
||||
where
|
||||
go (Var (OS os)) = return $ os == ccOS
|
||||
go (Var (Arch arch)) = return $ arch == ccArch
|
||||
go (Var (Flag flag)) =
|
||||
case lookup flag ccFlags of
|
||||
Nothing -> throwM $ FlagNotDefined ccPackageName flag cond0
|
||||
Just b -> return b
|
||||
go (Var (Impl flavor range)) = return
|
||||
$ flavor == ccCompilerFlavor
|
||||
&& ccCompilerVersion `withinRange` range
|
||||
go (Lit b) = return b
|
||||
go (CNot c) = not `liftM` go c
|
||||
go (CAnd x y) = (&&) `liftM` go x `ap` go y
|
||||
go (COr x y) = (||) `liftM` go x `ap` go y
|
||||
|
||||
data CheckCondException = FlagNotDefined PackageName FlagName (Condition ConfVar)
|
||||
deriving (Show, Typeable)
|
||||
instance Exception CheckCondException
|
||||
|
||||
data CheckCond = CheckCond
|
||||
{ ccPackageName :: PackageName -- for debugging only
|
||||
, ccOS :: OS
|
||||
, ccArch :: Arch
|
||||
, ccFlags :: Map FlagName Bool
|
||||
, ccCompilerFlavor :: CompilerFlavor
|
||||
, ccCompilerVersion :: Version
|
||||
, ccIncludeTests :: Bool
|
||||
, ccIncludeBenchmarks :: Bool
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE ViewPatterns #-}
|
||||
-- | Dealing with the 00-index file and all its cabal files.
|
||||
module Stackage.PackageIndex
|
||||
( sourcePackageIndex
|
||||
, UnparsedCabalFile (..)
|
||||
, getLatestDescriptions
|
||||
) where
|
||||
|
||||
import qualified Codec.Archive.Tar as Tar
|
||||
import Data.Conduit.Lazy (MonadActive,
|
||||
lazyConsume)
|
||||
import qualified Data.Text as T
|
||||
import Distribution.PackageDescription (package,
|
||||
packageDescription)
|
||||
import Distribution.PackageDescription.Parse (ParseResult (..),
|
||||
parsePackageDescription)
|
||||
import Distribution.ParseUtils (PError)
|
||||
import Stackage.Prelude
|
||||
import System.Directory (getAppUserDataDirectory)
|
||||
|
||||
-- | Name of the 00-index.tar downloaded from Hackage.
|
||||
getPackageIndexPath :: MonadIO m => m FilePath
|
||||
getPackageIndexPath = liftIO $ do
|
||||
c <- getCabalRoot
|
||||
configLines <- runResourceT $ sourceFile (c </> "config")
|
||||
$$ decodeUtf8C
|
||||
=$ linesUnboundedC
|
||||
=$ concatMapC getRemoteCache
|
||||
=$ sinkList
|
||||
case configLines of
|
||||
[x] -> return $ x </> "hackage.haskell.org" </> "00-index.tar"
|
||||
[] -> error $ "No remote-repo-cache found in Cabal config file"
|
||||
_ -> error $ "Multiple remote-repo-cache entries found in Cabal config file"
|
||||
where
|
||||
getCabalRoot :: IO FilePath
|
||||
getCabalRoot = fpFromString <$> getAppUserDataDirectory "cabal"
|
||||
|
||||
getRemoteCache s = do
|
||||
("remote-repo-cache", stripPrefix ":" -> Just v) <- Just $ break (== ':') s
|
||||
Just $ fpFromText $ T.strip v
|
||||
|
||||
-- | A cabal file with name and version parsed from the filepath, and the
|
||||
-- package description itself ready to be parsed. It's left in unparsed form
|
||||
-- for efficiency.
|
||||
data UnparsedCabalFile = UnparsedCabalFile
|
||||
{ ucfName :: PackageName
|
||||
, ucfVersion :: Version
|
||||
, ucfParse :: forall m. MonadThrow m => m GenericPackageDescription
|
||||
}
|
||||
|
||||
-- | Stream all of the cabal files from the 00-index tar file.
|
||||
sourcePackageIndex :: (MonadThrow m, MonadResource m, MonadActive m, MonadBaseControl IO m)
|
||||
=> Producer m UnparsedCabalFile
|
||||
sourcePackageIndex = do
|
||||
fp <- getPackageIndexPath
|
||||
-- yay for the tar package. Use lazyConsume instead of readFile to get some
|
||||
-- kind of resource protection
|
||||
lbs <- lift $ fromChunks <$> lazyConsume (sourceFile fp)
|
||||
loop (Tar.read lbs)
|
||||
where
|
||||
loop (Tar.Next e es) = goE e >> loop es
|
||||
loop Tar.Done = return ()
|
||||
loop (Tar.Fail e) = throwM e
|
||||
|
||||
goE e
|
||||
| Just front <- stripSuffix ".cabal" $ pack $ Tar.entryPath e
|
||||
, Tar.NormalFile lbs _size <- Tar.entryContent e = do
|
||||
(name, version) <- parseNameVersion front
|
||||
yield UnparsedCabalFile
|
||||
{ ucfName = name
|
||||
, ucfVersion = version
|
||||
, ucfParse = goContent (Tar.entryPath e) name version lbs
|
||||
}
|
||||
| otherwise = return ()
|
||||
|
||||
goContent fp name version lbs =
|
||||
case parsePackageDescription $ unpack $ decodeUtf8 lbs of
|
||||
ParseFailed e -> throwM $ CabalParseException (fpFromString fp) e
|
||||
ParseOk _warnings gpd -> do
|
||||
let pd = packageDescription gpd
|
||||
PackageIdentifier name' version' = package pd
|
||||
when (name /= name' || version /= version') $
|
||||
throwM $ MismatchedNameVersion (fpFromString fp)
|
||||
name name' version version'
|
||||
return gpd
|
||||
|
||||
parseNameVersion t1 = do
|
||||
let (p', t2) = break (== '/') $ T.replace "\\" "/" t1
|
||||
p <- simpleParse p'
|
||||
t3 <- maybe (throwM $ InvalidCabalPath t1 "no slash") return
|
||||
$ stripPrefix "/" t2
|
||||
let (v', t4) = break (== '/') t3
|
||||
v <- simpleParse v'
|
||||
when (t4 /= cons '/' p') $ throwM $ InvalidCabalPath t1 $ "Expected at end: " ++ p'
|
||||
return (p, v)
|
||||
|
||||
data InvalidCabalPath = InvalidCabalPath Text Text
|
||||
deriving (Show, Typeable)
|
||||
instance Exception InvalidCabalPath
|
||||
|
||||
data CabalParseException = CabalParseException FilePath PError
|
||||
| MismatchedNameVersion FilePath PackageName PackageName Version Version
|
||||
deriving (Show, Typeable)
|
||||
instance Exception CabalParseException
|
||||
|
||||
-- | Get all of the latest descriptions for name/version pairs matching the
|
||||
-- given criterion.
|
||||
getLatestDescriptions :: MonadIO m
|
||||
=> (PackageName -> Version -> Bool)
|
||||
-> (GenericPackageDescription -> IO desc)
|
||||
-> m (Map PackageName desc)
|
||||
getLatestDescriptions f parseDesc = liftIO $ do
|
||||
m <- runResourceT $ sourcePackageIndex $$ filterC f' =$ foldlC add mempty
|
||||
forM m $ \ucf -> liftIO $ ucfParse ucf >>= parseDesc
|
||||
where
|
||||
f' ucf = f (ucfName ucf) (ucfVersion ucf)
|
||||
add m ucf =
|
||||
case lookup name m of
|
||||
Just ucf' | ucfVersion ucf < ucfVersion ucf' -> m
|
||||
_ -> insertMap name ucf m
|
||||
where
|
||||
name = ucfName ucf
|
||||
@ -1,450 +0,0 @@
|
||||
-- | Perform an actual build, generate a binary package database and a
|
||||
-- documentation directory in the process.
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Stackage.PerformBuild
|
||||
( performBuild
|
||||
, PerformBuild (..)
|
||||
, BuildException (..)
|
||||
, pbDocDir
|
||||
) where
|
||||
|
||||
import Control.Concurrent.Async (async)
|
||||
import Control.Concurrent.STM.TSem
|
||||
import Control.Monad.Writer.Strict (execWriter, tell)
|
||||
import qualified Data.Map as Map
|
||||
import Data.NonNull (fromNullable)
|
||||
import Filesystem (canonicalizePath, createTree,
|
||||
getWorkingDirectory, isDirectory,
|
||||
removeTree, rename)
|
||||
import Filesystem.Path (parent)
|
||||
import qualified Filesystem.Path as F
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.BuildPlan
|
||||
import Stackage.PackageDescription
|
||||
import Stackage.Prelude hiding (pi)
|
||||
import System.Directory (findExecutable)
|
||||
import System.Environment (getEnvironment)
|
||||
import System.IO (IOMode (WriteMode),
|
||||
withBinaryFile)
|
||||
import System.IO.Temp (withSystemTempDirectory)
|
||||
|
||||
data BuildException = BuildException (Map PackageName BuildFailure) [Text]
|
||||
deriving Typeable
|
||||
instance Exception BuildException
|
||||
instance Show BuildException where
|
||||
show (BuildException m warnings) =
|
||||
unlines $ map go (mapToList m) ++ map unpack warnings
|
||||
where
|
||||
go (PackageName name, bf) = concat
|
||||
[ name
|
||||
, ": "
|
||||
, show bf
|
||||
]
|
||||
|
||||
data BuildFailure = DependencyFailed PackageName
|
||||
| DependencyMissing PackageName
|
||||
| ToolMissing ExeName
|
||||
| NotImplemented
|
||||
| BuildFailureException SomeException
|
||||
deriving (Show, Typeable)
|
||||
instance Exception BuildFailure
|
||||
|
||||
data PerformBuild = PerformBuild
|
||||
{ pbPlan :: BuildPlan
|
||||
, pbInstallDest :: FilePath
|
||||
, pbLog :: ByteString -> IO ()
|
||||
, pbLogDir :: FilePath
|
||||
, pbJobs :: Int
|
||||
, pbGlobalInstall :: Bool
|
||||
-- ^ Register packages in the global database
|
||||
, pbEnableTests :: Bool
|
||||
, pbEnableLibProfiling :: Bool
|
||||
, pbVerbose :: Bool
|
||||
, pbAllowNewer :: Bool
|
||||
-- ^ Pass --allow-newer to cabal configure
|
||||
}
|
||||
|
||||
data PackageInfo = PackageInfo
|
||||
{ piPlan :: PackagePlan
|
||||
, piName :: PackageName
|
||||
, piResult :: TMVar Bool
|
||||
}
|
||||
|
||||
waitForDeps :: Map ExeName (Set PackageName)
|
||||
-> Map PackageName PackageInfo
|
||||
-> Set Component
|
||||
-> BuildPlan
|
||||
-> PackageInfo
|
||||
-> IO a
|
||||
-> IO a
|
||||
waitForDeps toolMap packageMap activeComps bp pi action = do
|
||||
atomically $ do
|
||||
mapM_ checkPackage $ Map.keys $ filterUnused $ sdPackages $ ppDesc $ piPlan pi
|
||||
forM_ (Map.keys $ filterUnused $ sdTools $ ppDesc $ piPlan pi) $ \exe -> do
|
||||
case lookup exe toolMap >>= fromNullable . map checkPackage . setToList of
|
||||
Nothing
|
||||
| isCoreExe exe -> return ()
|
||||
| otherwise -> throwSTM $ ToolMissing exe
|
||||
Just packages -> ofoldl1' (<|>) packages
|
||||
action
|
||||
where
|
||||
filterUnused :: Ord key => Map key DepInfo -> Map key DepInfo
|
||||
filterUnused =
|
||||
mapFromList . filter (go . snd) . mapToList
|
||||
where
|
||||
go = not . null . intersection activeComps . diComponents
|
||||
|
||||
checkPackage package | package == piName pi = return ()
|
||||
checkPackage package =
|
||||
case lookup package packageMap of
|
||||
Nothing
|
||||
| isCore package -> return ()
|
||||
| otherwise -> throwSTM $ DependencyMissing package
|
||||
Just dep -> do
|
||||
res <- readTMVar $ piResult dep
|
||||
unless res $ throwSTM $ DependencyFailed package
|
||||
|
||||
isCore = (`member` siCorePackages (bpSystemInfo bp))
|
||||
isCoreExe = (`member` siCoreExecutables (bpSystemInfo bp))
|
||||
|
||||
withCounter :: TVar Int -> IO a -> IO a
|
||||
withCounter counter = bracket_
|
||||
(atomically $ modifyTVar counter (+ 1))
|
||||
(atomically $ modifyTVar counter (subtract 1))
|
||||
|
||||
withTSem :: TSem -> IO a -> IO a
|
||||
withTSem sem = bracket_ (atomically $ waitTSem sem) (atomically $ signalTSem sem)
|
||||
|
||||
-- | Returns @Nothing@ if installing to a global database
|
||||
pbDatabase :: PerformBuild -> Maybe FilePath
|
||||
pbDatabase pb
|
||||
| pbGlobalInstall pb = Nothing
|
||||
| otherwise = Just $ pbInstallDest pb </> "pkgdb"
|
||||
|
||||
pbBinDir, pbLibDir, pbDataDir, pbDocDir :: PerformBuild -> FilePath
|
||||
pbBinDir pb = pbInstallDest pb </> "bin"
|
||||
pbLibDir pb = pbInstallDest pb </> "lib"
|
||||
pbDataDir pb = pbInstallDest pb </> "share"
|
||||
pbDocDir pb = pbInstallDest pb </> "doc"
|
||||
|
||||
performBuild :: PerformBuild -> IO [Text]
|
||||
performBuild pb = do
|
||||
cwd <- getWorkingDirectory
|
||||
performBuild' pb
|
||||
{ pbInstallDest = cwd </> pbInstallDest pb
|
||||
, pbLogDir = cwd </> pbLogDir pb
|
||||
}
|
||||
|
||||
performBuild' :: PerformBuild -> IO [Text]
|
||||
performBuild' pb@PerformBuild {..} = withBuildDir $ \builddir -> do
|
||||
-- First make sure to fetch all of the dependencies... just in case Hackage
|
||||
-- has an outage. Don't feel like wasting hours of CPU time.
|
||||
pbLog $ encodeUtf8 "Pre-fetching all packages\n"
|
||||
let toDownload = flip map (mapToList $ bpPackages pbPlan)
|
||||
$ \(name, plan) -> unpack $ concat
|
||||
[ display name
|
||||
, "-"
|
||||
, display $ ppVersion plan
|
||||
]
|
||||
withCheckedProcess
|
||||
(proc "cabal"
|
||||
$ "fetch"
|
||||
: "--no-dependencies"
|
||||
: toDownload)
|
||||
$ \ClosedStream Inherited Inherited -> return ()
|
||||
|
||||
let removeTree' fp = whenM (isDirectory fp) (removeTree fp)
|
||||
mapM_ removeTree' [pbInstallDest, pbLogDir]
|
||||
|
||||
forM_ (pbDatabase pb) $ \db -> do
|
||||
createTree $ parent db
|
||||
withCheckedProcess (proc "ghc-pkg" ["init", fpToString db])
|
||||
$ \ClosedStream Inherited Inherited -> return ()
|
||||
pbLog $ encodeUtf8 "Copying built-in Haddocks\n"
|
||||
copyBuiltInHaddocks (pbDocDir pb)
|
||||
|
||||
sem <- atomically $ newTSem pbJobs
|
||||
active <- newTVarIO (0 :: Int)
|
||||
let toolMap = makeToolMap $ bpPackages pbPlan
|
||||
packageMap <- fmap fold $ forM (mapToList $ bpPackages pbPlan)
|
||||
$ \(name, plan) -> do
|
||||
let piPlan = plan
|
||||
piName = name
|
||||
piResult <- newEmptyTMVarIO
|
||||
return $ singletonMap name PackageInfo {..}
|
||||
|
||||
errsVar <- newTVarIO mempty
|
||||
warningsVar <- newTVarIO id
|
||||
mutex <- newMVar ()
|
||||
env <- getEnvironment
|
||||
haddockFiles <- newTVarIO mempty
|
||||
|
||||
forM_ packageMap $ \pi -> void $ async $ singleBuild pb SingleBuild
|
||||
{ sbSem = sem
|
||||
, sbErrsVar = errsVar
|
||||
, sbWarningsVar = warningsVar
|
||||
, sbActive = active
|
||||
, sbToolMap = toolMap
|
||||
, sbPackageMap = packageMap
|
||||
, sbBuildDir = builddir
|
||||
, sbPackageInfo = pi
|
||||
, sbRegisterMutex = mutex
|
||||
, sbModifiedEnv = maybe
|
||||
id
|
||||
(\db -> (("HASKELL_PACKAGE_SANDBOX", fpToString db):))
|
||||
(pbDatabase pb)
|
||||
(filter allowedEnv $ map fixEnv env)
|
||||
, sbHaddockFiles = haddockFiles
|
||||
}
|
||||
|
||||
void $ tryAny $ atomically $ readTVar active >>= checkSTM . (== 0)
|
||||
|
||||
warnings <- ($ []) <$> readTVarIO warningsVar
|
||||
errs <- readTVarIO errsVar
|
||||
when (not $ null errs) $ throwM $ BuildException errs warnings
|
||||
return warnings
|
||||
where
|
||||
withBuildDir f = withSystemTempDirectory "stackage-build" (f . fpFromString)
|
||||
|
||||
fixEnv (p, x)
|
||||
-- Thank you Windows having case-insensitive environment variables...
|
||||
| toUpper p == "PATH" = (p, fpToString (pbBinDir pb) ++ pathSep : x)
|
||||
| otherwise = (p, x)
|
||||
|
||||
allowedEnv (k, _) = k `notMember` bannedEnvs
|
||||
|
||||
-- | Separate for the PATH environment variable
|
||||
pathSep :: Char
|
||||
#ifdef mingw32_HOST_OS
|
||||
pathSep = ';'
|
||||
#else
|
||||
pathSep = ':'
|
||||
#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
|
||||
{ sbSem :: TSem
|
||||
, sbErrsVar :: TVar (Map PackageName BuildFailure)
|
||||
, sbWarningsVar :: TVar ([Text] -> [Text])
|
||||
, sbActive :: TVar Int
|
||||
, sbToolMap :: Map ExeName (Set PackageName)
|
||||
, sbPackageMap :: Map PackageName PackageInfo
|
||||
, sbBuildDir :: FilePath
|
||||
, sbPackageInfo :: PackageInfo
|
||||
, sbRegisterMutex :: MVar ()
|
||||
, sbModifiedEnv :: [(String, String)]
|
||||
, sbHaddockFiles :: TVar (Map Text FilePath) -- ^ package-version, .haddock file
|
||||
}
|
||||
|
||||
singleBuild :: PerformBuild -> SingleBuild -> IO ()
|
||||
singleBuild pb@PerformBuild {..} SingleBuild {..} =
|
||||
withCounter sbActive
|
||||
$ handle updateErrs
|
||||
$ (`finally` void (atomically $ tryPutTMVar (piResult sbPackageInfo) False))
|
||||
$ inner
|
||||
where
|
||||
libComps = setFromList [CompLibrary, CompExecutable]
|
||||
testComps = insertSet CompTestSuite libComps
|
||||
inner = do
|
||||
let wfd comps =
|
||||
waitForDeps sbToolMap sbPackageMap comps pbPlan sbPackageInfo
|
||||
. withTSem sbSem
|
||||
wfd libComps buildLibrary
|
||||
|
||||
wfd testComps runTests
|
||||
|
||||
name = display $ piName sbPackageInfo
|
||||
namever = concat
|
||||
[ name
|
||||
, "-"
|
||||
, display $ ppVersion $ piPlan sbPackageInfo
|
||||
]
|
||||
|
||||
runIn wdir outH cmd args =
|
||||
withCheckedProcess cp $ \ClosedStream UseProvidedHandle UseProvidedHandle ->
|
||||
(return () :: IO ())
|
||||
where
|
||||
cp = (proc (unpack $ asText cmd) (map (unpack . asText) args))
|
||||
{ cwd = Just $ fpToString wdir
|
||||
, std_out = UseHandle outH
|
||||
, std_err = UseHandle outH
|
||||
, env = Just sbModifiedEnv
|
||||
}
|
||||
runParent = runIn sbBuildDir
|
||||
runChild = runIn childDir
|
||||
childDir = sbBuildDir </> fpFromText namever
|
||||
|
||||
log' t = do
|
||||
i <- readTVarIO sbActive
|
||||
errs <- readTVarIO sbErrsVar
|
||||
pbLog $ encodeUtf8 $ concat
|
||||
[ t
|
||||
, " (pending: "
|
||||
, tshow i
|
||||
, ", failures: "
|
||||
, tshow $ length errs
|
||||
, ")\n"
|
||||
]
|
||||
libOut = pbLogDir </> fpFromText namever </> "build.out"
|
||||
testOut = pbLogDir </> fpFromText namever </> "test.out"
|
||||
testRunOut = pbLogDir </> fpFromText namever </> "test-run.out"
|
||||
|
||||
wf fp inner' = do
|
||||
createTree $ parent fp
|
||||
withBinaryFile (fpToString fp) WriteMode inner'
|
||||
|
||||
configArgs = ($ []) $ execWriter $ do
|
||||
when pbAllowNewer $ tell' "--allow-newer"
|
||||
tell' "--package-db=clear"
|
||||
tell' "--package-db=global"
|
||||
forM_ (pbDatabase pb) $ \db -> tell' $ "--package-db=" ++ fpToText db
|
||||
tell' $ "--libdir=" ++ fpToText (pbLibDir pb)
|
||||
tell' $ "--bindir=" ++ fpToText (pbBinDir pb)
|
||||
tell' $ "--datadir=" ++ fpToText (pbDataDir pb)
|
||||
tell' $ "--docdir=" ++ fpToText (pbDocDir pb)
|
||||
tell' $ "--flags=" ++ flags
|
||||
when (pbEnableLibProfiling && pcEnableLibProfile) $
|
||||
tell' "--enable-library-profiling"
|
||||
where
|
||||
tell' x = tell (x:)
|
||||
|
||||
flags :: Text
|
||||
flags = unwords $ map go $ mapToList pcFlagOverrides
|
||||
where
|
||||
go (name', isOn) = concat
|
||||
[ if isOn then "" else "-"
|
||||
, unFlagName name'
|
||||
]
|
||||
|
||||
PackageConstraints {..} = ppConstraints $ piPlan sbPackageInfo
|
||||
|
||||
buildLibrary = wf libOut $ \outH -> do
|
||||
let run a b = do when pbVerbose $ log' (unwords (a : b))
|
||||
runChild outH a b
|
||||
log' $ "Unpacking " ++ namever
|
||||
runParent outH "cabal" ["unpack", namever]
|
||||
|
||||
log' $ "Configuring " ++ namever
|
||||
run "cabal" $ "configure" : configArgs
|
||||
|
||||
log' $ "Building " ++ namever
|
||||
run "cabal" ["build"]
|
||||
|
||||
log' $ "Copying/registering " ++ namever
|
||||
run "cabal" ["copy"]
|
||||
withMVar sbRegisterMutex $ const $
|
||||
run "cabal" ["register"]
|
||||
|
||||
-- Even if the tests later fail, we can allow other libraries to build
|
||||
-- on top of our successful results
|
||||
--
|
||||
-- FIXME do we need to wait to do this until after Haddocks build?
|
||||
-- otherwise, we could have a race condition and try to build a
|
||||
-- dependency's haddocks before this finishes
|
||||
atomically $ putTMVar (piResult sbPackageInfo) True
|
||||
|
||||
when (pcHaddocks /= Don'tBuild && not (null $ sdModules $ ppDesc $ piPlan sbPackageInfo)) $ do
|
||||
log' $ "Haddocks " ++ namever
|
||||
hfs <- readTVarIO sbHaddockFiles
|
||||
let hfsOpts = flip map (mapToList hfs) $ \(pkgVer, hf) -> concat
|
||||
[ "--haddock-options=--read-interface="
|
||||
, "../"
|
||||
, pkgVer
|
||||
, "/,"
|
||||
, fpToText hf
|
||||
]
|
||||
args = "haddock"
|
||||
: "--hyperlink-source"
|
||||
: "--html"
|
||||
: "--hoogle"
|
||||
: "--html-location=../$pkg-$version/"
|
||||
: hfsOpts
|
||||
|
||||
eres <- tryAny $ run "cabal" args
|
||||
|
||||
forM_ eres $ \() -> do
|
||||
renameOrCopy
|
||||
(childDir </> "dist" </> "doc" </> "html" </> fpFromText name)
|
||||
(pbDocDir pb </> fpFromText namever)
|
||||
|
||||
enewPath <- tryIO
|
||||
$ canonicalizePath
|
||||
$ pbDocDir pb
|
||||
</> fpFromText namever
|
||||
</> fpFromText name <.> "haddock"
|
||||
case enewPath of
|
||||
Left e -> warn $ tshow e
|
||||
Right newPath -> atomically
|
||||
$ modifyTVar sbHaddockFiles
|
||||
$ insertMap namever newPath
|
||||
|
||||
case (eres, pcHaddocks) of
|
||||
(Left e, ExpectSuccess) -> throwM e
|
||||
(Right (), ExpectFailure) -> warn $ namever ++ ": unexpected Haddock success"
|
||||
_ -> return ()
|
||||
|
||||
runTests = wf testOut $ \outH -> do
|
||||
let run = runChild outH
|
||||
|
||||
when (pbEnableTests && pcTests /= Don'tBuild) $ do
|
||||
log' $ "Test configure " ++ namever
|
||||
run "cabal" $ "configure" : "--enable-tests" : configArgs
|
||||
|
||||
eres <- tryAny $ do
|
||||
log' $ "Test build " ++ namever
|
||||
run "cabal" ["build"]
|
||||
|
||||
log' $ "Test run " ++ namever
|
||||
run "cabal" ["test", "--log=" ++ fpToText testRunOut]
|
||||
|
||||
case (eres, pcTests) of
|
||||
(Left e, ExpectSuccess) -> throwM e
|
||||
(Right (), ExpectFailure) -> warn $ namever ++ ": unexpected test success"
|
||||
_ -> return ()
|
||||
|
||||
warn t = atomically $ modifyTVar sbWarningsVar (. (t:))
|
||||
|
||||
updateErrs exc = do
|
||||
log' $ concat
|
||||
[ display (piName sbPackageInfo)
|
||||
, ": "
|
||||
, tshow exc
|
||||
]
|
||||
atomically $ modifyTVar sbErrsVar $ insertMap (piName sbPackageInfo) exc'
|
||||
where
|
||||
exc' =
|
||||
case fromException exc of
|
||||
Just bf -> bf
|
||||
Nothing -> BuildFailureException exc
|
||||
|
||||
renameOrCopy :: FilePath -> FilePath -> IO ()
|
||||
renameOrCopy src dest = rename src dest `catchIO` \_ -> copyDir src dest
|
||||
|
||||
copyDir :: FilePath -> FilePath -> IO ()
|
||||
copyDir src dest =
|
||||
runResourceT $ sourceDirectoryDeep False src $$ mapM_C go
|
||||
where
|
||||
src' = src </> ""
|
||||
go fp = forM_ (F.stripPrefix src' fp) $ \suffix -> do
|
||||
let dest' = dest </> suffix
|
||||
liftIO $ createTree $ parent dest'
|
||||
sourceFile fp $$ (sinkFile dest' :: Sink ByteString (ResourceT IO) ())
|
||||
|
||||
copyBuiltInHaddocks :: FilePath -> IO ()
|
||||
copyBuiltInHaddocks docdir = do
|
||||
mghc <- findExecutable "ghc"
|
||||
case mghc of
|
||||
Nothing -> error "GHC not found on PATH"
|
||||
Just ghc -> do
|
||||
src <- canonicalizePath
|
||||
(parent (fpFromString ghc) </> "../share/doc/ghc/html/libraries")
|
||||
copyDir src docdir
|
||||
@ -1,103 +0,0 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
module Stackage.Prelude
|
||||
( module X
|
||||
, module Stackage.Prelude
|
||||
) where
|
||||
|
||||
import ClassyPrelude.Conduit as X
|
||||
import Data.Aeson (FromJSON, ToJSON)
|
||||
import Data.Conduit.Process as X
|
||||
import qualified Data.Map as Map
|
||||
import Data.Typeable (TypeRep, typeOf)
|
||||
import Distribution.Package as X (PackageIdentifier (..), PackageName (PackageName))
|
||||
import Distribution.PackageDescription as X (FlagName (..), GenericPackageDescription)
|
||||
import qualified Distribution.Text as DT
|
||||
import Distribution.Version as X (Version (..),
|
||||
VersionRange)
|
||||
import Distribution.Version as X (withinRange)
|
||||
import qualified Distribution.Version as C
|
||||
|
||||
unPackageName :: PackageName -> Text
|
||||
unPackageName (PackageName str) = pack str
|
||||
|
||||
unFlagName :: FlagName -> Text
|
||||
unFlagName (FlagName str) = pack str
|
||||
|
||||
mkPackageName :: Text -> PackageName
|
||||
mkPackageName = PackageName . unpack
|
||||
|
||||
mkFlagName :: Text -> FlagName
|
||||
mkFlagName = FlagName . unpack
|
||||
|
||||
display :: DT.Text a => a -> Text
|
||||
display = fromString . DT.display
|
||||
|
||||
simpleParse :: (MonadThrow m, DT.Text a, Typeable a) => Text -> m a
|
||||
simpleParse orig = withTypeRep $ \rep ->
|
||||
case DT.simpleParse str of
|
||||
Nothing -> throwM (ParseFailedException rep (pack str))
|
||||
Just v -> return v
|
||||
where
|
||||
str = unpack orig
|
||||
|
||||
withTypeRep :: Typeable a => (TypeRep -> m a) -> m a
|
||||
withTypeRep f =
|
||||
res
|
||||
where
|
||||
res = f (typeOf (unwrap res))
|
||||
|
||||
unwrap :: m a -> a
|
||||
unwrap _ = error "unwrap"
|
||||
|
||||
data ParseFailedException = ParseFailedException TypeRep Text
|
||||
deriving (Show, Typeable)
|
||||
instance Exception ParseFailedException
|
||||
|
||||
newtype Maintainer = Maintainer { unMaintainer :: Text }
|
||||
deriving (Show, Eq, Ord, Hashable, ToJSON, FromJSON, IsString)
|
||||
|
||||
-- | Name of an executable.
|
||||
newtype ExeName = ExeName { unExeName :: Text }
|
||||
deriving (Show, Eq, Ord, Hashable, ToJSON, FromJSON, IsString)
|
||||
|
||||
intersectVersionRanges :: VersionRange -> VersionRange -> VersionRange
|
||||
intersectVersionRanges x y = C.simplifyVersionRange $ C.intersectVersionRanges x y
|
||||
|
||||
-- | There seems to be a bug in Cabal where serializing and deserializing
|
||||
-- version ranges winds up with different representations. So we have a
|
||||
-- super-simplifier to deal with that.
|
||||
simplifyVersionRange :: VersionRange -> VersionRange
|
||||
simplifyVersionRange vr =
|
||||
fromMaybe (assert False vr') $ simpleParse $ display vr'
|
||||
where
|
||||
vr' = C.simplifyVersionRange vr
|
||||
|
||||
-- | Topologically sort so that items with dependencies occur after those
|
||||
-- dependencies.
|
||||
topologicalSort :: (Ord key, Show key, MonadThrow m, Typeable key)
|
||||
=> (value -> finalValue)
|
||||
-> (value -> Set key) -- ^ deps
|
||||
-> Map key value
|
||||
-> m (Vector (key, finalValue))
|
||||
topologicalSort toFinal toDeps =
|
||||
loop id . mapWithKey removeSelfDeps . fmap (toDeps &&& toFinal)
|
||||
where
|
||||
removeSelfDeps k (deps, final) = (deleteSet k deps, final)
|
||||
loop front toProcess | null toProcess = return $ pack $ front []
|
||||
loop front toProcess
|
||||
| null noDeps = throwM $ NoEmptyDeps (map fst toProcess')
|
||||
| otherwise = loop (front . noDeps') (mapFromList hasDeps)
|
||||
where
|
||||
toProcess' = fmap (first removeUnavailable) toProcess
|
||||
allKeys = Map.keysSet toProcess
|
||||
removeUnavailable = asSet . setFromList . filter (`member` allKeys) . setToList
|
||||
(noDeps, hasDeps) = partition (null . fst . snd) $ mapToList toProcess'
|
||||
noDeps' = (map (second snd) noDeps ++)
|
||||
|
||||
data TopologicalSortException key = NoEmptyDeps (Map key (Set key))
|
||||
deriving (Show, Typeable)
|
||||
instance (Show key, Typeable key) => Exception (TopologicalSortException key)
|
||||
@ -1,114 +0,0 @@
|
||||
-- | Create a bundle to be uploaded to Stackage Server.
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
module Stackage.ServerBundle
|
||||
( serverBundle
|
||||
, epochTime
|
||||
, bpAllPackages
|
||||
, docsListing
|
||||
) where
|
||||
|
||||
import qualified Codec.Archive.Tar as Tar
|
||||
import qualified Codec.Archive.Tar.Entry as Tar
|
||||
import qualified Codec.Compression.GZip as GZip
|
||||
import qualified Data.Map as M
|
||||
import qualified Data.Yaml as Y
|
||||
import Filesystem (isFile)
|
||||
import Foreign.C.Types (CTime (CTime))
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.BuildPlan
|
||||
import Stackage.Prelude
|
||||
import qualified System.PosixCompat.Time as PC
|
||||
import qualified Text.XML as X
|
||||
import Text.XML.Cursor
|
||||
|
||||
-- | Get current time
|
||||
epochTime :: IO Tar.EpochTime
|
||||
epochTime = (\(CTime t) -> fromIntegral t) <$> PC.epochTime
|
||||
|
||||
-- | All package/versions in a build plan, including core packages.
|
||||
--
|
||||
-- Note that this may include packages not available on Hackage.
|
||||
bpAllPackages :: BuildPlan -> Map PackageName Version
|
||||
bpAllPackages BuildPlan {..} =
|
||||
siCorePackages bpSystemInfo ++ map ppVersion bpPackages
|
||||
|
||||
serverBundle :: Tar.EpochTime
|
||||
-> Text -- ^ title
|
||||
-> Text -- ^ slug
|
||||
-> BuildPlan
|
||||
-> LByteString
|
||||
serverBundle time title slug bp@BuildPlan {..} = GZip.compress $ Tar.write
|
||||
[ fe "build-plan.yaml" (fromStrict $ Y.encode bp)
|
||||
, fe "hackage" hackage
|
||||
, fe "slug" (fromStrict $ encodeUtf8 slug)
|
||||
, fe "desc" (fromStrict $ encodeUtf8 title)
|
||||
, fe "core" corePackagesList
|
||||
]
|
||||
where
|
||||
fe name contents =
|
||||
case Tar.toTarPath False name of
|
||||
Left s -> error s
|
||||
Right name' -> (Tar.fileEntry name' contents)
|
||||
{ Tar.entryTime = time
|
||||
}
|
||||
hackage = builderToLazy $ foldMap goPair $ mapToList packageMap
|
||||
|
||||
-- need to remove some packages that don't exist on Hackage
|
||||
packageMap = foldr deleteMap (bpAllPackages bp) $ map PackageName
|
||||
[ "bin-package-db"
|
||||
, "ghc"
|
||||
, "rts"
|
||||
]
|
||||
|
||||
goPair (name, version) =
|
||||
toBuilder (display name) ++
|
||||
toBuilder (asText "-") ++
|
||||
toBuilder (display version) ++
|
||||
toBuilder (asText "\n")
|
||||
|
||||
corePackagesList =
|
||||
builderToLazy $ toBuilder $ unlines $
|
||||
map (\(PackageName name) -> name)
|
||||
(M.keys $ siCorePackages bpSystemInfo)
|
||||
|
||||
docsListing :: BuildPlan
|
||||
-> FilePath -- ^ docs directory
|
||||
-> IO ByteString
|
||||
docsListing bp docsDir =
|
||||
fmap (Y.encode . fold) $ mapM go $ mapToList $ bpAllPackages bp
|
||||
where
|
||||
go :: (PackageName, Version) -> IO (Map Text Y.Value)
|
||||
go (package, version) = do -- handleAny (const $ return mempty) $ do
|
||||
let dirname = fpFromText (concat
|
||||
[ display package
|
||||
, "-"
|
||||
, display version
|
||||
])
|
||||
indexFP = (docsDir </> dirname </> "index.html")
|
||||
ie <- isFile indexFP
|
||||
if ie
|
||||
then do
|
||||
doc <- flip X.readFile indexFP X.def
|
||||
{ X.psDecodeEntities = X.decodeHtmlEntities
|
||||
}
|
||||
let cursor = fromDocument doc
|
||||
getPair x = take 1 $ do
|
||||
href <- attribute "href" x
|
||||
let name = concat $ x $// content
|
||||
guard $ not $ null name
|
||||
return (href, name)
|
||||
pairs = cursor $// attributeIs "class" "module"
|
||||
&/ laxElement "a" >=> getPair
|
||||
m <- fmap fold $ forM pairs $ \(href, name) -> do
|
||||
let suffix = dirname </> fpFromText href
|
||||
e <- isFile $ docsDir </> suffix
|
||||
return $ if e
|
||||
then asMap $ singletonMap name [fpToText dirname, href]
|
||||
else mempty
|
||||
return $ singletonMap (display package) $ Y.object
|
||||
[ "version" Y..= display version
|
||||
, "modules" Y..= m
|
||||
]
|
||||
else return mempty
|
||||
@ -1,54 +0,0 @@
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
-- | Take an existing build plan and bump all packages to the newest version in
|
||||
-- the same major version number.
|
||||
module Stackage.UpdateBuildPlan
|
||||
( updateBuildConstraints
|
||||
, updateBuildPlan
|
||||
) where
|
||||
|
||||
import qualified Data.Map as Map
|
||||
import Distribution.Version (anyVersion, earlierVersion,
|
||||
orLaterVersion)
|
||||
import Stackage.BuildConstraints
|
||||
import Stackage.BuildPlan
|
||||
import Stackage.Prelude
|
||||
|
||||
updateBuildPlan :: Map PackageName PackagePlan -> BuildPlan -> IO BuildPlan
|
||||
updateBuildPlan packagesOrig
|
||||
= newBuildPlan packagesOrig . updateBuildConstraints
|
||||
|
||||
updateBuildConstraints :: BuildPlan -> BuildConstraints
|
||||
updateBuildConstraints BuildPlan {..} =
|
||||
BuildConstraints {..}
|
||||
where
|
||||
bcSystemInfo = bpSystemInfo
|
||||
bcPackages = Map.keysSet bpPackages
|
||||
bcGithubUsers = bpGithubUsers
|
||||
|
||||
bcPackageConstraints name = PackageConstraints
|
||||
{ pcVersionRange = addBumpRange (maybe anyVersion pcVersionRange moldPC)
|
||||
, pcMaintainer = moldPC >>= pcMaintainer
|
||||
, pcTests = maybe ExpectSuccess pcTests moldPC
|
||||
, pcHaddocks = maybe ExpectSuccess pcHaddocks moldPC
|
||||
, pcBuildBenchmarks = maybe True pcBuildBenchmarks moldPC
|
||||
, pcFlagOverrides = maybe mempty pcFlagOverrides moldPC
|
||||
, pcEnableLibProfile = maybe False pcEnableLibProfile moldPC
|
||||
}
|
||||
where
|
||||
moldBP = lookup name bpPackages
|
||||
moldPC = ppConstraints <$> moldBP
|
||||
|
||||
addBumpRange oldRange =
|
||||
case moldBP of
|
||||
Nothing -> oldRange
|
||||
Just bp -> intersectVersionRanges oldRange
|
||||
$ bumpRange $ ppVersion bp
|
||||
|
||||
bumpRange version = intersectVersionRanges
|
||||
(orLaterVersion version)
|
||||
(earlierVersion $ bumpVersion version)
|
||||
bumpVersion (Version (x:y:_) _) = Version [x, y + 1] []
|
||||
bumpVersion (Version [x] _) = Version [x, 1] []
|
||||
bumpVersion (Version [] _) = assert False $ Version [1, 0] []
|
||||
@ -1,279 +0,0 @@
|
||||
-- | Upload to Stackage and Hackage
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
module Stackage.Upload
|
||||
( UploadBundle (..)
|
||||
, SnapshotIdent (..)
|
||||
, uploadBundle
|
||||
, UploadDocs (..)
|
||||
, uploadDocs
|
||||
, uploadHackageDistro
|
||||
, uploadHackageDistroNamed
|
||||
, UploadDocMap (..)
|
||||
, uploadDocMap
|
||||
) where
|
||||
|
||||
import Control.Monad.Writer.Strict (execWriter, tell)
|
||||
import Data.Default.Class (Default (..))
|
||||
import Filesystem (isDirectory, isFile)
|
||||
import Network.HTTP.Client
|
||||
import Network.HTTP.Client.MultipartFormData
|
||||
import Stackage.BuildPlan (BuildPlan)
|
||||
import Stackage.Prelude
|
||||
import Stackage.ServerBundle (bpAllPackages, docsListing)
|
||||
import System.IO.Temp (withSystemTempFile)
|
||||
|
||||
newtype StackageServer = StackageServer { unStackageServer :: Text }
|
||||
deriving (Show, Eq, Ord, Hashable, IsString)
|
||||
instance Default StackageServer where
|
||||
def = "http://www.stackage.org"
|
||||
|
||||
data UploadBundle = UploadBundle
|
||||
{ ubServer :: StackageServer
|
||||
, ubContents :: LByteString
|
||||
, ubAlias :: Maybe Text
|
||||
, ubNightly :: Maybe Text -- ^ should be GHC version
|
||||
, ubLTS :: Maybe Text -- ^ e.g. 2.3
|
||||
, ubAuthToken :: Text
|
||||
}
|
||||
instance Default UploadBundle where
|
||||
def = UploadBundle
|
||||
{ ubServer = def
|
||||
, ubContents = mempty
|
||||
, ubAlias = Nothing
|
||||
, ubNightly = Nothing
|
||||
, ubLTS = Nothing
|
||||
, ubAuthToken = "no-auth-token-provided"
|
||||
}
|
||||
|
||||
newtype SnapshotIdent = SnapshotIdent { unSnapshotIdent :: Text }
|
||||
deriving (Show, Eq, Ord, Hashable, IsString)
|
||||
|
||||
uploadBundle :: UploadBundle -> Manager -> IO (SnapshotIdent, Maybe Text)
|
||||
uploadBundle UploadBundle {..} man = do
|
||||
req1 <- parseUrl $ unpack $ unStackageServer ubServer ++ "/upload"
|
||||
req2 <- formDataBody formData req1
|
||||
let req3 = req2
|
||||
{ method = "PUT"
|
||||
, requestHeaders =
|
||||
[ ("Authorization", encodeUtf8 ubAuthToken)
|
||||
, ("Accept", "application/json")
|
||||
] ++ requestHeaders req2
|
||||
, redirectCount = 0
|
||||
, checkStatus = \_ _ _ -> Nothing
|
||||
, responseTimeout = Just 300000000
|
||||
}
|
||||
res <- httpLbs req3 man
|
||||
case lookup "x-stackage-ident" $ responseHeaders res of
|
||||
Just snapid -> return
|
||||
( SnapshotIdent $ decodeUtf8 snapid
|
||||
, decodeUtf8 <$> lookup "location" (responseHeaders res)
|
||||
)
|
||||
Nothing -> error $ "An error occurred: " ++ show res
|
||||
where
|
||||
params = mapMaybe (\(x, y) -> (x, ) <$> y)
|
||||
[ ("alias", ubAlias)
|
||||
, ("nightly", ubNightly)
|
||||
, ("lts", ubLTS)
|
||||
]
|
||||
formData = ($ []) $ execWriter $ do
|
||||
forM_ params $ \(key, value) ->
|
||||
tell' $ partBS key $ encodeUtf8 value
|
||||
tell' $ partFileRequestBody "stackage" "stackage"
|
||||
$ RequestBodyLBS ubContents
|
||||
|
||||
tell' x = tell (x:)
|
||||
|
||||
data UploadDocs = UploadDocs
|
||||
{ udServer :: StackageServer
|
||||
, udDocs :: FilePath -- ^ may be a directory or a tarball
|
||||
, udAuthToken :: Text
|
||||
, udSnapshot :: SnapshotIdent
|
||||
}
|
||||
|
||||
uploadDocs :: UploadDocs -> Manager -> IO (Response LByteString)
|
||||
uploadDocs (UploadDocs (StackageServer host) fp0 token ident) man = do
|
||||
fe <- isFile fp0
|
||||
if fe
|
||||
then uploadDocsFile $ fpToString fp0
|
||||
else do
|
||||
de <- isDirectory fp0
|
||||
if de
|
||||
then uploadDocsDir
|
||||
else error $ "Path not found: " ++ fpToString fp0
|
||||
where
|
||||
uploadDocsDir = withSystemTempFile "haddocks.tar.xz" $ \fp h -> do
|
||||
hClose h
|
||||
dirs <- fmap sort
|
||||
$ runResourceT
|
||||
$ sourceDirectory fp0
|
||||
$$ filterMC (liftIO . isDirectory)
|
||||
=$ mapC (fpToString . filename)
|
||||
=$ sinkList
|
||||
writeFile (fp0 </> "index.html") $ mkIndex
|
||||
(unpack $ unSnapshotIdent ident)
|
||||
dirs
|
||||
writeFile (fp0 </> "style.css") styleCss
|
||||
-- FIXME write index.html, style.css
|
||||
let cp = (proc "tar" $ "cJf" : fp : "index.html" : "style.css" : dirs)
|
||||
{ cwd = Just $ fpToString fp0
|
||||
}
|
||||
withCheckedProcess cp $ \Inherited Inherited Inherited -> return ()
|
||||
uploadDocsFile fp
|
||||
uploadDocsFile fp = do
|
||||
req1 <- parseUrl $ unpack $ concat
|
||||
[ host
|
||||
, "/upload-haddock/"
|
||||
, unSnapshotIdent ident
|
||||
]
|
||||
let formData =
|
||||
[ partFileSource "tarball" fp
|
||||
]
|
||||
req2 <- formDataBody formData req1
|
||||
let req3 = req2
|
||||
{ method = "PUT"
|
||||
, requestHeaders =
|
||||
[ ("Authorization", encodeUtf8 token)
|
||||
, ("Accept", "application/json")
|
||||
] ++ requestHeaders req2
|
||||
, redirectCount = 0
|
||||
, checkStatus = \_ _ _ -> Nothing
|
||||
, responseTimeout = Just 300000000
|
||||
}
|
||||
httpLbs req3 man
|
||||
|
||||
uploadHackageDistro :: BuildPlan
|
||||
-> ByteString -- ^ Hackage username
|
||||
-> ByteString -- ^ Hackage password
|
||||
-> Manager
|
||||
-> IO (Response LByteString)
|
||||
uploadHackageDistro = uploadHackageDistroNamed "Stackage"
|
||||
|
||||
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
|
||||
csv = encodeUtf8
|
||||
$ builderToLazy
|
||||
$ mconcat
|
||||
$ intersperse "\n"
|
||||
$ map go
|
||||
$ mapToList
|
||||
$ bpAllPackages bp
|
||||
go (name, version) =
|
||||
"\"" ++
|
||||
(toBuilder $ display name) ++
|
||||
"\",\"" ++
|
||||
(toBuilder $ display version) ++
|
||||
"\",\"http://www.stackage.org/package/" ++
|
||||
(toBuilder $ display name) ++
|
||||
"\""
|
||||
|
||||
data UploadDocMap = UploadDocMap
|
||||
{ udmServer :: StackageServer
|
||||
, udmAuthToken :: Text
|
||||
, udmSnapshot :: SnapshotIdent
|
||||
, udmDocDir :: FilePath
|
||||
, udmPlan :: BuildPlan
|
||||
}
|
||||
|
||||
uploadDocMap :: UploadDocMap -> Manager -> IO (Response LByteString)
|
||||
uploadDocMap UploadDocMap {..} man = do
|
||||
docmap <- docsListing udmPlan udmDocDir
|
||||
req1 <- parseUrl $ unpack $ unStackageServer udmServer ++ "/upload-doc-map"
|
||||
req2 <- formDataBody (formData docmap) req1
|
||||
let req3 = req2
|
||||
{ method = "PUT"
|
||||
, requestHeaders =
|
||||
[ ("Authorization", encodeUtf8 udmAuthToken)
|
||||
, ("Accept", "application/json")
|
||||
] ++ requestHeaders req2
|
||||
, redirectCount = 0
|
||||
, checkStatus = \_ _ _ -> Nothing
|
||||
, responseTimeout = Just 300000000
|
||||
}
|
||||
httpLbs req3 man
|
||||
where
|
||||
formData docmap =
|
||||
[ partBS "snapshot" (encodeUtf8 $ unSnapshotIdent udmSnapshot)
|
||||
, partFileRequestBody "docmap" "docmap" $ RequestBodyBS docmap
|
||||
]
|
||||
|
||||
mkIndex :: String -> [String] -> String
|
||||
mkIndex snapid dirs = concat
|
||||
[ "<!DOCTYPE html>\n<html lang='en'><head><title>Haddocks index</title>"
|
||||
, "<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'>"
|
||||
, "<link rel='stylesheet' href='style.css'>"
|
||||
, "<link rel='shortcut icon' href='http://www.stackage.org/static/img/favicon.ico' />"
|
||||
, "</head>"
|
||||
, "<body><div class='container'>"
|
||||
, "<div class='row'><div class='span12 col-md-12'>"
|
||||
, "<h1>Haddock documentation index</h1>"
|
||||
, "<p class='return'><a href=\"http://www.stackage.org/stackage/"
|
||||
, snapid
|
||||
, "\">Return to snapshot</a></p><ul>"
|
||||
, concatMap toLI dirs
|
||||
, "</ul></div></div></div></body></html>"
|
||||
]
|
||||
where
|
||||
toLI name = concat
|
||||
[ "<li><a href='"
|
||||
, name
|
||||
, "/index.html'>"
|
||||
, name
|
||||
, "</a></li>"
|
||||
]
|
||||
|
||||
styleCss :: String
|
||||
styleCss = concat
|
||||
[ "@media (min-width: 530px) {"
|
||||
, "ul { -webkit-column-count: 2; -moz-column-count: 2; column-count: 2 }"
|
||||
, "}"
|
||||
, "@media (min-width: 760px) {"
|
||||
, "ul { -webkit-column-count: 3; -moz-column-count: 3; column-count: 3 }"
|
||||
, "}"
|
||||
, "ul {"
|
||||
, " margin-left: 0;"
|
||||
, " padding-left: 0;"
|
||||
, " list-style-type: none;"
|
||||
, "}"
|
||||
, "body {"
|
||||
, " background: #f0f0f0;"
|
||||
, " font-family: 'Lato', sans-serif;"
|
||||
, " text-shadow: 1px 1px 1px #ffffff;"
|
||||
, " font-size: 20px;"
|
||||
, " line-height: 30px;"
|
||||
, " padding-bottom: 5em;"
|
||||
, "}"
|
||||
, "h1 {"
|
||||
, " font-weight: normal;"
|
||||
, " color: #06537d;"
|
||||
, " font-size: 45px;"
|
||||
, "}"
|
||||
, ".return a {"
|
||||
, " color: #06537d;"
|
||||
, " font-style: italic;"
|
||||
, "}"
|
||||
, ".return {"
|
||||
, " margin-bottom: 1em;"
|
||||
, "}"]
|
||||
@ -1,88 +0,0 @@
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Monad
|
||||
import Data.Monoid
|
||||
import Data.String (fromString)
|
||||
import Data.Version
|
||||
import Options.Applicative
|
||||
import Paths_stackage (version)
|
||||
import Stackage.CompleteBuild
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
join $
|
||||
execParser $
|
||||
info
|
||||
(helpOption <*> versionOption <*> config)
|
||||
(header "Stackage" <>
|
||||
fullDesc)
|
||||
where
|
||||
helpOption =
|
||||
abortOption ShowHelpText $
|
||||
long "help" <>
|
||||
help "Show this help text"
|
||||
versionOption =
|
||||
infoOption
|
||||
("fpbuild version " ++ showVersion version)
|
||||
(long "version" <>
|
||||
help "Show fpbuild 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 exec parse name desc =
|
||||
command name $
|
||||
info
|
||||
(fmap exec parse)
|
||||
(progDesc desc)
|
||||
buildFlags =
|
||||
BuildFlags <$>
|
||||
fmap
|
||||
not
|
||||
(switch
|
||||
(long "skip-tests" <>
|
||||
help "Skip build and running the test suites")) <*>
|
||||
fmap
|
||||
not
|
||||
(switch
|
||||
(long "skip-upload" <>
|
||||
help "Skip uploading bundle, docs, etc.")) <*>
|
||||
switch
|
||||
(long "enable-library-profiling" <>
|
||||
help "Enable profiling 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")
|
||||
@ -67,12 +67,13 @@ packages:
|
||||
- csv-conduit
|
||||
- diagrams-cairo
|
||||
- dimensional
|
||||
- executable-hash
|
||||
- executable-path
|
||||
- fgl
|
||||
- fixed-list
|
||||
- foreign-store
|
||||
- formatting
|
||||
- fpco-api
|
||||
#- fpco-api
|
||||
- gtk2hs-buildtools
|
||||
- happy
|
||||
- histogram-fill
|
||||
@ -92,6 +93,8 @@ packages:
|
||||
- shelly
|
||||
- smtLib
|
||||
- stackage
|
||||
- stackage-curator
|
||||
- stackage-types
|
||||
- statistics-linreg
|
||||
- th-expand-syns
|
||||
- thyme
|
||||
@ -119,10 +122,10 @@ packages:
|
||||
- kure
|
||||
|
||||
"Omari Norman <omari@smileystation.com>":
|
||||
- barecheck
|
||||
- rainbow
|
||||
- rainbow-tests
|
||||
- quickpull
|
||||
- multiarg
|
||||
- prednote
|
||||
- cartel
|
||||
|
||||
"Neil Mitchell":
|
||||
- hlint
|
||||
@ -150,6 +153,7 @@ packages:
|
||||
"Jasper Van der Jeugt":
|
||||
- blaze-html
|
||||
- blaze-markup
|
||||
- hakyll
|
||||
- stylish-haskell
|
||||
|
||||
"Antoine Latter":
|
||||
@ -181,7 +185,6 @@ packages:
|
||||
- crypto-random-api
|
||||
- hit
|
||||
- language-java
|
||||
- language-java
|
||||
- libgit
|
||||
- pem
|
||||
- siphash
|
||||
@ -208,15 +211,17 @@ packages:
|
||||
- scrobble
|
||||
- shell-conduit
|
||||
- sourcemap
|
||||
- hindent
|
||||
- descriptive
|
||||
- wrap
|
||||
# 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
|
||||
# "Alberto G. Corona <agocorona@gmail.com>":
|
||||
# - RefSerialize
|
||||
# - TCache
|
||||
# - Workflow
|
||||
# - MFlow
|
||||
"Alberto G. Corona <agocorona@gmail.com>":
|
||||
- RefSerialize
|
||||
- TCache
|
||||
- Workflow
|
||||
- MFlow
|
||||
|
||||
"Edward Kmett <ekmett@gmail.com>":
|
||||
- ad
|
||||
@ -311,13 +316,17 @@ packages:
|
||||
|
||||
"Brent Yorgey <byorgey@gmail.com>":
|
||||
- active
|
||||
- BlogLiterately
|
||||
- BlogLiterately-diagrams
|
||||
# Temporarily disabled due to restrictive lens upper bound
|
||||
#- BlogLiterately
|
||||
#- BlogLiterately-diagrams
|
||||
- diagrams
|
||||
- diagrams-builder
|
||||
|
||||
# https://github.com/fpco/stackage/issues/443
|
||||
#- diagrams-builder
|
||||
#- diagrams-haddock
|
||||
|
||||
- diagrams-contrib
|
||||
- diagrams-core
|
||||
- diagrams-haddock
|
||||
- diagrams-lib
|
||||
- diagrams-postscript
|
||||
- diagrams-svg
|
||||
@ -332,6 +341,8 @@ packages:
|
||||
- JuicyPixels
|
||||
- FontyFruity
|
||||
- Rasterific
|
||||
- svg-tree
|
||||
- rasterific-svg
|
||||
|
||||
"Patrick Brisbin":
|
||||
- gravatar
|
||||
@ -363,15 +374,20 @@ packages:
|
||||
- tardis
|
||||
- lens-family-th
|
||||
|
||||
"Daniel Díaz <dhelta.diaz@gmail.com>":
|
||||
"Daniel Díaz dhelta.diaz@gmail.com @Daniel-Diaz":
|
||||
- HaTeX
|
||||
- matrix
|
||||
- binary-list
|
||||
- haskintex
|
||||
- post-mess-age
|
||||
- include-file
|
||||
|
||||
"Gabriel Gonzalez <Gabriel439@gmail.com>":
|
||||
- pipes
|
||||
- pipes-parse
|
||||
- pipes-concurrency
|
||||
- pipes-safe
|
||||
- turtle
|
||||
|
||||
"Chris Allen <cma@bitemyapp.com>":
|
||||
- bloodhound
|
||||
@ -383,9 +399,12 @@ packages:
|
||||
- fay-jquery
|
||||
- fay-text
|
||||
- fay-uri
|
||||
- fclabels
|
||||
- snaplet-fay
|
||||
|
||||
"Sebastiaan Visser <haskell@fvisser.nl>":
|
||||
- clay
|
||||
- fclabels
|
||||
|
||||
"Rodrigo Setti <rodrigosetti@gmail.com>":
|
||||
- messagepack
|
||||
- messagepack-rpc
|
||||
@ -418,10 +437,7 @@ packages:
|
||||
- amqp
|
||||
- curl
|
||||
- generics-sop
|
||||
|
||||
# https://github.com/fpco/stackage/issues/341
|
||||
- haskell-names < 0.5
|
||||
|
||||
- haskell-names
|
||||
- haskell-packages
|
||||
- heredoc
|
||||
- hse-cpp
|
||||
@ -455,6 +471,8 @@ packages:
|
||||
- circle-packing
|
||||
- arbtt
|
||||
- ghc-heap-view
|
||||
- tttool
|
||||
- gipeda
|
||||
|
||||
"Aditya Bhargava <adit@adit.io":
|
||||
- HandsomeSoup
|
||||
@ -494,9 +512,9 @@ packages:
|
||||
- code-builder
|
||||
- fay-builder
|
||||
- generic-aeson
|
||||
- generic-xmlpickler
|
||||
- hxt-pickle-utils
|
||||
- imagesize-conduit
|
||||
- imagesize-conduit
|
||||
- json-schema
|
||||
- multipart
|
||||
- regular-xmlpickler
|
||||
@ -509,8 +527,6 @@ packages:
|
||||
- rest-types
|
||||
- rest-wai
|
||||
- tostring
|
||||
- tostring
|
||||
- uri-encode
|
||||
- uri-encode
|
||||
|
||||
"Simon Michael <simon@joyful.com>":
|
||||
@ -520,7 +536,10 @@ packages:
|
||||
- io-manager
|
||||
|
||||
"Dimitri Sabadie <dimitri.sabadie@gmail.com":
|
||||
# https://github.com/fpco/stackage/pull/461#issuecomment-76914158
|
||||
# - al
|
||||
- monad-journal
|
||||
- smoothie
|
||||
|
||||
"Thomas Schilling <nominolo@googlemail.com>":
|
||||
- ghc-syb-utils
|
||||
@ -565,6 +584,7 @@ packages:
|
||||
- haddock-api
|
||||
- here
|
||||
- hlibgit2
|
||||
- gitlib-libgit2
|
||||
- hostname-validate
|
||||
- interpolatedstring-perl6
|
||||
- iproute
|
||||
@ -603,14 +623,18 @@ packages:
|
||||
- Spock
|
||||
- Spock-digestive
|
||||
- Spock-worker
|
||||
- users
|
||||
- users-test
|
||||
- users-postgresql-simple
|
||||
|
||||
"Joey Eremondi <joey@eremondi.com>":
|
||||
- aeson-pretty
|
||||
- digest
|
||||
- elm-build-lib
|
||||
- elm-compiler
|
||||
# See: https://github.com/elm-lang/elm-compiler/commit/e714001a928b3834b62555fc350909c95d380ef4
|
||||
#- elm-build-lib
|
||||
#- elm-compiler
|
||||
- elm-core-sources
|
||||
- elm-package
|
||||
#- elm-package
|
||||
- language-glsl
|
||||
- prettyclass
|
||||
- QuasiText
|
||||
@ -632,6 +656,11 @@ packages:
|
||||
"Samplecount stefan@samplecount.com @kaoskorobase":
|
||||
- shake-language-c
|
||||
|
||||
"Marcin Mrotek <marcin.jan.mrotek@gmail.com>":
|
||||
- diagrams-hsqml
|
||||
- type-list
|
||||
- vinyl-utils
|
||||
|
||||
"Marcin Mrotek <marcin.jan.mrotek@gmail.com>":
|
||||
- type-list
|
||||
|
||||
@ -672,49 +701,170 @@ packages:
|
||||
"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
|
||||
|
||||
"Adam C. Foltzer acfoltzer@galois.com @acfoltzer":
|
||||
- cryptol
|
||||
- gitrev
|
||||
|
||||
"Luke Taylor tekul.hs@gmail.com @tekul":
|
||||
- jose-jwt
|
||||
|
||||
"Brendan Hay brendan.g.hay@gmail.com @brendanhay":
|
||||
- amazonka
|
||||
- amazonka-core
|
||||
- amazonka-autoscaling
|
||||
- amazonka-cloudformation
|
||||
- amazonka-cloudfront
|
||||
- amazonka-cloudhsm
|
||||
- amazonka-cloudsearch-domains
|
||||
- amazonka-cloudsearch
|
||||
- amazonka-cloudtrail
|
||||
- amazonka-cloudwatch-logs
|
||||
- amazonka-cloudwatch
|
||||
- amazonka-codedeploy
|
||||
- amazonka-cognito-identity
|
||||
- amazonka-cognito-sync
|
||||
- amazonka-config
|
||||
- amazonka-datapipeline
|
||||
- amazonka-directconnect
|
||||
- amazonka-dynamodb
|
||||
- amazonka-ec2
|
||||
- amazonka-ecs
|
||||
- amazonka-elasticache
|
||||
- amazonka-elasticbeanstalk
|
||||
- amazonka-elastictranscoder
|
||||
- amazonka-elb
|
||||
- amazonka-emr
|
||||
- amazonka-glacier
|
||||
- amazonka-iam
|
||||
- amazonka-importexport
|
||||
- amazonka-kinesis
|
||||
- amazonka-kms
|
||||
- amazonka-lambda
|
||||
- amazonka-opsworks
|
||||
- amazonka-rds
|
||||
- amazonka-redshift
|
||||
- amazonka-route53-domains
|
||||
- amazonka-route53
|
||||
- amazonka-s3
|
||||
- amazonka-sdb
|
||||
- amazonka-ses
|
||||
- amazonka-sns
|
||||
- amazonka-sqs
|
||||
- amazonka-ssm
|
||||
- amazonka-storagegateway
|
||||
- amazonka-sts
|
||||
- amazonka-support
|
||||
- amazonka-swf
|
||||
- ede
|
||||
- pagerduty
|
||||
- semver
|
||||
- text-manipulate
|
||||
|
||||
"Nick Partridge nkpart@gmail.com @nkpart":
|
||||
- cabal-file-th
|
||||
|
||||
"Gershom Bazerman <gershomb@gmail.com> @gbaz":
|
||||
- jmacro
|
||||
- jmacro-rpc
|
||||
- jmacro-rpc-happstack
|
||||
- jmacro-rpc-snap
|
||||
- mbox
|
||||
- kmeans
|
||||
- boolsimplifier
|
||||
- cubicspline
|
||||
- maximal-cliques
|
||||
|
||||
"Alexander Bondarenko <aenor.realm@gmail.com> @wiz":
|
||||
- soap
|
||||
- soap-tls
|
||||
- soap-openssl
|
||||
|
||||
"Stackage upper bounds":
|
||||
# GHC 7.8 uppdate bound
|
||||
- haddock-api < 2.16
|
||||
- haddock-library < 1.2
|
||||
- hdocs < 0.4.2
|
||||
|
||||
# Force a specific version that's compatible with transformers 0.3
|
||||
- transformers-compat == 0.3.3.3
|
||||
|
||||
# https://github.com/fpco/stackage/issues/291
|
||||
- random < 1.0.1.3
|
||||
|
||||
# https://github.com/fpco/stackage/issues/370
|
||||
- monad-control < 1
|
||||
- lifted-async < 0.3
|
||||
- scotty < 0.9.1
|
||||
- hoauth2 < 0.4.4
|
||||
|
||||
# https://github.com/fpco/stackage/issues/389
|
||||
- lens < 4.7
|
||||
|
||||
# https://github.com/fpco/stackage/issues/390
|
||||
# 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/398
|
||||
- monoid-subclasses < 0.4
|
||||
|
||||
# https://github.com/fpco/stackage/issues/401
|
||||
- happstack-server < 7.4
|
||||
|
||||
# https://github.com/fpco/stackage/issues/402
|
||||
- vector-space < 0.9
|
||||
|
||||
# https://github.com/fpco/stackage/issues/407
|
||||
- HStringTemplate < 0.8
|
||||
|
||||
# https://github.com/fpco/stackage/issues/410
|
||||
- elm-package < 0.4
|
||||
|
||||
# https://github.com/fpco/lts-haskell/issues/5
|
||||
- ChasingBottoms < 1.3.0.10 || > 1.3.0.10
|
||||
- transformers-compat == 0.4.0.3
|
||||
|
||||
# https://github.com/fpco/stackage/issues/415
|
||||
- hackage-db < 1.12
|
||||
|
||||
# https://github.com/fpco/stackage/issues/442
|
||||
- blaze-builder < 0.4
|
||||
|
||||
# https://github.com/fpco/stackage/issues/487
|
||||
- blaze-markup < 0.7
|
||||
- blaze-html < 0.8
|
||||
|
||||
# https://github.com/fpco/stackage/issues/467
|
||||
- lens < 4.8
|
||||
|
||||
# https://github.com/fpco/stackage/issues/476
|
||||
- vector-space < 0.10
|
||||
|
||||
# https://github.com/fpco/stackage/issues/479
|
||||
- QuickCheck < 2.8
|
||||
|
||||
# https://github.com/fpco/stackage/issues/483
|
||||
- rethinkdb-client-driver < 0.0.15
|
||||
|
||||
# https://github.com/fpco/stackage/issues/494
|
||||
- criterion < 1.1
|
||||
|
||||
# https://github.com/fpco/stackage/issues/497
|
||||
- primitive < 0.6
|
||||
|
||||
# https://github.com/jgm/pandoc/issues/2036
|
||||
- highlighting-kate < 0.5.13
|
||||
|
||||
# https://github.com/bos/mwc-random/issues/45
|
||||
- mwc-random < 0.13.3.1
|
||||
|
||||
# Package flags are applied to individual packages, and override the values of
|
||||
# global-flags
|
||||
package-flags:
|
||||
@ -747,6 +897,10 @@ package-flags:
|
||||
# GHC 7.10 remove
|
||||
aeson:
|
||||
old-locale: true
|
||||
tttool:
|
||||
old-locale: true
|
||||
amazonka-core:
|
||||
old-locale: true
|
||||
|
||||
hxt:
|
||||
network-uri: true
|
||||
@ -761,6 +915,17 @@ package-flags:
|
||||
text:
|
||||
integer-simple: false
|
||||
|
||||
tar:
|
||||
old-time: false
|
||||
|
||||
mtl-compat:
|
||||
two-point-one: true
|
||||
two-point-two: false
|
||||
|
||||
# https://github.com/fpco/stackage/pull/482#issuecomment-83635207
|
||||
jose-jwt:
|
||||
doctest: false
|
||||
|
||||
# By skipping a test suite, we do not pull in the build dependencies
|
||||
skipped-tests:
|
||||
- ReadArgs # old version of hspec
|
||||
@ -888,9 +1053,6 @@ expected-test-failures:
|
||||
# https://github.com/BioHaskell/octree/issues/4
|
||||
- Octree
|
||||
|
||||
# https://github.com/goldfirere/th-desugar/issues/12
|
||||
- th-desugar
|
||||
|
||||
# https://github.com/jmillikin/haskell-filesystem/issues/3
|
||||
- system-filepath
|
||||
|
||||
@ -942,9 +1104,6 @@ expected-test-failures:
|
||||
# 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
|
||||
|
||||
@ -957,20 +1116,61 @@ expected-test-failures:
|
||||
# https://github.com/bos/wreq/issues/53
|
||||
- wreq
|
||||
|
||||
# https://github.com/vincenthz/tasty-kat/issues/1
|
||||
- tasty-kat
|
||||
# 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
|
||||
|
||||
# Tests not reliable on non-Windows systems
|
||||
- nsis
|
||||
|
||||
# Haddocks which are expected to fail. Same concept as expected test failures.
|
||||
expected-haddock-failures:
|
||||
# https://github.com/acw/bytestring-progress/issues/4
|
||||
- bytestring-progress
|
||||
|
||||
# https://github.com/ekmett/gl/issues/4
|
||||
- gl
|
||||
|
||||
# https://github.com/leventov/yarr/issues/5
|
||||
- yarr
|
||||
|
||||
# https://github.com/wereHamster/rethinkdb-client-driver/issues/1
|
||||
- rethinkdb-client-driver
|
||||
|
||||
# Requires build before haddock, which doesn't always happen in incremental
|
||||
# builds. Could consider special-casing this requirement.
|
||||
- gtk
|
||||
|
||||
# Benchmarks which should not be built. Note that Stackage does *not* generally
|
||||
# build benchmarks. The difference here will be whether dependencies for these
|
||||
# benchmarks are included or not.
|
||||
@ -997,7 +1197,12 @@ skipped-benchmarks:
|
||||
# sometimes falls out-of-sync on hasql-postgres
|
||||
- hasql
|
||||
|
||||
skipped-profiling: []
|
||||
# https://github.com/fpco/stackage/issues/488
|
||||
- uuid-types
|
||||
|
||||
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
|
||||
# be pinged on failure. If no value is specified here, then the owning account
|
||||
|
||||
847
cabal.config
847
cabal.config
@ -1,847 +0,0 @@
|
||||
-- Stackage snapshot from: http://www.stackage.org/snapshot/nightly-2014-12-24
|
||||
-- Please place this file next to your .cabal file as cabal.config
|
||||
-- To only use tested packages, uncomment the following line:
|
||||
-- remote-repo: stackage-nightly-2014-12-24:http://www.stackage.org/snapshot/nightly-2014-12-24
|
||||
constraints: abstract-deque ==0.3,
|
||||
abstract-par ==0.3.3,
|
||||
accelerate ==0.15.0.0,
|
||||
ace ==0.6,
|
||||
action-permutations ==0.0.0.1,
|
||||
active ==0.1.0.17,
|
||||
AC-Vector ==2.3.2,
|
||||
ad ==4.2.1.1,
|
||||
adjunctions ==4.2,
|
||||
aeson ==0.8.0.2,
|
||||
aeson-pretty ==0.7.2,
|
||||
aeson-qq ==0.7.4,
|
||||
aeson-utils ==0.2.2.1,
|
||||
alarmclock ==0.2.0.5,
|
||||
alex ==3.1.3,
|
||||
amqp ==0.10.1,
|
||||
ansi-terminal ==0.6.2.1,
|
||||
ansi-wl-pprint ==0.6.7.1,
|
||||
appar ==0.1.4,
|
||||
approximate ==0.2.1.1,
|
||||
arbtt ==0.8.1.4,
|
||||
arithmoi ==0.4.1.1,
|
||||
array installed,
|
||||
arrow-list ==0.6.1.5,
|
||||
asn1-data ==0.7.1,
|
||||
asn1-encoding ==0.9.0,
|
||||
asn1-parse ==0.9.0,
|
||||
asn1-types ==0.3.0,
|
||||
async ==2.0.2,
|
||||
atto-lisp ==0.2.2,
|
||||
attoparsec ==0.12.1.2,
|
||||
attoparsec-conduit ==1.1.0,
|
||||
attoparsec-enumerator ==0.3.3,
|
||||
attoparsec-expr ==0.1.1.1,
|
||||
authenticate ==1.3.2.11,
|
||||
auto-update ==0.1.2.1,
|
||||
aws ==0.11,
|
||||
bake ==0.2,
|
||||
bank-holidays-england ==0.1.0.1,
|
||||
barecheck ==0.2.0.6,
|
||||
base16-bytestring ==0.1.1.6,
|
||||
base64-bytestring ==1.0.0.1,
|
||||
base-compat ==0.5.0,
|
||||
base-prelude ==0.1.8,
|
||||
base-unicode-symbols ==0.2.2.4,
|
||||
basic-prelude ==0.3.10,
|
||||
bifunctors ==4.2,
|
||||
binary installed,
|
||||
binary-list ==1.0.1.0,
|
||||
bindings-DSL ==1.0.21,
|
||||
bioace ==0.0.1,
|
||||
bioalign ==0.0.5,
|
||||
biocore ==0.3.1,
|
||||
biofasta ==0.0.3,
|
||||
biofastq ==0.1,
|
||||
biophd ==0.0.5,
|
||||
biopsl ==0.4,
|
||||
biosff ==0.3.7.1,
|
||||
bits ==0.4,
|
||||
BlastHTTP ==1.0.1,
|
||||
blastxml ==0.3.2,
|
||||
blaze-builder ==0.3.3.4,
|
||||
blaze-builder-enumerator ==0.2.0.6,
|
||||
blaze-html ==0.7.0.3,
|
||||
blaze-markup ==0.6.1.1,
|
||||
blaze-svg ==0.3.4,
|
||||
blaze-textual ==0.2.0.9,
|
||||
BlogLiterately ==0.7.1.7,
|
||||
BlogLiterately-diagrams ==0.1.4.3,
|
||||
bloodhound ==0.5.0.1,
|
||||
bmp ==1.2.5.2,
|
||||
Boolean ==0.2.3,
|
||||
bool-extras ==0.4.0,
|
||||
bound ==1.0.4,
|
||||
BoundedChan ==1.0.3.0,
|
||||
bson ==0.3.1,
|
||||
bumper ==0.6.0.2,
|
||||
byteable ==0.1.1,
|
||||
bytedump ==1.0,
|
||||
byteorder ==1.0.4,
|
||||
bytes ==0.14.1.2,
|
||||
bytestring installed,
|
||||
bytestring-builder ==0.10.4.0.1,
|
||||
bytestring-lexing ==0.4.3.2,
|
||||
bytestring-mmap ==0.2.2,
|
||||
bytestring-progress ==1.0.3,
|
||||
bytestring-trie ==0.2.4,
|
||||
bzlib ==0.5.0.4,
|
||||
bzlib-conduit ==0.2.1.3,
|
||||
c2hs ==0.20.1,
|
||||
Cabal installed,
|
||||
cabal-install ==1.18.0.6,
|
||||
cabal-src ==0.2.5,
|
||||
cairo ==0.13.0.5,
|
||||
case-insensitive ==1.2.0.3,
|
||||
cases ==0.1.2,
|
||||
cassava ==0.4.2.1,
|
||||
cautious-file ==1.0.2,
|
||||
cereal ==0.4.1.0,
|
||||
cereal-conduit ==0.7.2.3,
|
||||
certificate ==1.3.9,
|
||||
charset ==0.3.7,
|
||||
Chart ==1.3.2,
|
||||
Chart-diagrams ==1.3.2,
|
||||
ChasingBottoms ==1.3.0.8,
|
||||
check-email ==1.0,
|
||||
checkers ==0.4.1,
|
||||
chell ==0.4,
|
||||
chell-quickcheck ==0.2.4,
|
||||
chunked-data ==0.1.0.1,
|
||||
cipher-aes ==0.2.9,
|
||||
cipher-blowfish ==0.0.3,
|
||||
cipher-camellia ==0.0.2,
|
||||
cipher-des ==0.0.6,
|
||||
cipher-rc4 ==0.1.4,
|
||||
circle-packing ==0.1.0.3,
|
||||
classy-prelude ==0.10.2,
|
||||
classy-prelude-conduit ==0.10.2,
|
||||
classy-prelude-yesod ==0.10.2,
|
||||
clientsession ==0.9.1.1,
|
||||
clock ==0.4.1.3,
|
||||
cmdargs ==0.10.12,
|
||||
code-builder ==0.1.3,
|
||||
colour ==2.3.3,
|
||||
comonad ==4.2.2,
|
||||
comonads-fd ==4.0,
|
||||
comonad-transformers ==4.0,
|
||||
compdata ==0.9,
|
||||
compensated ==0.6.1,
|
||||
composition ==1.0.1.0,
|
||||
compressed ==3.10,
|
||||
concatenative ==1.0.1,
|
||||
concurrent-extra ==0.7.0.9,
|
||||
concurrent-supply ==0.1.7,
|
||||
cond ==0.4.1.1,
|
||||
conduit ==1.2.3.1,
|
||||
conduit-combinators ==0.3.0.5,
|
||||
conduit-extra ==1.1.5.1,
|
||||
configurator ==0.3.0.0,
|
||||
connection ==0.2.3,
|
||||
constraints ==0.4.1.1,
|
||||
containers installed,
|
||||
containers-unicode-symbols ==0.3.1.1,
|
||||
contravariant ==1.2,
|
||||
control-monad-free ==0.5.3,
|
||||
control-monad-loop ==0.1,
|
||||
convertible ==1.1.0.0,
|
||||
cookie ==0.4.1.4,
|
||||
courier ==0.1.0.15,
|
||||
cpphs ==1.18.6,
|
||||
cprng-aes ==0.6.1,
|
||||
cpu ==0.1.2,
|
||||
criterion ==1.0.2.0,
|
||||
crypto-api ==0.13.2,
|
||||
cryptocipher ==0.6.2,
|
||||
crypto-cipher-tests ==0.0.11,
|
||||
crypto-cipher-types ==0.0.9,
|
||||
cryptohash ==0.11.6,
|
||||
cryptohash-conduit ==0.1.1,
|
||||
cryptohash-cryptoapi ==0.1.3,
|
||||
crypto-numbers ==0.2.3,
|
||||
crypto-pubkey ==0.2.6,
|
||||
crypto-pubkey-types ==0.4.2.3,
|
||||
crypto-random ==0.0.8,
|
||||
crypto-random-api ==0.2.0,
|
||||
css-text ==0.1.2.1,
|
||||
csv ==0.1.2,
|
||||
csv-conduit ==0.6.3,
|
||||
curl ==1.3.8,
|
||||
data-accessor ==0.2.2.6,
|
||||
data-accessor-mtl ==0.2.0.4,
|
||||
data-binary-ieee754 ==0.4.4,
|
||||
data-default ==0.5.3,
|
||||
data-default-class ==0.0.1,
|
||||
data-default-instances-base ==0.0.1,
|
||||
data-default-instances-containers ==0.0.1,
|
||||
data-default-instances-dlist ==0.0.1,
|
||||
data-default-instances-old-locale ==0.0.1,
|
||||
data-inttrie ==0.1.0,
|
||||
data-lens-light ==0.1.2.1,
|
||||
data-memocombinators ==0.5.1,
|
||||
data-reify ==0.6,
|
||||
DAV ==1.0.3,
|
||||
deepseq installed,
|
||||
deepseq-generics ==0.1.1.2,
|
||||
derive ==2.5.18,
|
||||
diagrams ==1.2,
|
||||
diagrams-builder ==0.6.0.2,
|
||||
diagrams-cairo ==1.2.0.4,
|
||||
diagrams-contrib ==1.1.2.4,
|
||||
diagrams-core ==1.2.0.4,
|
||||
diagrams-haddock ==0.2.2.12,
|
||||
diagrams-lib ==1.2.0.7,
|
||||
diagrams-postscript ==1.1.0.3,
|
||||
diagrams-svg ==1.1.0.3,
|
||||
Diff ==0.3.0,
|
||||
digest ==0.0.1.2,
|
||||
digestive-functors ==0.7.1.3,
|
||||
dimensional ==0.13.0.1,
|
||||
directory installed,
|
||||
directory-tree ==0.12.0,
|
||||
direct-sqlite ==2.3.14,
|
||||
distributed-process ==0.5.3,
|
||||
distributed-process-async ==0.2.0,
|
||||
distributed-process-client-server ==0.1.1,
|
||||
distributed-process-execution ==0.1.0,
|
||||
distributed-process-extras ==0.1.1,
|
||||
distributed-process-simplelocalnet ==0.2.2.0,
|
||||
distributed-process-supervisor ==0.1.1,
|
||||
distributed-process-task ==0.1.0,
|
||||
distributed-static ==0.3.1.0,
|
||||
distributive ==0.4.4,
|
||||
djinn-ghc ==0.0.2.2,
|
||||
djinn-lib ==0.0.1.2,
|
||||
dlist ==0.7.1,
|
||||
dlist-instances ==0.1,
|
||||
doctest ==0.9.11.1,
|
||||
double-conversion ==2.0.1.0,
|
||||
dual-tree ==0.2.0.5,
|
||||
easy-file ==0.2.0,
|
||||
either ==4.3.2.1,
|
||||
elm-build-lib ==0.14.0.0,
|
||||
elm-compiler ==0.14,
|
||||
elm-core-sources ==1.0.0,
|
||||
elm-package ==0.2.2,
|
||||
email-validate ==2.0.1,
|
||||
enclosed-exceptions ==1.0.1,
|
||||
entropy ==0.3.4.1,
|
||||
enumerator ==0.4.20,
|
||||
eq ==4.0.3,
|
||||
erf ==2.0.0.0,
|
||||
errorcall-eq-instance ==0.1.0,
|
||||
errors ==1.4.7,
|
||||
ersatz ==0.2.6.1,
|
||||
esqueleto ==2.1.2.1,
|
||||
exceptions ==0.6.1,
|
||||
exception-transformers ==0.3.0.4,
|
||||
executable-path ==0.0.3,
|
||||
ex-pool ==0.2,
|
||||
extensible-exceptions ==0.1.1.4,
|
||||
extra ==1.0,
|
||||
failure ==0.2.0.3,
|
||||
fast-logger ==2.2.3,
|
||||
fay ==0.21.2.1,
|
||||
fay-base ==0.19.4.1,
|
||||
fay-builder ==0.2.0.1,
|
||||
fay-dom ==0.5,
|
||||
fay-jquery ==0.6.0.2,
|
||||
fay-text ==0.3.2,
|
||||
fay-uri ==0.2.0.0,
|
||||
fb ==1.0.7,
|
||||
fb-persistent ==0.3.4,
|
||||
fclabels ==2.0.2,
|
||||
FenwickTree ==0.1.1,
|
||||
fgl ==5.5.0.1,
|
||||
file-embed ==0.0.7,
|
||||
file-location ==0.4.5.3,
|
||||
filemanip ==0.3.6.2,
|
||||
filepath installed,
|
||||
fingertree ==0.1.0.0,
|
||||
fixed ==0.2.1,
|
||||
fixed-list ==0.1.5,
|
||||
flexible-defaults ==0.0.1.1,
|
||||
focus ==0.1.3,
|
||||
foldl ==1.0.7,
|
||||
force-layout ==0.3.0.8,
|
||||
foreign-store ==0.1,
|
||||
formatting ==6.0.0,
|
||||
fpco-api ==1.2.0.4,
|
||||
free ==4.10.0.1,
|
||||
freenect ==1.2,
|
||||
frisby ==0.2,
|
||||
fsnotify ==0.1.0.3,
|
||||
fuzzcheck ==0.1.1,
|
||||
gd ==3000.7.3,
|
||||
generic-aeson ==0.2.0.2,
|
||||
generic-deriving ==1.6.3,
|
||||
generics-sop ==0.1.0.4,
|
||||
ghc-heap-view ==0.5.3,
|
||||
ghcid ==0.3.3,
|
||||
ghc-mod ==5.2.1.1,
|
||||
ghc-mtl ==1.2.1.0,
|
||||
ghc-paths ==0.1.0.9,
|
||||
ghc-prim installed,
|
||||
ghc-syb-utils ==0.2.2,
|
||||
gio ==0.13.0.3,
|
||||
git-embed ==0.1.0,
|
||||
gl ==0.6.2,
|
||||
glib ==0.13.0.6,
|
||||
Glob ==0.7.5,
|
||||
GLURaw ==1.4.0.1,
|
||||
GLUT ==2.5.1.1,
|
||||
graph-core ==0.2.1.0,
|
||||
graphs ==0.5.0.1,
|
||||
graphviz ==2999.17.0.1,
|
||||
gravatar ==0.6,
|
||||
groundhog ==0.7.0.1,
|
||||
groundhog-mysql ==0.7.0.1,
|
||||
groundhog-postgresql ==0.7.0.1,
|
||||
groundhog-sqlite ==0.7.0.1,
|
||||
groundhog-th ==0.7.0,
|
||||
groupoids ==4.0,
|
||||
groups ==0.4.0.0,
|
||||
gtk ==0.13.3,
|
||||
gtk2hs-buildtools ==0.13.0.3,
|
||||
haddock-api ==2.15.0.1,
|
||||
haddock-library ==1.1.1,
|
||||
half ==0.2.0.1,
|
||||
HandsomeSoup ==0.3.5,
|
||||
happstack-server ==7.3.9,
|
||||
happy ==1.19.4,
|
||||
hashable ==1.2.3.1,
|
||||
hashable-extras ==0.2.0.1,
|
||||
hashmap ==1.3.0.1,
|
||||
hashtables ==1.2.0.1,
|
||||
haskeline installed,
|
||||
haskell2010 installed,
|
||||
haskell98 installed,
|
||||
haskell-lexer ==1.0,
|
||||
haskell-names ==0.4.1,
|
||||
haskell-packages ==0.2.4.3,
|
||||
haskell-src ==1.0.1.6,
|
||||
haskell-src-exts ==1.16.0.1,
|
||||
haskell-src-meta ==0.6.0.8,
|
||||
hasql ==0.4.1,
|
||||
hasql-backend ==0.2.2,
|
||||
hasql-postgres ==0.9.1,
|
||||
hastache ==0.6.1,
|
||||
HaTeX ==3.16.0.0,
|
||||
HaXml ==1.24.1,
|
||||
haxr ==3000.10.3.1,
|
||||
HCodecs ==0.5,
|
||||
hdaemonize ==0.5.0.0,
|
||||
hdevtools ==0.1.0.6,
|
||||
heaps ==0.3.1,
|
||||
hebrew-time ==0.1.1,
|
||||
heist ==0.14.0.1,
|
||||
here ==1.2.6,
|
||||
heredoc ==0.2.0.0,
|
||||
highlighting-kate ==0.5.11.1,
|
||||
hinotify ==0.3.7,
|
||||
hint ==0.4.2.1,
|
||||
histogram-fill ==0.8.3.0,
|
||||
hit ==0.6.2,
|
||||
hjsmin ==0.1.4.7,
|
||||
hledger ==0.23.3,
|
||||
hledger-lib ==0.23.3,
|
||||
hlibgit2 ==0.18.0.13,
|
||||
hlint ==1.9.13,
|
||||
hmatrix ==0.16.1.2,
|
||||
hmatrix-gsl ==0.16.0.2,
|
||||
holy-project ==0.1.1.1,
|
||||
hoogle ==4.2.36,
|
||||
hoopl installed,
|
||||
hOpenPGP ==1.11,
|
||||
hopenpgp-tools ==0.13,
|
||||
hostname ==1.0,
|
||||
hostname-validate ==1.0.0,
|
||||
hourglass ==0.2.6,
|
||||
hpc installed,
|
||||
hPDB ==1.2.0,
|
||||
hPDB-examples ==1.1.2,
|
||||
hs-bibutils ==5.5,
|
||||
hscolour ==1.20.3,
|
||||
hse-cpp ==0.1,
|
||||
hslogger ==1.2.6,
|
||||
hslua ==0.3.13,
|
||||
hspec ==2.1.2,
|
||||
hspec2 ==0.6.1,
|
||||
hspec-core ==2.1.2,
|
||||
hspec-discover ==2.1.2,
|
||||
hspec-expectations ==0.6.1,
|
||||
hspec-meta ==2.0.0,
|
||||
hspec-wai ==0.6.2,
|
||||
hspec-wai-json ==0.6.0,
|
||||
HStringTemplate ==0.7.3,
|
||||
hsyslog ==2.0,
|
||||
HTF ==0.12.2.3,
|
||||
html ==1.0.1.2,
|
||||
html-conduit ==1.1.1.1,
|
||||
HTTP ==4000.2.19,
|
||||
http-client ==0.4.6.1,
|
||||
http-client-tls ==0.2.2,
|
||||
http-conduit ==2.1.5,
|
||||
http-date ==0.0.4,
|
||||
http-reverse-proxy ==0.4.1.2,
|
||||
http-types ==0.8.5,
|
||||
HUnit ==1.2.5.2,
|
||||
hweblib ==0.6.3,
|
||||
hxt ==9.3.1.10,
|
||||
hxt-charproperties ==9.2.0.0,
|
||||
hxt-http ==9.1.5,
|
||||
hxt-pickle-utils ==0.1.0.2,
|
||||
hxt-regex-xmlschema ==9.2.0,
|
||||
hxt-relaxng ==9.1.5.1,
|
||||
hxt-unicode ==9.0.2.2,
|
||||
hybrid-vectors ==0.1.2,
|
||||
hyphenation ==0.4,
|
||||
idna ==0.3.0,
|
||||
ieee754 ==0.7.4,
|
||||
imagesize-conduit ==1.0.0.4,
|
||||
immortal ==0.2,
|
||||
incremental-parser ==0.2.3.3,
|
||||
indents ==0.3.3,
|
||||
ini ==0.2.2,
|
||||
integer-gmp installed,
|
||||
integration ==0.2.0.1,
|
||||
interpolate ==0.1.0,
|
||||
interpolatedstring-perl6 ==0.9.0,
|
||||
intervals ==0.7.0.1,
|
||||
io-choice ==0.0.5,
|
||||
io-manager ==0.1.0.2,
|
||||
io-memoize ==1.1.1.0,
|
||||
iproute ==1.3.1,
|
||||
iterable ==3.0,
|
||||
ixset ==1.0.6,
|
||||
js-flot ==0.8.3,
|
||||
js-jquery ==1.11.1,
|
||||
json-schema ==0.7.3.0,
|
||||
JuicyPixels ==3.1.7.1,
|
||||
JuicyPixels-repa ==0.7,
|
||||
kan-extensions ==4.1.1,
|
||||
kdt ==0.2.2,
|
||||
keter ==1.3.7.1,
|
||||
keys ==3.10.1,
|
||||
kure ==2.4.10,
|
||||
language-c ==0.4.7,
|
||||
language-ecmascript ==0.16.2,
|
||||
language-glsl ==0.1.1,
|
||||
language-haskell-extract ==0.2.4,
|
||||
language-java ==0.2.7,
|
||||
language-javascript ==0.5.13,
|
||||
lazy-csv ==0.5,
|
||||
lca ==0.2.4,
|
||||
lens ==4.6.0.1,
|
||||
lens-aeson ==1.0.0.3,
|
||||
lens-family-th ==0.4.0.0,
|
||||
lhs2tex ==1.18.1,
|
||||
libgit ==0.3.0,
|
||||
libnotify ==0.1.1.0,
|
||||
lifted-async ==0.2.0.2,
|
||||
lifted-base ==0.2.3.3,
|
||||
linear ==1.15.5,
|
||||
linear-accelerate ==0.2,
|
||||
list-t ==0.3.1,
|
||||
loch-th ==0.2.1,
|
||||
log-domain ==0.9.3,
|
||||
logfloat ==0.12.1,
|
||||
logict ==0.6.0.2,
|
||||
loop ==0.2.0,
|
||||
lucid ==2.5,
|
||||
machines ==0.4.1,
|
||||
mandrill ==0.1.1.0,
|
||||
map-syntax ==0.2,
|
||||
markdown ==0.1.13,
|
||||
markdown-unlit ==0.2.0.1,
|
||||
math-functions ==0.1.5.2,
|
||||
matrix ==0.3.4.0,
|
||||
MaybeT ==0.1.2,
|
||||
MemoTrie ==0.6.2,
|
||||
mersenne-random-pure64 ==0.2.0.4,
|
||||
messagepack ==0.3.0,
|
||||
messagepack-rpc ==0.1.0.3,
|
||||
mime-mail ==0.4.6.2,
|
||||
mime-mail-ses ==0.3.2.1,
|
||||
mime-types ==0.1.0.5,
|
||||
missing-foreign ==0.1.1,
|
||||
MissingH ==1.3.0.1,
|
||||
mmap ==0.5.9,
|
||||
mmorph ==1.0.4,
|
||||
MonadCatchIO-transformers ==0.3.1.3,
|
||||
monad-control ==0.3.3.0,
|
||||
monad-coroutine ==0.8.0.1,
|
||||
monadcryptorandom ==0.6.1,
|
||||
monad-extras ==0.5.9,
|
||||
monadic-arrays ==0.2.1.3,
|
||||
monad-journal ==0.6.0.2,
|
||||
monad-logger ==0.3.11.1,
|
||||
monad-loops ==0.4.2.1,
|
||||
monad-par ==0.3.4.7,
|
||||
monad-parallel ==0.7.1.3,
|
||||
monad-par-extras ==0.3.3,
|
||||
monad-primitive ==0.1,
|
||||
monad-products ==4.0.0.1,
|
||||
MonadPrompt ==1.0.0.5,
|
||||
MonadRandom ==0.3.0.1,
|
||||
monad-st ==0.2.4,
|
||||
monads-tf ==0.1.0.2,
|
||||
mongoDB ==2.0.3,
|
||||
monoid-extras ==0.3.3.5,
|
||||
monoid-subclasses ==0.3.6.2,
|
||||
mono-traversable ==0.7.0,
|
||||
mtl ==2.1.3.1,
|
||||
mtlparse ==0.1.2,
|
||||
mtl-prelude ==1.0.1,
|
||||
multimap ==1.2.1,
|
||||
multipart ==0.1.2,
|
||||
MusicBrainz ==0.2.2,
|
||||
mwc-random ==0.13.2.2,
|
||||
mysql ==0.1.1.7,
|
||||
mysql-simple ==0.2.2.4,
|
||||
nanospec ==0.2.0,
|
||||
nats ==1,
|
||||
neat-interpolation ==0.2.2,
|
||||
nettle ==0.1.0,
|
||||
network ==2.6.0.2,
|
||||
network-conduit-tls ==1.1.0.2,
|
||||
network-info ==0.2.0.5,
|
||||
network-multicast ==0.0.11,
|
||||
network-simple ==0.4.0.2,
|
||||
network-transport ==0.4.1.0,
|
||||
network-transport-tcp ==0.4.1,
|
||||
network-transport-tests ==0.2.1.0,
|
||||
network-uri ==2.6.0.1,
|
||||
newtype ==0.2,
|
||||
nsis ==0.2.4,
|
||||
numbers ==3000.2.0.1,
|
||||
numeric-extras ==0.0.3,
|
||||
NumInstances ==1.4,
|
||||
numtype ==1.1,
|
||||
Octree ==0.5.3,
|
||||
old-locale installed,
|
||||
old-time installed,
|
||||
OneTuple ==0.2.1,
|
||||
opaleye ==0.3,
|
||||
OpenGL ==2.9.2.0,
|
||||
OpenGLRaw ==1.5.0.0,
|
||||
openpgp-asciiarmor ==0.1,
|
||||
operational ==0.2.3.2,
|
||||
options ==1.2.1,
|
||||
optparse-applicative ==0.11.0.1,
|
||||
osdkeys ==0.0,
|
||||
pandoc ==1.13.2,
|
||||
pandoc-citeproc ==0.6,
|
||||
pandoc-types ==1.12.4.1,
|
||||
pango ==0.13.0.4,
|
||||
parallel ==3.2.0.5,
|
||||
parallel-io ==0.3.3,
|
||||
parseargs ==0.1.5.2,
|
||||
parsec ==3.1.7,
|
||||
parsers ==0.12.1.1,
|
||||
partial-handler ==0.1.0,
|
||||
path-pieces ==0.1.5,
|
||||
patience ==0.1.1,
|
||||
pcre-light ==0.4.0.3,
|
||||
pdfinfo ==1.5.1,
|
||||
pem ==0.2.2,
|
||||
persistent ==2.1.1.3,
|
||||
persistent-mongoDB ==2.1.2,
|
||||
persistent-mysql ==2.1.2,
|
||||
persistent-postgresql ==2.1.2,
|
||||
persistent-sqlite ==2.1.1.2,
|
||||
persistent-template ==2.1.0.1,
|
||||
phantom-state ==0.2.0.2,
|
||||
pipes ==4.1.4,
|
||||
pipes-concurrency ==2.0.2,
|
||||
pipes-parse ==3.0.2,
|
||||
placeholders ==0.1,
|
||||
pointed ==4.1.1,
|
||||
polyparse ==1.9,
|
||||
pool-conduit ==0.1.2.3,
|
||||
postgresql-binary ==0.5.0,
|
||||
postgresql-libpq ==0.9.0.1,
|
||||
postgresql-simple ==0.4.8.0,
|
||||
pqueue ==1.2.1,
|
||||
prefix-units ==0.1.0.2,
|
||||
prelude-extras ==0.4,
|
||||
present ==2.2,
|
||||
pretty installed,
|
||||
prettyclass ==1.0.0.0,
|
||||
pretty-class ==1.0.1.1,
|
||||
pretty-show ==1.6.8,
|
||||
primes ==0.2.1.0,
|
||||
primitive ==0.5.4.0,
|
||||
process installed,
|
||||
process-conduit ==1.2.0.1,
|
||||
process-extras ==0.2.0,
|
||||
product-profunctors ==0.6,
|
||||
profunctor-extras ==4.0,
|
||||
profunctors ==4.3.2,
|
||||
project-template ==0.1.4.2,
|
||||
publicsuffixlist ==0.1,
|
||||
punycode ==2.0,
|
||||
pure-io ==0.2.1,
|
||||
pureMD5 ==2.1.2.1,
|
||||
pwstore-fast ==2.4.4,
|
||||
quandl-api ==0.2.0.0,
|
||||
QuasiText ==0.1.2.5,
|
||||
QuickCheck ==2.7.6,
|
||||
quickcheck-assertions ==0.1.1,
|
||||
quickcheck-instances ==0.3.9,
|
||||
quickcheck-io ==0.1.1,
|
||||
quickpull ==0.4.0.0,
|
||||
rainbow ==0.20.0.4,
|
||||
rainbow-tests ==0.20.0.4,
|
||||
random ==1.0.1.1,
|
||||
random-fu ==0.2.6.1,
|
||||
random-shuffle ==0.0.4,
|
||||
random-source ==0.3.0.6,
|
||||
rank1dynamic ==0.2.0.1,
|
||||
raw-strings-qq ==1.0.2,
|
||||
ReadArgs ==1.2.2,
|
||||
reducers ==3.10.3,
|
||||
reflection ==1.5.1,
|
||||
regex-applicative ==0.3.0.3,
|
||||
regex-base ==0.93.2,
|
||||
regex-compat ==0.95.1,
|
||||
regex-pcre-builtin ==0.94.4.8.8.35,
|
||||
regex-posix ==0.95.2,
|
||||
regexpr ==0.5.4,
|
||||
regex-tdfa ==1.2.0,
|
||||
regex-tdfa-rc ==1.1.8.3,
|
||||
regular ==0.3.4.3,
|
||||
regular-xmlpickler ==0.2,
|
||||
rematch ==0.2.0.0,
|
||||
repa ==3.3.1.2,
|
||||
repa-algorithms ==3.3.1.2,
|
||||
repa-devil ==0.3.2.2,
|
||||
repa-io ==3.3.1.2,
|
||||
reroute ==0.2.2.1,
|
||||
resource-pool ==0.2.3.2,
|
||||
resourcet ==1.1.3.3,
|
||||
rest-client ==0.4.0.2,
|
||||
rest-core ==0.33.1.2,
|
||||
rest-gen ==0.16.1.3,
|
||||
rest-happstack ==0.2.10.3,
|
||||
rest-snap ==0.1.17.14,
|
||||
rest-stringmap ==0.2.0.2,
|
||||
rest-types ==1.11.1.1,
|
||||
rest-wai ==0.1.0.4,
|
||||
rev-state ==0.1,
|
||||
rfc5051 ==0.1.0.3,
|
||||
runmemo ==1.0.0.1,
|
||||
rvar ==0.2.0.2,
|
||||
safe ==0.3.8,
|
||||
safecopy ==0.8.3,
|
||||
scientific ==0.3.3.3,
|
||||
scotty ==0.9.0,
|
||||
scrobble ==0.2.1.1,
|
||||
securemem ==0.1.4,
|
||||
semigroupoid-extras ==4.0,
|
||||
semigroupoids ==4.2,
|
||||
semigroups ==0.16.0.1,
|
||||
sendfile ==0.7.9,
|
||||
seqloc ==0.6,
|
||||
setenv ==0.1.1.2,
|
||||
SHA ==1.6.4.1,
|
||||
shake ==0.14.2,
|
||||
shake-language-c ==0.6.3,
|
||||
shakespeare ==2.0.2.1,
|
||||
shakespeare-i18n ==1.1.0,
|
||||
shakespeare-text ==1.1.0,
|
||||
shell-conduit ==4.5,
|
||||
shelly ==1.5.6,
|
||||
silently ==1.2.4.1,
|
||||
simple-reflect ==0.3.2,
|
||||
simple-sendfile ==0.2.18,
|
||||
singletons ==1.0,
|
||||
siphash ==1.0.3,
|
||||
skein ==1.0.9.2,
|
||||
slave-thread ==0.1.5,
|
||||
smallcheck ==1.1.1,
|
||||
smtLib ==1.0.7,
|
||||
snap ==0.13.3.2,
|
||||
snap-core ==0.9.6.4,
|
||||
snaplet-fay ==0.3.3.8,
|
||||
snap-server ==0.9.4.6,
|
||||
socks ==0.5.4,
|
||||
sodium ==0.11.0.2,
|
||||
sourcemap ==0.1.3.0,
|
||||
speculation ==1.5.0.1,
|
||||
sphinx ==0.6.0.1,
|
||||
split ==0.2.2,
|
||||
Spock ==0.7.5.1,
|
||||
spoon ==0.3.1,
|
||||
sqlite-simple ==0.4.8.0,
|
||||
stateref ==0.3,
|
||||
statestack ==0.2.0.3,
|
||||
statistics ==0.13.2.1,
|
||||
statistics-linreg ==0.3,
|
||||
stm ==2.4.4,
|
||||
stm-chans ==3.0.0.2,
|
||||
stm-conduit ==2.5.2,
|
||||
stm-containers ==0.2.7,
|
||||
stm-stats ==0.2.0.0,
|
||||
storable-complex ==0.2.1,
|
||||
storable-endian ==0.2.5,
|
||||
streaming-commons ==0.1.8,
|
||||
streams ==3.2,
|
||||
strict ==0.3.2,
|
||||
stringable ==0.1.3,
|
||||
stringbuilder ==0.5.0,
|
||||
stringprep ==1.0.0,
|
||||
stringsearch ==0.3.6.5,
|
||||
stylish-haskell ==0.5.11.0,
|
||||
SVGFonts ==1.4.0.3,
|
||||
syb ==0.4.2,
|
||||
syb-with-class ==0.6.1.5,
|
||||
system-canonicalpath ==0.2.0.0,
|
||||
system-fileio ==0.3.16,
|
||||
system-filepath ==0.4.13,
|
||||
system-posix-redirect ==1.1.0.1,
|
||||
tabular ==0.2.2.5,
|
||||
tagged ==0.7.3,
|
||||
tagshare ==0.0,
|
||||
tagsoup ==0.13.3,
|
||||
tagstream-conduit ==0.5.5.3,
|
||||
tar ==0.4.0.1,
|
||||
tardis ==0.3.0.0,
|
||||
tasty ==0.10.1,
|
||||
tasty-ant-xml ==1.0.1,
|
||||
tasty-golden ==2.2.2.4,
|
||||
tasty-hunit ==0.9.0.1,
|
||||
tasty-quickcheck ==0.8.3.2,
|
||||
tasty-smallcheck ==0.8.0.1,
|
||||
tasty-th ==0.1.3,
|
||||
template-haskell installed,
|
||||
temporary ==1.2.0.3,
|
||||
temporary-rc ==1.2.0.3,
|
||||
terminal-progress-bar ==0.0.1.4,
|
||||
terminal-size ==0.3.0,
|
||||
terminfo installed,
|
||||
test-framework ==0.8.1.0,
|
||||
test-framework-hunit ==0.3.0.1,
|
||||
test-framework-quickcheck2 ==0.3.0.3,
|
||||
test-framework-th ==0.2.4,
|
||||
testing-feat ==0.4.0.2,
|
||||
testpack ==2.1.3.0,
|
||||
texmath ==0.8.0.1,
|
||||
text ==1.1.1.3,
|
||||
text-binary ==0.1.0,
|
||||
text-format ==0.3.1.1,
|
||||
text-icu ==0.7.0.0,
|
||||
tf-random ==0.5,
|
||||
th-desugar ==1.4.2,
|
||||
th-expand-syns ==0.3.0.4,
|
||||
th-extras ==0.0.0.2,
|
||||
th-lift ==0.7,
|
||||
th-orphans ==0.8.2,
|
||||
threads ==0.5.1.2,
|
||||
th-reify-many ==0.1.2,
|
||||
thyme ==0.3.5.5,
|
||||
time installed,
|
||||
time-compat ==0.1.0.3,
|
||||
time-lens ==0.4.0.1,
|
||||
timezone-olson ==0.1.6,
|
||||
timezone-series ==0.1.4,
|
||||
tls ==1.2.13,
|
||||
tls-debug ==0.3.4,
|
||||
tostring ==0.2.1,
|
||||
transformers installed,
|
||||
transformers-base ==0.4.3,
|
||||
transformers-compat ==0.3.3.3,
|
||||
traverse-with-class ==0.2.0.3,
|
||||
tree-view ==0.4,
|
||||
tuple ==0.3.0.2,
|
||||
type-eq ==0.4.2,
|
||||
type-list ==0.0.0.0,
|
||||
udbus ==0.2.1,
|
||||
unbounded-delays ==0.1.0.8,
|
||||
union-find ==0.2,
|
||||
uniplate ==1.6.12,
|
||||
unix installed,
|
||||
unix-compat ==0.4.1.3,
|
||||
unix-time ==0.3.4,
|
||||
unordered-containers ==0.2.5.1,
|
||||
uri-encode ==1.5.0.3,
|
||||
url ==2.1.3,
|
||||
utf8-light ==0.4.2,
|
||||
utf8-string ==0.3.8,
|
||||
uuid ==1.3.7,
|
||||
vault ==0.3.0.4,
|
||||
vector ==0.10.12.2,
|
||||
vector-algorithms ==0.6.0.3,
|
||||
vector-binary-instances ==0.2.1.0,
|
||||
vector-instances ==3.3,
|
||||
vector-space ==0.8.7,
|
||||
vector-space-points ==0.2,
|
||||
vector-th-unbox ==0.2.1.0,
|
||||
vhd ==0.2.2,
|
||||
void ==0.7,
|
||||
wai ==3.0.2.1,
|
||||
wai-app-static ==3.0.0.5,
|
||||
wai-conduit ==3.0.0.2,
|
||||
wai-eventsource ==3.0.0,
|
||||
wai-extra ==3.0.3.1,
|
||||
wai-logger ==2.2.3,
|
||||
wai-middleware-static ==0.6.0.1,
|
||||
wai-websockets ==3.0.0.3,
|
||||
warp ==3.0.4.1,
|
||||
warp-tls ==3.0.1.1,
|
||||
webdriver ==0.6.0.3,
|
||||
web-fpco ==0.1.1.0,
|
||||
websockets ==0.9.2.1,
|
||||
wizards ==1.0.1,
|
||||
wl-pprint ==1.1,
|
||||
wl-pprint-extras ==3.5.0.3,
|
||||
wl-pprint-terminfo ==3.7.1.3,
|
||||
wl-pprint-text ==1.1.0.2,
|
||||
word8 ==0.1.1,
|
||||
X11 ==1.6.1.2,
|
||||
x509 ==1.5.0.1,
|
||||
x509-store ==1.5.0,
|
||||
x509-system ==1.5.0,
|
||||
x509-validation ==1.5.1,
|
||||
xenstore ==0.1.1,
|
||||
xhtml installed,
|
||||
xml ==1.3.13,
|
||||
xml-conduit ==1.2.3.1,
|
||||
xmlgen ==0.6.2.1,
|
||||
xml-hamlet ==0.4.0.9,
|
||||
xmlhtml ==0.2.3.3,
|
||||
xml-types ==0.3.4,
|
||||
xss-sanitize ==0.3.5.4,
|
||||
yackage ==0.7.0.6,
|
||||
yaml ==0.8.10.1,
|
||||
Yampa ==0.9.6,
|
||||
YampaSynth ==0.2,
|
||||
yesod ==1.4.1.3,
|
||||
yesod-auth ==1.4.1.1,
|
||||
yesod-auth-deskcom ==1.4.0,
|
||||
yesod-auth-fb ==1.6.6,
|
||||
yesod-auth-hashdb ==1.4.1.1,
|
||||
yesod-bin ==1.4.3.1,
|
||||
yesod-core ==1.4.7.1,
|
||||
yesod-eventsource ==1.4.0.1,
|
||||
yesod-fay ==0.7.0,
|
||||
yesod-fb ==0.3.4,
|
||||
yesod-form ==1.4.3.1,
|
||||
yesod-gitrepo ==0.1.1.0,
|
||||
yesod-newsfeed ==1.4.0.1,
|
||||
yesod-persistent ==1.4.0.2,
|
||||
yesod-sitemap ==1.4.0.1,
|
||||
yesod-static ==1.4.0.4,
|
||||
yesod-test ==1.4.2.1,
|
||||
yesod-text-markdown ==0.1.7,
|
||||
yesod-websockets ==0.2.1.1,
|
||||
zeromq4-haskell ==0.6.2,
|
||||
zip-archive ==0.2.3.5,
|
||||
zlib ==0.5.4.2,
|
||||
zlib-bindings ==0.1.1.5,
|
||||
zlib-enum ==0.2.3.1,
|
||||
zlib-lens ==0.1
|
||||
@ -12,11 +12,15 @@
|
||||
|
||||
add-apt-repository -y ppa:chris-lea/zeromq
|
||||
add-apt-repository -y ppa:floe/libtisch
|
||||
add-apt-repository -y ppa:zoogie/sdl2-snapshots
|
||||
apt-get update
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
libncurses-dev \
|
||||
git \
|
||||
wget \
|
||||
m4 \
|
||||
texlive-full \
|
||||
libgmp3c2 \
|
||||
libgmp3-dev \
|
||||
zlib1g-dev \
|
||||
@ -33,11 +37,11 @@ apt-get install -y \
|
||||
llvm \
|
||||
libbz2-dev \
|
||||
libjudy-dev \
|
||||
libsqlite3-dev \
|
||||
libmysqlclient-dev \
|
||||
libpq-dev \
|
||||
libicu-dev \
|
||||
libssl-dev \
|
||||
nettle-dev \
|
||||
libgsl0-dev \
|
||||
libblas-dev \
|
||||
liblapack-dev \
|
||||
@ -47,4 +51,21 @@ apt-get install -y \
|
||||
libgd2-xpm-dev \
|
||||
libyaml-dev \
|
||||
liblzma-dev \
|
||||
libsdl2-dev \
|
||||
libxss-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
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
name: stackage
|
||||
version: 0.5.2
|
||||
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.
|
||||
homepage: https://github.com/fpco/stackage
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
author: Michael Snoyman
|
||||
maintainer: michael@fpcomplete.com
|
||||
category: Distribution
|
||||
build-type: Simple
|
||||
cabal-version: >=1.10
|
||||
extra-source-files: README.md
|
||||
ChangeLog.md
|
||||
test/test-build-constraints.yaml
|
||||
|
||||
library
|
||||
default-language: Haskell2010
|
||||
exposed-modules: Stackage.Prelude
|
||||
Stackage.BuildConstraints
|
||||
Stackage.CorePackages
|
||||
Stackage.PackageIndex
|
||||
Stackage.BuildPlan
|
||||
Stackage.CheckBuildPlan
|
||||
Stackage.UpdateBuildPlan
|
||||
Stackage.GithubPings
|
||||
Stackage.PackageDescription
|
||||
Stackage.ServerBundle
|
||||
Stackage.Upload
|
||||
Stackage.PerformBuild
|
||||
Stackage.CompleteBuild
|
||||
build-depends: base >= 4 && < 5
|
||||
, containers
|
||||
, Cabal >= 1.14
|
||||
, tar >= 0.3
|
||||
, zlib
|
||||
, bytestring
|
||||
, directory
|
||||
, filepath
|
||||
, transformers
|
||||
, process
|
||||
, old-locale
|
||||
, time
|
||||
, utf8-string
|
||||
|
||||
, conduit-extra
|
||||
, classy-prelude-conduit
|
||||
, text
|
||||
, system-fileio
|
||||
, system-filepath
|
||||
, mtl
|
||||
, aeson
|
||||
, yaml
|
||||
, unix-compat
|
||||
, http-client
|
||||
, http-client-tls
|
||||
, temporary
|
||||
, data-default-class
|
||||
, stm
|
||||
, mono-traversable
|
||||
, async
|
||||
, streaming-commons >= 0.1.7.1
|
||||
, semigroups
|
||||
, xml-conduit
|
||||
|
||||
executable stackage
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: app
|
||||
main-is: stackage.hs
|
||||
build-depends: base
|
||||
, stackage
|
||||
, optparse-applicative >= 0.11
|
||||
ghc-options: -rtsopts -threaded -with-rtsopts=-N
|
||||
|
||||
test-suite spec
|
||||
type: exitcode-stdio-1.0
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: test
|
||||
main-is: Spec.hs
|
||||
other-modules: Stackage.CorePackagesSpec
|
||||
Stackage.PackageIndexSpec
|
||||
Stackage.BuildPlanSpec
|
||||
build-depends: base
|
||||
, stackage
|
||||
, hspec
|
||||
, QuickCheck
|
||||
, text
|
||||
, classy-prelude-conduit
|
||||
, Cabal
|
||||
, yaml
|
||||
, containers
|
||||
, http-client
|
||||
, http-client-tls
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/fpco/stackage
|
||||
@ -1 +0,0 @@
|
||||
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
|
||||
@ -1,143 +0,0 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
|
||||
module Stackage.BuildPlanSpec (spec) where
|
||||
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Map.Strict as M
|
||||
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 = do
|
||||
it "simple package set" $ check testBuildConstraints $ makePackageSet
|
||||
[("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
|
||||
ebp' = Y.decodeEither bs
|
||||
|
||||
bp' <- either error return ebp'
|
||||
|
||||
let allPackages = Map.keysSet (bpPackages bp) ++ Map.keysSet (bpPackages bp')
|
||||
forM_ allPackages $ \name ->
|
||||
(name, lookup name (bpPackages bp')) `shouldBe`
|
||||
(name, lookup name (bpPackages bp))
|
||||
bpGithubUsers bp' `shouldBe` bpGithubUsers bp
|
||||
|
||||
when (bp' /= bp) $ error "bp' /= bp"
|
||||
bp2 <- updateBuildPlan plans bp
|
||||
when (dropVersionRanges bp2 /= dropVersionRanges bp) $ error "bp2 /= bp"
|
||||
checkBuildPlan bp
|
||||
where
|
||||
dropVersionRanges bp =
|
||||
bp { bpPackages = map go $ bpPackages bp }
|
||||
where
|
||||
go pb = pb { ppConstraints = go' $ ppConstraints pb }
|
||||
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"
|
||||
@ -1,19 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
|
||||
module Stackage.CorePackagesSpec (spec) where
|
||||
|
||||
import Stackage.CorePackages
|
||||
import Stackage.Prelude
|
||||
import Test.Hspec
|
||||
|
||||
spec :: Spec
|
||||
spec = do
|
||||
it "works" $ void getCorePackages
|
||||
it "contains known core packages" $ do
|
||||
m <- getCorePackages
|
||||
forM_ (words "ghc containers base") $ \p ->
|
||||
m `shouldSatisfy` (member (PackageName p))
|
||||
it "getCoreExecutables includes known executables" $ do
|
||||
s <- getCoreExecutables
|
||||
s `shouldSatisfy` member "ghc"
|
||||
s `shouldSatisfy` member "hsc2hs"
|
||||
s `shouldSatisfy` member "runghc"
|
||||
@ -1,21 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
|
||||
module Stackage.PackageIndexSpec (spec) where
|
||||
|
||||
import Stackage.PackageIndex
|
||||
import Stackage.Prelude
|
||||
import Test.Hspec
|
||||
import Distribution.Package (packageId)
|
||||
|
||||
spec :: Spec
|
||||
spec = do
|
||||
it "works" $ (runResourceT $ sourcePackageIndex $$ sinkNull :: IO ())
|
||||
it "getLatestDescriptions gives reasonable results" $ do
|
||||
let f x y = (display x, display y) `member` asSet (setFromList
|
||||
[ (asText "base", asText "4.5.0.0")
|
||||
, ("does-not-exist", "9999999999999999999")
|
||||
])
|
||||
m <- getLatestDescriptions f return
|
||||
length m `shouldBe` 1
|
||||
p <- simpleParse $ asText "base"
|
||||
v <- simpleParse $ asText "4.5.0.0"
|
||||
(pkgVersion . packageId <$> m) `shouldBe` singletonMap p v
|
||||
@ -1,20 +0,0 @@
|
||||
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
|
||||
Loading…
Reference in New Issue
Block a user