mirror of
https://github.com/commercialhaskell/stackage.git
synced 2026-01-30 16:10:25 +01:00
commit
1e3262d576
3
.dir-locals.el
Normal file
3
.dir-locals.el
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
((haskell-mode . ((haskell-process-type . cabal-repl)
|
||||||
|
(haskell-indent-spaces . 4)
|
||||||
|
(hindent-style . "johan-tibell"))))
|
||||||
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
dist
|
||||||
|
builds
|
||||||
|
logs
|
||||||
|
.cabal-sandbox
|
||||||
|
cabal.sandbox.config
|
||||||
|
tarballs
|
||||||
|
*.yaml
|
||||||
|
.git
|
||||||
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,13 +1,5 @@
|
|||||||
dist
|
|
||||||
*.o
|
|
||||||
*.hi
|
|
||||||
*.chi
|
|
||||||
*.chs.h
|
|
||||||
*.swp
|
|
||||||
/builds/
|
/builds/
|
||||||
/logs/
|
/logs/
|
||||||
/.cabal-sandbox/
|
|
||||||
cabal.sandbox.config
|
|
||||||
nightly-*.yaml
|
nightly-*.yaml
|
||||||
lts-*.yaml
|
lts-*.yaml
|
||||||
/tarballs/
|
*.swp
|
||||||
|
|||||||
21
.travis.yml
Normal file
21
.travis.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
env:
|
||||||
|
- CABALVER=1.22 GHCVER=7.10.1
|
||||||
|
|
||||||
|
# Note: the distinction between `before_install` and `install` is not important.
|
||||||
|
before_install:
|
||||||
|
- travis_retry sudo add-apt-repository -y ppa:hvr/ghc
|
||||||
|
- travis_retry sudo apt-get update
|
||||||
|
- travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER # see note about happy/alex
|
||||||
|
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
|
||||||
|
|
||||||
|
install:
|
||||||
|
- cabal --version
|
||||||
|
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||||
|
- travis_retry cabal update
|
||||||
|
- 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:
|
||||||
|
- ./stackage-curator check
|
||||||
34
ChangeLog.md
34
ChangeLog.md
@ -1,34 +0,0 @@
|
|||||||
## 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.
|
|
||||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
FROM ubuntu:14.04
|
||||||
|
|
||||||
|
ENV HOME /home/stackage
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
|
||||||
|
RUN mkdir /home/stackage -p
|
||||||
|
RUN locale-gen en_US.UTF-8
|
||||||
|
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common python-software-properties git
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive add-apt-repository ppa:hvr/ghc -y
|
||||||
|
|
||||||
|
ADD debian-bootstrap.sh /tmp/debian-bootstrap.sh
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive bash /tmp/debian-bootstrap.sh
|
||||||
|
RUN rm /tmp/debian-bootstrap.sh
|
||||||
|
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y cabal-install-1.22 ghc-7.10.1 ghc-7.10.1-htmldocs alex-3.1.3 happy-1.19.4 sudo
|
||||||
|
|
||||||
|
ENV PATH /home/stackage/.cabal/bin:/usr/local/sbin:/usr/local/bin:/opt/ghc/7.10.1/bin:/opt/cabal/1.22/bin:/opt/alex/3.1.3/bin:/opt/happy/1.19.4/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
|
||||||
|
RUN cabal update
|
||||||
|
RUN cabal install hscolour cabal-install && 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
|
||||||
101
README.md
101
README.md
@ -1,16 +1,28 @@
|
|||||||
stackage
|
stackage
|
||||||
========
|
========
|
||||||
|
|
||||||
|
[](https://travis-ci.org/fpco/stackage)
|
||||||
|
|
||||||
"Stable Hackage," tools for creating a vetted set of packages from Hackage.
|
"Stable Hackage," tools for creating a vetted set of packages from Hackage.
|
||||||
|
|
||||||
__NOTE__ This repository is for package authors to get their code into
|
__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
|
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).
|
instructions on [http://www.stackage.org/](http://www.stackage.org).
|
||||||
|
|
||||||
A note about the codebase: the goal is to minimize dependencies and have
|
The Stackage project consists of multiple repositories. This repository
|
||||||
the maximum range of supported compiler versions. Therefore, we avoid
|
contains the metadata on packages to be included in future builds and some
|
||||||
anything "complicated." For example, instead of using the text package,
|
project information. In addition, we have the following repositories:
|
||||||
we use Strings everywhere.
|
|
||||||
|
* [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)
|
||||||
|
* [stackage-nightly](https://github.com/fpco/stackage-nightly)
|
||||||
|
* [stackage-cli](https://github.com/fpco/stackage-cli) [](https://travis-ci.org/fpco/stackage-cli)
|
||||||
|
* [stackage-update](https://github.com/fpco/stackage-update) [](https://travis-ci.org/fpco/stackage-update)
|
||||||
|
* [stackage-upload](https://github.com/fpco/stackage-upload) [](https://travis-ci.org/fpco/stackage-upload)
|
||||||
|
* [stackage-install](https://github.com/fpco/stackage-install) [](https://travis-ci.org/fpco/stackage-install)
|
||||||
|
* [stackage-build-plan](https://github.com/fpco/stackage-build-plan) [](https://travis-ci.org/fpco/stackage-build-plan)
|
||||||
|
|
||||||
Get your package included
|
Get your package included
|
||||||
-------------------------
|
-------------------------
|
||||||
@ -37,6 +49,23 @@ dependencies, you may send a pull request without testing first.
|
|||||||
You should also read the [maintainers
|
You should also read the [maintainers
|
||||||
agreement](https://github.com/fpco/stackage/wiki/Maintainers-Agreement).
|
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
|
Build the package set
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
@ -49,6 +78,28 @@ build by running:
|
|||||||
cabal install stackage
|
cabal install stackage
|
||||||
stackage nightly
|
stackage nightly
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
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
|
||||||
|
some modifications to `build-constraints.yaml` are valid, try the following:
|
||||||
|
|
||||||
|
1. Create a local clone of the `stackage` repo
|
||||||
|
2. Make modifications to your local `build-constraints.yaml`
|
||||||
|
3. Inside the `stackage` working directory, run the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ docker run -it --rm -v $(pwd):/stackage -w /stackage snoyberg/stackage /bin/bash -c 'cabal update && stackage check'
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly, if you'd like to perform an entire build, you can replace the last step with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ docker run -it --rm -v $(pwd):/stackage -w /stackage snoyberg/stackage /bin/bash -c 'cabal update && stackage nightly --skip-upload'
|
||||||
|
```
|
||||||
|
|
||||||
## Processing
|
## Processing
|
||||||
|
|
||||||
The following describes at a high level the series of steps for processing
|
The following describes at a high level the series of steps for processing
|
||||||
@ -68,45 +119,3 @@ The following describes at a high level the series of steps for processing
|
|||||||
1. Load up most recent build plan
|
1. Load up most recent build plan
|
||||||
2. Convert build plan into constraints for next build
|
2. Convert build plan into constraints for next build
|
||||||
3. Continue from step (3) above
|
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,211 +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
|
|
||||||
) 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)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
]
|
|
||||||
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"
|
|
||||||
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 man = do
|
|
||||||
e <- isFile fp
|
|
||||||
if e
|
|
||||||
then decodeFileEither (fpToString fp) >>= either throwIO toBC
|
|
||||||
else httpLbs req man >>=
|
|
||||||
either throwIO toBC . decodeEither' . toStrict . responseBody
|
|
||||||
where
|
|
||||||
fp = "build-constraints.yaml"
|
|
||||||
req = "https://raw.githubusercontent.com/fpco/stackage/master/build-constraints.yaml"
|
|
||||||
|
|
||||||
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
|
|
||||||
{ cfGlobalFlags :: Map FlagName Bool
|
|
||||||
, 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
instance FromJSON ConstraintFile where
|
|
||||||
parseJSON = withObject "ConstraintFile" $ \o -> do
|
|
||||||
cfGlobalFlags <- goFlagMap <$> o .: "global-flags"
|
|
||||||
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"
|
|
||||||
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
|
|
||||||
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) ++
|
|
||||||
cfGlobalFlags
|
|
||||||
|
|
||||||
bcGithubUsers = cfGithubUsers
|
|
||||||
@ -1,207 +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
|
|
||||||
) 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 {..}
|
|
||||||
|
|
||||||
newBuildPlan :: MonadIO m => BuildConstraints -> m BuildPlan
|
|
||||||
newBuildPlan bc@BuildConstraints {..} = liftIO $ do
|
|
||||||
packagesOrig <- getLatestDescriptions (isAllowed bc) (mkPackagePlan bc)
|
|
||||||
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
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
{-# 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
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Control.Monad.Writer.Strict (Writer, execWriter, tell)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import Stackage.BuildConstraints
|
|
||||||
import Stackage.BuildPlan
|
|
||||||
import Stackage.PackageDescription
|
|
||||||
import Stackage.Prelude
|
|
||||||
|
|
||||||
-- FIXME check cycles in dependencies, only looking at libraries and
|
|
||||||
-- executables
|
|
||||||
|
|
||||||
checkBuildPlan :: MonadThrow m => BuildPlan -> m ()
|
|
||||||
checkBuildPlan BuildPlan {..}
|
|
||||||
| null errs' = return ()
|
|
||||||
| otherwise = throwM errs
|
|
||||||
where
|
|
||||||
allPackages = siCorePackages bpSystemInfo ++ map ppVersion bpPackages
|
|
||||||
errs@(BadBuildPlan errs') =
|
|
||||||
execWriter $ mapM_ (checkDeps allPackages) $ mapToList bpPackages
|
|
||||||
|
|
||||||
checkDeps :: Map PackageName Version
|
|
||||||
-> (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
|
|
||||||
| version `withinRange` range -> return ()
|
|
||||||
| 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
|
|
||||||
}
|
|
||||||
|
|
||||||
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,214 +0,0 @@
|
|||||||
{-# LANGUAGE NoImplicitPrelude #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
|
||||||
module Stackage.CompleteBuild
|
|
||||||
( BuildType (..)
|
|
||||||
, BumpType (..)
|
|
||||||
, completeBuild
|
|
||||||
, justCheck
|
|
||||||
) where
|
|
||||||
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.IO (BufferMode (LineBuffering), hSetBuffering)
|
|
||||||
|
|
||||||
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 ()
|
|
||||||
}
|
|
||||||
|
|
||||||
getSettings :: Manager -> BuildType -> IO Settings
|
|
||||||
getSettings man Nightly = do
|
|
||||||
day <- tshow . utctDay <$> getCurrentTime
|
|
||||||
let slug' = "nightly-" ++ day
|
|
||||||
plan' <- defaultBuildConstraints man >>= newBuildPlan
|
|
||||||
return Settings
|
|
||||||
{ planFile = fpFromText ("nightly-" ++ day) <.> "yaml"
|
|
||||||
, buildDir = fpFromText $ "builds/stackage-nightly-" ++ day
|
|
||||||
, logDir = fpFromText $ "logs/stackage-nightly-" ++ day
|
|
||||||
, title = \ghcVer -> concat
|
|
||||||
[ "Stackage Nightly "
|
|
||||||
, day
|
|
||||||
, ", GHC "
|
|
||||||
, ghcVer
|
|
||||||
]
|
|
||||||
, slug = slug'
|
|
||||||
, setArgs = \ghcVer ub -> ub { ubNightly = Just ghcVer }
|
|
||||||
, plan = plan'
|
|
||||||
, postBuild = return ()
|
|
||||||
}
|
|
||||||
getSettings man (LTS bumpType) = do
|
|
||||||
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
|
|
||||||
plan' <- defaultBuildConstraints man >>= newBuildPlan
|
|
||||||
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
|
|
||||||
plan' <- updateBuildPlan oldplan
|
|
||||||
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"]
|
|
||||||
}
|
|
||||||
|
|
||||||
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"
|
|
||||||
]
|
|
||||||
|
|
||||||
-- | Generate and check a new build plan, but do not execute it.
|
|
||||||
--
|
|
||||||
-- Since 0.3.1
|
|
||||||
justCheck :: IO ()
|
|
||||||
justCheck = withManager tlsManagerSettings $ \man -> do
|
|
||||||
putStrLn "Loading build constraints"
|
|
||||||
bc <- defaultBuildConstraints man
|
|
||||||
|
|
||||||
putStrLn "Creating build plan"
|
|
||||||
plan <- newBuildPlan bc
|
|
||||||
|
|
||||||
putStrLn $ "Writing build plan to check-plan.yaml"
|
|
||||||
encodeFile "check-plan.yaml" plan
|
|
||||||
|
|
||||||
putStrLn "Checking plan"
|
|
||||||
checkBuildPlan plan
|
|
||||||
|
|
||||||
putStrLn "Plan seems valid!"
|
|
||||||
|
|
||||||
completeBuild :: BuildType -> IO ()
|
|
||||||
completeBuild buildType = withManager tlsManagerSettings $ \man -> do
|
|
||||||
hSetBuffering stdout LineBuffering
|
|
||||||
|
|
||||||
putStrLn $ "Loading settings for: " ++ tshow buildType
|
|
||||||
Settings {..} <- getSettings man buildType
|
|
||||||
|
|
||||||
putStrLn $ "Writing build plan to: " ++ fpToText planFile
|
|
||||||
encodeFile (fpToString planFile) plan
|
|
||||||
|
|
||||||
putStrLn "Checking build plan"
|
|
||||||
checkBuildPlan plan
|
|
||||||
|
|
||||||
putStrLn "Performing build"
|
|
||||||
let pb = PerformBuild
|
|
||||||
{ pbPlan = plan
|
|
||||||
, pbInstallDest = buildDir
|
|
||||||
, pbLogDir = logDir
|
|
||||||
, pbLog = hPut stdout
|
|
||||||
, pbJobs = 8
|
|
||||||
, pbGlobalInstall = False
|
|
||||||
}
|
|
||||||
performBuild pb >>= mapM_ putStrLn
|
|
||||||
|
|
||||||
putStrLn "Uploading bundle to Stackage Server"
|
|
||||||
token <- readFile "/auth-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 = decodeUtf8 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 = decodeUtf8 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 <- uploadHackageDistro 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 = decodeUtf8 token
|
|
||||||
, udmSnapshot = ident
|
|
||||||
, udmDocDir = pbDocDir pb
|
|
||||||
, udmPlan = plan
|
|
||||||
} man >>= print
|
|
||||||
@ -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,433 +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
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
(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)
|
|
||||||
|
|
||||||
-- | Separate for the PATH environment variable
|
|
||||||
pathSep :: Char
|
|
||||||
#ifdef mingw32_HOST_OS
|
|
||||||
pathSep = ';'
|
|
||||||
#else
|
|
||||||
pathSep = ':'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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 = runChild outH
|
|
||||||
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 (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,52 +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 :: BuildPlan -> IO BuildPlan
|
|
||||||
updateBuildPlan = newBuildPlan . 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
|
|
||||||
}
|
|
||||||
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,265 +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
|
|
||||||
, 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 bp username password =
|
|
||||||
httpLbs (applyBasicAuth username password req)
|
|
||||||
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) ++
|
|
||||||
"\""
|
|
||||||
|
|
||||||
req = "http://hackage.haskell.org/distro/Stackage/packages.csv"
|
|
||||||
{ requestHeaders = [("Content-Type", "text/csv")]
|
|
||||||
, requestBody = RequestBodyLBS csv
|
|
||||||
, checkStatus = \_ _ _ -> Nothing
|
|
||||||
, method = "PUT"
|
|
||||||
}
|
|
||||||
|
|
||||||
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,16 +0,0 @@
|
|||||||
import Stackage.CompleteBuild
|
|
||||||
import System.Environment (getArgs)
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = do
|
|
||||||
args <- getArgs
|
|
||||||
case args of
|
|
||||||
[x] | Just y <- lookup x m -> y
|
|
||||||
_ -> error $ "Expected one argument, one of: " ++ unwords (map fst m)
|
|
||||||
where
|
|
||||||
m =
|
|
||||||
[ ("nightly", completeBuild Nightly)
|
|
||||||
, ("lts-major", completeBuild $ LTS Major)
|
|
||||||
, ("lts-minor", completeBuild $ LTS Minor)
|
|
||||||
, ("check", justCheck)
|
|
||||||
]
|
|
||||||
10
automated/.gitignore
vendored
Normal file
10
automated/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/auth-token
|
||||||
|
/bin/
|
||||||
|
/gitconfig
|
||||||
|
/hackage-creds
|
||||||
|
/ssh-nightly/
|
||||||
|
/ssh-lts/
|
||||||
|
/nighlty/
|
||||||
|
/lts-*/
|
||||||
|
/stackage-curator/
|
||||||
|
/stackage-update/
|
||||||
82
automated/build.sh
Executable file
82
automated/build.sh
Executable file
@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
ROOT=$(cd $(dirname $0) ; pwd)
|
||||||
|
TARGET=$1
|
||||||
|
TAG=$(echo $TARGET | cut -d- -f 1)
|
||||||
|
IMAGE=snoyberg/stackage:$TAG
|
||||||
|
|
||||||
|
if [ "$TAG" = "nightly" ]
|
||||||
|
then
|
||||||
|
TROOT=$ROOT/nightly
|
||||||
|
else
|
||||||
|
TROOT=$ROOT/$(echo $TARGET | cut -d. -f 1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
PLAN_FILE=current-plan.yaml
|
||||||
|
DOCMAP_FILE=current-docmap.yaml
|
||||||
|
BUNDLE_FILE=current.bundle
|
||||||
|
|
||||||
|
CABAL_DIR=$ROOT/cabal
|
||||||
|
GHC_DIR=$ROOT/ghc
|
||||||
|
DOT_STACKAGE_DIR=$ROOT/dot-stackage
|
||||||
|
WORKDIR=$TROOT/work
|
||||||
|
SSH_DIR=$ROOT/ssh-$(echo $TARGET | cut -d- -f 1)
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
"$CABAL_DIR" \
|
||||||
|
"$GHC_DIR" \
|
||||||
|
"$DOT_STACKAGE_DIR" \
|
||||||
|
"$WORKDIR" \
|
||||||
|
"$SSH_DIR"
|
||||||
|
|
||||||
|
GITCONFIG=$ROOT/gitconfig
|
||||||
|
cat >$GITCONFIG <<EOF
|
||||||
|
[user]
|
||||||
|
email = michael+stackage-build@fpcomplete.com
|
||||||
|
name = Stackage Build host
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >$SSH_DIR/known_hosts <<EOF
|
||||||
|
|1|Qn0iij8BnxGZXbyFSozS9zWkH+Q=|YrKKNp2KHO3/oc4UBFIe1zOvhDc= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||||
|
|1|RxBEt2ljiEppr019szMIhbY12m0=|0FZ2Oji1LphRbPLLEQhFzTmL69I= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||||
|
EOF
|
||||||
|
|
||||||
|
AUTH_TOKEN=$ROOT/auth-token
|
||||||
|
HACKAGE_CREDS=$ROOT/hackage-creds
|
||||||
|
|
||||||
|
function require_400_file {
|
||||||
|
if [ ! -f "$1" ]
|
||||||
|
then
|
||||||
|
echo File not found: "$1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 400 "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_400_file "$SSH_DIR/id_rsa"
|
||||||
|
require_400_file "$AUTH_TOKEN"
|
||||||
|
require_400_file "$HACKAGE_CREDS"
|
||||||
|
|
||||||
|
mkdir -p $ROOT/bin
|
||||||
|
BINDIR=$(cd $ROOT/bin ; pwd)
|
||||||
|
(
|
||||||
|
cd $BINDIR
|
||||||
|
rm -f stackage-curator stackage-curator.bz2
|
||||||
|
wget https://s3.amazonaws.com/stackage-travis/stackage-curator/stackage-curator.bz2
|
||||||
|
bunzip2 stackage-curator.bz2
|
||||||
|
chmod +x stackage-curator
|
||||||
|
)
|
||||||
|
|
||||||
|
ARGS_COMMON="--rm -u $USER -v $WORKDIR:/home/stackage/work -w /home/stackage/work -v $BINDIR/stackage-curator:/usr/local/bin/stackage-curator:ro -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro"
|
||||||
|
ARGS_PREBUILD="$ARGS_COMMON -v $CABAL_DIR:/home/stackage/.cabal -v $GHC_DIR:/home/stackage/.ghc -v $DOT_STACKAGE_DIR:/home/stackage/.stackage"
|
||||||
|
ARGS_BUILD="$ARGS_COMMON -v $CABAL_DIR:/home/stackage/.cabal:ro -v $GHC_DIR:/home/stackage/.ghc:ro"
|
||||||
|
ARGS_UPLOAD="$ARGS_COMMON -e AWS_ACCESS_KEY=$AWS_ACCESS_KEY -e AWS_SECRET_KEY=$AWS_SECRET_KEY -v $AUTH_TOKEN:/auth-token:ro -v $HACKAGE_CREDS:/hackage-creds:ro -v $DOT_STACKAGE_DIR:/home/stackage/.stackage -v $SSH_DIR:/home/ubuntu/.ssh:ro -v $GITCONFIG:/home/stackage/.gitconfig:ro -v $CABAL_DIR:/home/stackage/.cabal:ro"
|
||||||
|
|
||||||
|
# Use cabal update first to initialize ~/.cabal.config, then use stackage-curator update to get it securely
|
||||||
|
docker run $ARGS_UPLOAD $IMAGE /bin/bash -c "stackage-curator check-target-available --target $TARGET"
|
||||||
|
docker run $ARGS_PREBUILD $IMAGE /bin/bash -c "cabal update && stackage-curator update && stackage-curator create-plan --plan-file $PLAN_FILE --target $TARGET ${CONSTRAINTS:-} && stackage-curator check --plan-file $PLAN_FILE && stackage-curator fetch --plan-file $PLAN_FILE && cabal install random cabal-install"
|
||||||
|
docker run $ARGS_BUILD $IMAGE stackage-curator make-bundle --plan-file $PLAN_FILE --docmap-file $DOCMAP_FILE --bundle-file $BUNDLE_FILE --target $TARGET
|
||||||
|
docker run $ARGS_UPLOAD $IMAGE /bin/bash -c "stackage-curator upload --bundle-file $BUNDLE_FILE && stackage-curator hackage-distro --plan-file $PLAN_FILE --target $TARGET && stackage-curator upload-github --plan-file $PLAN_FILE --docmap-file $DOCMAP_FILE --target $TARGET && stackage-curator upload-index --plan-file $PLAN_FILE --target $TARGET && stackage-curator upload-docs --target $TARGET --bundle-file $BUNDLE_FILE"
|
||||||
File diff suppressed because it is too large
Load Diff
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.1,
|
|
||||||
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
|
|
||||||
@ -10,14 +10,16 @@
|
|||||||
# instructions, see:
|
# instructions, see:
|
||||||
# http://www.stackage.org/install
|
# http://www.stackage.org/install
|
||||||
|
|
||||||
sudo add-apt-repository -y ppa:chris-lea/zeromq
|
add-apt-repository -y ppa:zoogie/sdl2-snapshots
|
||||||
sudo add-apt-repository -y ppa:floe/libtisch
|
|
||||||
sudo apt-get update
|
apt-get update
|
||||||
sudo apt-get install -y \
|
apt-get install -y \
|
||||||
build-essential \
|
build-essential \
|
||||||
libncurses-dev \
|
libncurses-dev \
|
||||||
git \
|
git \
|
||||||
libgmp3c2 \
|
wget \
|
||||||
|
m4 \
|
||||||
|
texlive-full \
|
||||||
libgmp3-dev \
|
libgmp3-dev \
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
libedit2 \
|
libedit2 \
|
||||||
@ -33,11 +35,11 @@ sudo apt-get install -y \
|
|||||||
llvm \
|
llvm \
|
||||||
libbz2-dev \
|
libbz2-dev \
|
||||||
libjudy-dev \
|
libjudy-dev \
|
||||||
|
libsqlite3-dev \
|
||||||
libmysqlclient-dev \
|
libmysqlclient-dev \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
libicu-dev \
|
libicu-dev \
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
nettle-dev \
|
|
||||||
libgsl0-dev \
|
libgsl0-dev \
|
||||||
libblas-dev \
|
libblas-dev \
|
||||||
liblapack-dev \
|
liblapack-dev \
|
||||||
@ -46,4 +48,25 @@ sudo apt-get install -y \
|
|||||||
libnotify-dev \
|
libnotify-dev \
|
||||||
libgd2-xpm-dev \
|
libgd2-xpm-dev \
|
||||||
libyaml-dev \
|
libyaml-dev \
|
||||||
|
liblzma-dev \
|
||||||
|
libsdl2-dev \
|
||||||
|
libxss-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libgsasl7-dev \
|
||||||
libzmq3-dev
|
libzmq3-dev
|
||||||
|
|
||||||
|
mkdir /tmp/nettle-build
|
||||||
|
(
|
||||||
|
cd /tmp/nettle-build
|
||||||
|
wget https://ftp.gnu.org/gnu/nettle/nettle-2.7.1.tar.gz
|
||||||
|
tar zxf nettle-2.7.1.tar.gz
|
||||||
|
cd nettle-2.7.1
|
||||||
|
./configure --prefix=/usr
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
mkdir -p /usr/lib/x86_64-linux-gnu/
|
||||||
|
ln -sfv /usr/lib/libnettle.so.4.7 /usr/lib/x86_64-linux-gnu/libnettle.so.4
|
||||||
|
)
|
||||||
|
rm -rf /tmp/nettle-build
|
||||||
|
|||||||
@ -1,95 +0,0 @@
|
|||||||
name: stackage
|
|
||||||
version: 0.3.1
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
9
stackage/ChangeLog.md
Normal file
9
stackage/ChangeLog.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
## 0.7.3.0
|
||||||
|
|
||||||
|
* Added the executables split off from stackage-cli.
|
||||||
|
|
||||||
|
## 0.7.0.0
|
||||||
|
|
||||||
|
* First release of this incarnation of the stackage package. Previously, this
|
||||||
|
package provided completely different functionality. That functionality has
|
||||||
|
since moved to stackage-curator.
|
||||||
20
stackage/LICENSE
Normal file
20
stackage/LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2015 FP Complete
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
2
stackage/README.md
Normal file
2
stackage/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
This is a dummy wrapper package, forcing installation of other packages which
|
||||||
|
provide real functionality.
|
||||||
3
stackage/Stackage/Dummy.hs
Normal file
3
stackage/Stackage/Dummy.hs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- | This module does absolutely nothing. It's present so that cabal can more
|
||||||
|
-- easily track whether the stackage package is installed.
|
||||||
|
module Stackage.Dummy () where
|
||||||
29
stackage/stackage.cabal
Normal file
29
stackage/stackage.cabal
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: stackage
|
||||||
|
version: 0.7.3.2
|
||||||
|
synopsis: Dummy package forcing installation of other Stackage packages
|
||||||
|
homepage: https://www.stackage.org/
|
||||||
|
license: MIT
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Michael Snoyman
|
||||||
|
maintainer: michael@snoyman.com
|
||||||
|
category: Development
|
||||||
|
build-type: Simple
|
||||||
|
extra-source-files: README.md ChangeLog.md
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
library
|
||||||
|
exposed-modules: Stackage.Dummy
|
||||||
|
build-depends: base < 10
|
||||||
|
, stackage-cli >= 0.1.0
|
||||||
|
, stackage-update
|
||||||
|
, stackage-upload
|
||||||
|
, stackage-install
|
||||||
|
, stackage-build-plan
|
||||||
|
, stackage-cabal >= 0.1.1
|
||||||
|
, stackage-sandbox >= 0.1.1
|
||||||
|
, stackage-setup >= 0.0.1
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
source-repository head
|
||||||
|
type: git
|
||||||
|
location: git://github.com/fpco/stackage.git
|
||||||
@ -1 +0,0 @@
|
|||||||
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}
|
|
||||||
module Stackage.BuildPlanSpec (spec) where
|
|
||||||
|
|
||||||
import Stackage.BuildPlan
|
|
||||||
import Stackage.Prelude
|
|
||||||
import Stackage.BuildConstraints
|
|
||||||
import Stackage.UpdateBuildPlan
|
|
||||||
import Test.Hspec
|
|
||||||
import qualified Data.Yaml as Y
|
|
||||||
import Distribution.Version (anyVersion)
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Network.HTTP.Client (withManager)
|
|
||||||
import Network.HTTP.Client.TLS (tlsManagerSettings)
|
|
||||||
|
|
||||||
spec :: Spec
|
|
||||||
spec = it "works" $ withManager tlsManagerSettings $ \man -> do
|
|
||||||
bc <- defaultBuildConstraints man
|
|
||||||
bp <- newBuildPlan 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 bp
|
|
||||||
when (dropVersionRanges bp2 /= dropVersionRanges bp) $ error "bp2 /= bp"
|
|
||||||
where
|
|
||||||
dropVersionRanges bp =
|
|
||||||
bp { bpPackages = map go $ bpPackages bp }
|
|
||||||
where
|
|
||||||
go pb = pb { ppConstraints = go' $ ppConstraints pb }
|
|
||||||
go' pc = pc { pcVersionRange = anyVersion }
|
|
||||||
@ -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
|
|
||||||
Loading…
Reference in New Issue
Block a user