diff options
author | Will Thompson <will@willthompson.co.uk> | 2015-08-18 12:18:05 +0100 |
---|---|---|
committer | Will Thompson <will@willthompson.co.uk> | 2015-08-18 12:18:05 +0100 |
commit | 62bacb9fa9ce65c33c0bf14d45a2d619d2e108b9 (patch) | |
tree | 6e9222dd924d00cb622c7ac8cb306419d032d5c3 | |
parent | 95ac81a922c47ef3bdee61a9d989d6648ce90e5c (diff) | |
parent | 0328a9024234c8fab001726786c09b5f9b36192e (diff) |
Merge branch 'no-cabal-hgettext'
https://github.com/fpco/stackage/issues/746
-rw-r--r-- | .travis.yml | 103 | ||||
-rw-r--r-- | GetText.hs | 220 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | Setup.hs | 31 | ||||
-rw-r--r-- | bustle.cabal | 15 | ||||
-rwxr-xr-x | make_travis_yml.hs | 228 |
6 files changed, 534 insertions, 66 deletions
diff --git a/.travis.yml b/.travis.yml index aa8be2f..8b3e518 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,58 +1,79 @@ +# This file has been generated -- see https://github.com/hvr/multi-ghc-travis +language: c sudo: false -env: -# TODO -# # Fedora 22: -# - CABALVER=1.18 GHCVER=7.8.4 -# 7.10.2 is not in the magic whitelist at https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise - - CABALVER=1.22 GHCVER=7.10.1 - - CABALVER=head GHCVER=head +cache: + directories: + - $HOME/.cabsnap + - $HOME/.cabal/packages + +before_cache: + - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log + - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar matrix: - allow_failures: - - env: CABALVER=head GHCVER=head - -addons: - apt: - sources: - # https://github.com/hvr/multi-ghc-travis - - hvr-ghc - packages: - - libpcap-dev - - libgtk-3-dev - - libcairo2-dev - # GAH: I guess env does not have any effect here - - cabal-install-1.18 - - cabal-install-1.22 - - cabal-install-head - - ghc-7.8.4 - - ghc-7.10.1 - - ghc-head - # /GAH - - happy-1.19.4 - - alex-3.1.3 + include: + - env: CABALVER=1.18 GHCVER=7.8.4 + compiler: ": #GHC 7.8.4" + addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,libpcap-dev,libgtk-3-dev,libcairo2-dev,happy-1.19.4,alex-3.1.3], sources: [hvr-ghc]}} + - env: CABALVER=1.22 GHCVER=7.10.1 + compiler: ": #GHC 7.10.1" + addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.1,libpcap-dev,libgtk-3-dev,libcairo2-dev,happy-1.19.4,alex-3.1.3], sources: [hvr-ghc]}} + +before_install: + - unset CC + - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:/opt/happy/1.19.4/bin:/opt/alex/3.1.3/bin:$PATH install: -# Is it just not installing those packages? - - dpkg -l - - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:/opt/alex/3.1.3/bin:/opt/happy/1.19.4/bin:$PATH - cabal --version - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" - - ghc-pkg list Cabal - - travis_retry cabal update -# TODO: shouldn't gtk3 et al build-depend on this? Should we do so? - - cabal install gtk2hs-buildtools - - cabal install --only-dependencies --enable-tests --enable-benchmarks + - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ]; + then + zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz > + $HOME/.cabal/packages/hackage.haskell.org/00-index.tar; + fi + - travis_retry cabal update -v + - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config + - cabal install --only-dependencies --enable-tests --enable-benchmarks --flags='WithGtk2HsBuildTools' --dry -v > installplan.txt + - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt + +# check whether current requested install-plan matches cached package-db snapshot + - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt; + then + echo "cabal build-cache HIT"; + rm -rfv .ghc; + cp -a $HOME/.cabsnap/ghc $HOME/.ghc; + cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/; + else + echo "cabal build-cache MISS"; + rm -rf $HOME/.cabsnap; + mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin; + travis_retry cabal install --only-dependencies --enable-tests --enable-benchmarks --flags='WithGtk2HsBuildTools'; + fi + +# snapshot package-db on cache miss + - if [ ! -d $HOME/.cabsnap ]; + then + echo "snapshotting package-db to build-cache"; + mkdir $HOME/.cabsnap; + cp -a $HOME/.ghc $HOME/.cabsnap/ghc; + cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/; + fi +# 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: - if [ -f configure.ac ]; then autoreconf -i; fi - - cabal configure --enable-tests --enable-benchmarks -v2 - - cabal build - - cabal test + - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging + - cabal build # this builds all libraries and executables (including tests/benchmarks) + - ./dist/setup/setup test - cabal check - - cabal sdist + - cabal sdist # tests that a source-distribution can be generated + # Check that the resulting source distribution can be built & installed. # If there are no other `.tar.gz` files in `dist`, this can be even simpler: # `cabal install --force-reinstalls dist/*-*.tar.gz` - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && (cd dist && cabal install --force-reinstalls "$SRC_TGZ") + +# EOF diff --git a/GetText.hs b/GetText.hs new file mode 100644 index 0000000..1c27146 --- /dev/null +++ b/GetText.hs @@ -0,0 +1,220 @@ +-- | This library extends the Distribution with internationalization support. +-- +-- It performs two functions: +-- +-- * compiles and installs PO files to the specified directory +-- +-- * tells the application where files were installed to make it able +-- to bind them to the code +-- +-- Each PO file will be placed to the +-- @{datadir}\/locale\/{loc}\/LC_MESSAGES\/{domain}.mo@ where: +-- +-- [@datadir@] Usually @prefix/share@ but could be different, depends +-- on system. +-- +-- [@loc@] Locale name (language code, two characters). This module +-- supposes, that each PO file has a base name set to the proper +-- locale, e.g. @de.po@ is the German translation of the program, so +-- this file will be placed under @{datadir}\/locale\/de@ directory +-- +-- [@domain@] Program domain. A unique identifier of single +-- translational unit (program). By default domain will be set to the +-- package name, but its name could be configured in the @.cabal@ file. +-- +-- The module defines following @.cabal@ fields: +-- +-- [@x-gettext-domain-name@] Name of the domain. One ofmore +-- alphanumeric characters separated by hyphens or underlines. When +-- not set, package name will be used. +-- +-- [@x-gettext-po-files@] List of files with translations. Could be +-- used a limited form of wildcards, e.g.: @x-gettext-po-files: +-- po/*.po@ +-- +-- [@x-gettext-domain-def@] Name of the macro, in which domain name +-- will be passed to the program. Default value is +-- @__MESSAGE_CATALOG_DOMAIN__@ +-- +-- [@x-gettext-msg-cat-def@] Name of the macro, in which path to the +-- message catalog will be passed to the program. Default value is +-- @__MESSAGE_CATALOG_DIR__@ +-- +-- The last two parameters are used to send configuration data to the +-- code during its compilation. The most common usage example is: +-- +-- +-- > ... +-- > prepareI18N = do +-- > setLocale LC_ALL (Just "") +-- > bindTextDomain __MESSAGE_CATALOG_DOMAIN__ (Just __MESSAGE_CATALOG_DIR__) +-- > textDomain __MESSAGE_CATALOG_DOMAIN__ +-- > +-- > main = do +-- > prepareI18N +-- > ... +-- > +-- > ... +-- +-- +-- /NOTE:/ files, passed in the @x-gettext-po-files@ are not +-- automatically added to the source distribution, so they should be +-- also added to the @extra-source-files@ parameter, along with +-- translation template file (usually @message.pot@) +-- +-- /WARNING:/ sometimes, when only configuration targets changes, code +-- will not recompile, thus you should execute @cabal clean@ to +-- cleanup the build and restart it again from the configuration. This +-- is temporary bug, it will be fixed in next releases. +-- +-- /TODO:/ this is lifted verbatim (modulo other /TODO/s) from hgettext's +-- Distribution.Simple.I18N.GetText partly to expose individual hooks and +-- partly to avoid the /cabal configure/-time dependency. For the latter, +-- see https://github.com/fpco/stackage/issues/746 +-- + +module GetText + ( + -- | /TODO:/ upstream exporting the individual hooks? + installPOFiles, + + -- | /TODO:/ upstream generating GetText_foo.hs rather than exporting these? + getDomainNameDefault, + getPackageName, + targetDataDir, + + installGetTextHooks, + gettextDefaultMain + ) where + +import Distribution.Simple +import Distribution.Simple.Setup as S +import Distribution.Simple.LocalBuildInfo +import Distribution.PackageDescription +import Distribution.Simple.Configure +import Distribution.Simple.InstallDirs as I +import Distribution.Simple.Utils + +import Language.Haskell.Extension + +import Control.Monad +import Control.Arrow (second) +import Data.Maybe (listToMaybe, maybeToList, fromMaybe) +import Data.List (unfoldr,nub,null) +import System.FilePath +import System.Directory +import System.Process + +-- | Default main function, same as +-- +-- > defaultMainWithHooks $ installGetTextHooks simpleUserHooks +-- +gettextDefaultMain :: IO () +gettextDefaultMain = defaultMainWithHooks $ installGetTextHooks simpleUserHooks + +-- | Installs hooks, used by GetText module to install +-- PO files to the system. Previous won't be disabled +-- +installGetTextHooks :: UserHooks -- ^ initial user hooks + -> UserHooks -- ^ patched user hooks +installGetTextHooks uh = uh{ + confHook = \a b -> + (confHook uh) a b >>= + return . updateLocalBuildInfo, + + postInst = \a b c d -> + (postInst uh) a b c d >> + installPOFiles a b c d + } + + +updateLocalBuildInfo :: LocalBuildInfo -> LocalBuildInfo +updateLocalBuildInfo l = + let sMap = getCustomFields l + [domDef, catDef] = map ($ sMap) [getDomainDefine, getMsgCatalogDefine] + dom = getDomainNameDefault sMap (getPackageName l) + tar = targetDataDir l + [catMS, domMS] = map (uncurry formatMacro) [(domDef, dom), (catDef, tar)] + in (appendCPPOptions [domMS,catMS] . appendExtension [EnableExtension CPP]) l + +installPOFiles :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO () +installPOFiles _ _ _ l = + let sMap = getCustomFields l + destDir = targetDataDir l + dom = getDomainNameDefault sMap (getPackageName l) + installFile file = do + let fname = takeFileName file + let bname = takeBaseName fname + let targetDir = destDir </> bname </> "LC_MESSAGES" + -- ensure we have directory destDir/{loc}/LC_MESSAGES + createDirectoryIfMissing True targetDir + system $ "msgfmt --output-file=" ++ + (targetDir </> dom <.> "mo") ++ + " " ++ file + in do + filelist <- getPoFilesDefault sMap + -- copy all whose name is in the form of dir/{loc}.po to the + -- destDir/{loc}/LC_MESSAGES/dom.mo + -- with the 'msgfmt' tool + mapM_ installFile filelist + +forBuildInfo :: LocalBuildInfo -> (BuildInfo -> BuildInfo) -> LocalBuildInfo +forBuildInfo l f = + let a = l{localPkgDescr = updPkgDescr (localPkgDescr l)} + updPkgDescr x = x{library = updLibrary (library x), + executables = updExecs (executables x)} + updLibrary Nothing = Nothing + updLibrary (Just x) = Just $ x{libBuildInfo = f (libBuildInfo x)} + updExecs x = map updExec x + updExec x = x{buildInfo = f (buildInfo x)} + in a + +appendExtension :: [Extension] -> LocalBuildInfo -> LocalBuildInfo +appendExtension exts l = + forBuildInfo l updBuildInfo + where updBuildInfo x = x{defaultExtensions = updExts (defaultExtensions x)} + updExts s = nub (s ++ exts) + +appendCPPOptions :: [String] -> LocalBuildInfo -> LocalBuildInfo +appendCPPOptions opts l = + forBuildInfo l updBuildInfo + where updBuildInfo x = x{cppOptions = updOpts (cppOptions x)} + updOpts s = nub (s ++ opts) + +formatMacro name value = "-D" ++ name ++ "=" ++ (show value) + +targetDataDir :: LocalBuildInfo -> FilePath +targetDataDir l = + let dirTmpls = installDirTemplates l + prefix' = prefix dirTmpls + data' = datadir dirTmpls + dataEx = I.fromPathTemplate $ I.substPathTemplate [(PrefixVar, prefix')] data' + in dataEx ++ "/locale" + +getPackageName :: LocalBuildInfo -> String +getPackageName = fromPackageName . packageName . localPkgDescr + where fromPackageName (PackageName s) = s + +getCustomFields :: LocalBuildInfo -> [(String, String)] +getCustomFields = customFieldsPD . localPkgDescr + +findInParametersDefault :: [(String, String)] -> String -> String -> String +findInParametersDefault al name def = (fromMaybe def . lookup name) al + +getDomainNameDefault :: [(String, String)] -> String -> String +getDomainNameDefault al d = findInParametersDefault al "x-gettext-domain-name" d + +getDomainDefine :: [(String, String)] -> String +getDomainDefine al = findInParametersDefault al "x-gettext-domain-def" "__MESSAGE_CATALOG_DOMAIN__" + +getMsgCatalogDefine :: [(String, String)] -> String +getMsgCatalogDefine al = findInParametersDefault al "x-gettext-msg-cat-def" "__MESSAGE_CATALOG_DIR__" + +getPoFilesDefault :: [(String, String)] -> IO [String] +getPoFilesDefault al = toFileList $ findInParametersDefault al "x-gettext-po-files" "" + where toFileList "" = return [] + toFileList x = liftM concat $ mapM matchFileGlob $ split' x + -- from Blow your mind (HaskellWiki) + -- splits string by newline, space and comma + split' x = concatMap lines $ concatMap words $ unfoldr (\b -> fmap (const . (second $ drop 1) . break (==',') $ b) . listToMaybe $ b) x + @@ -123,3 +123,6 @@ maintainer-make-release: bustle.cabal dist/build/autogen/version.txt git tag -s -m 'Bustle '`cat dist/build/autogen/version.txt` \ bustle-`cat dist/build/autogen/version.txt` make maintainer-binary-tarball + +.travis.yml: bustle.cabal make_travis_yml.hs + ./make_travis_yml.hs $< libpcap-dev libgtk-3-dev libcairo2-dev happy-1.19.4 alex-3.1.3 > $@ @@ -1,11 +1,9 @@ {-# OPTIONS_GHC -Wall #-} -import Data.Maybe (fromMaybe) import System.FilePath ( (</>), (<.>) ) import Distribution.PackageDescription import Distribution.Simple import Distribution.Simple.BuildPaths ( autogenModulesDir ) -import Distribution.Simple.InstallDirs as I import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Setup as S import Distribution.Simple.Utils @@ -14,7 +12,7 @@ import Distribution.Text ( display ) import Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as ModuleName -import qualified Distribution.Simple.I18N.GetText as GetText +import qualified GetText as GetText main :: IO () main = defaultMainWithHooks $ installBustleHooks simpleUserHooks @@ -31,13 +29,13 @@ main = defaultMainWithHooks $ installBustleHooks simpleUserHooks installBustleHooks :: UserHooks -> UserHooks installBustleHooks uh = uh - { postInst = postInst gtuh + { postInst = \a b c d -> do + postInst uh a b c d + GetText.installPOFiles a b c d , buildHook = \pkg lbi hooks flags -> do writeGetTextConstantsFile pkg lbi flags buildHook uh pkg lbi hooks flags } - where - gtuh = GetText.installGetTextHooks uh writeGetTextConstantsFile :: PackageDescription -> LocalBuildInfo -> BuildFlags -> IO () @@ -90,24 +88,7 @@ generateModule pkg lbi = "getMessageCatalogDir = catchIO (getEnv \"" ++ fixedPackageName pkg ++ "_localedir\") (\\_ -> return messageCatalogDir)\n" sMap = customFieldsPD (localPkgDescr lbi) - dom = getDomainNameDefault sMap (getPackageName lbi) - tar = targetDataDir lbi + dom = GetText.getDomainNameDefault sMap (GetText.getPackageName lbi) + tar = GetText.targetDataDir lbi -- Cargo-culted from hgettext -findInParametersDefault :: [(String, String)] -> String -> String -> String -findInParametersDefault al name def = (fromMaybe def . lookup name) al - -getPackageName :: LocalBuildInfo -> String -getPackageName = fromPackageName . packageName . localPkgDescr - where fromPackageName (PackageName s) = s - -getDomainNameDefault :: [(String, String)] -> String -> String -getDomainNameDefault al d = findInParametersDefault al "x-gettext-domain-name" d - -targetDataDir :: LocalBuildInfo -> FilePath -targetDataDir l = - let dirTmpls = installDirTemplates l - prefix' = prefix dirTmpls - data' = datadir dirTmpls - dataEx = I.fromPathTemplate $ I.substPathTemplate [(PrefixVar, prefix')] data' - in dataEx ++ "/locale" diff --git a/bustle.cabal b/bustle.cabal index 05386d8..f9edb84 100644 --- a/bustle.cabal +++ b/bustle.cabal @@ -2,6 +2,7 @@ Name: bustle Category: Network, Desktop Version: 0.5.1 Cabal-Version: >= 1.18 +Tested-With: GHC >= 7.8.4 && < 7.11 Synopsis: Draw sequence diagrams of D-Bus traffic Description: Draw sequence diagrams of D-Bus traffic License: OtherLicense @@ -35,6 +36,10 @@ Extra-source-files: , ldd-me-up.sh , LICENSE.bundled-libraries + -- inlined copy of the Cabal hooks from hgettext; + -- see https://github.com/fpco/stackage/issues/746 + , GetText.hs + -- wow many translate , po/*.po , po/*.pot @@ -67,6 +72,13 @@ Flag threaded Description: Build with the multi-threaded runtime Default: True +Flag WithGtk2HsBuildTools + Description: Build-depend on gtk2hs-buildtools. They aren't (currently) + used to build Bustle itself but are needed to build + dependencies like gtk3, which for whatever reason do not + Build-Depend on the tools. + Default: False + Executable bustle Main-is: Bustle.hs Other-modules: Bustle.Application.Monad @@ -122,6 +134,9 @@ Executable bustle , text , time + if flag(WithGtk2HsBuildTools) + Build-Depends: gtk2hs-buildtools + Executable test-monitor if flag(InteractiveTests) buildable: True diff --git a/make_travis_yml.hs b/make_travis_yml.hs new file mode 100755 index 0000000..551cbd5 --- /dev/null +++ b/make_travis_yml.hs @@ -0,0 +1,228 @@ +#!/usr/bin/env runghc + +-- NB: This code deliberately avoids relying on non-standard packages + +import Control.Monad +import Data.Maybe +import Data.List +import System.Environment +import System.Exit +import System.IO + +import Distribution.PackageDescription.Parse (readPackageDescription) +import Distribution.PackageDescription (packageDescription, testedWith) +import Distribution.Compiler (CompilerFlavor(..)) +import Distribution.Version +import Distribution.Text + +putStrLnErr :: String -> IO () +putStrLnErr m = hPutStrLn stderr ("*ERROR* " ++ m) >> exitFailure + +putStrLnWarn :: String -> IO () +putStrLnWarn m = hPutStrLn stderr ("*WARNING* " ++ m) + +putStrLnInfo :: String -> IO () +putStrLnInfo m = hPutStrLn stderr ("*INFO* " ++ m) + +main :: IO () +main = do + args <- getArgs + case args of + (cabfn:xpkgs) -> do genTravisFromCabalFile cabfn xpkgs + _ -> putStrLnErr (unlines $ [ "expected .cabal file as command-line argument" + , "Usage: make_travis_yml.hs <cabal-file> <extra-apt-packages...>" + , "" + , "Example: make_travis_yml.hs someProject.cabal alex-3.1.4 liblzma-dev > .travis.yml" + ]) + +genTravisFromCabalFile :: FilePath -> [String] -> IO () +genTravisFromCabalFile fn xpkgs = do + gpd <- readPackageDescription maxBound fn + + let compilers = testedWith $ packageDescription $ gpd + + let unknownComps = nub [ c | (c,_) <- compilers, c /= GHC ] + ghcVerConstrs = [ vc | (GHC,vc) <- compilers ] + ghcVerConstrs' = simplifyVersionRange $ foldr unionVersionRanges noVersion ghcVerConstrs + + when (null compilers) $ do + putStrLnErr "empty or missing 'tested-with:' definition in .cabal file" + + unless (null unknownComps) $ do + putStrLnWarn $ "ignoring unsupported compilers mentioned in tested-with: " ++ show unknownComps + + when (null ghcVerConstrs) $ do + putStrLnErr "'tested-with:' doesn't mention any 'GHC' version" + + when (isNoVersion ghcVerConstrs') $ do + putStrLnErr "'tested-with:' describes an empty version range for 'GHC'" + + when (isAnyVersion ghcVerConstrs') $ do + putStrLnErr "'tested-with:' allows /any/ 'GHC' version" + + let testedGhcVersions = filter (`withinRange` ghcVerConstrs') knownGhcVersions + + when (null testedGhcVersions) $ do + putStrLnErr "no known GHC version is allowed by the 'tested-with' specification" + + let pathBits = concat [ [ "/opt/ghc/$GHCVER/bin", "/opt/cabal/$CABALVER/bin" ] + , catMaybes (map pathForPackage xpkgs) + , ["$PATH"] + ] + + -- FIXME + let flags = "WithGtk2HsBuildTools" + + putStrLnInfo $ "Generating Travis-CI config for testing for GHC versions: " ++ (unwords $ map disp' $ testedGhcVersions) + + ---------------------------------------------------------------------------- + -- travis.yml generation starts here + + putStrLn "# This file has been generated -- see https://github.com/hvr/multi-ghc-travis" + putStrLn "language: c" + putStrLn "sudo: false" + putStrLn "" + putStrLn "cache:" + putStrLn " directories:" + putStrLn " - $HOME/.cabsnap" + putStrLn " - $HOME/.cabal/packages" + putStrLn "" + putStrLn "before_cache:" + putStrLn " - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log" + putStrLn " - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar" + putStrLn "" + putStrLn "matrix:" + putStrLn " include:" + + forM_ testedGhcVersions $ \gv -> do + let cvs = disp' (lookupCabVer gv) + gvs = disp' gv + + xpkgs' = concatMap (',':) xpkgs + + putStrLn $ concat [ " - env: CABALVER=", cvs, " GHCVER=", gvs ] + putStrLn $ concat [ " compiler: \": #GHC ", gvs, "\"" ] + putStrLn $ concat [ " addons: {apt: {packages: [cabal-install-", cvs, ",ghc-", gvs, xpkgs' + , "], sources: [hvr-ghc]}}" ] + return () + + let headGhcVers = filter isHead testedGhcVersions + + unless (null headGhcVers) $ do + putStrLn "" + putStrLn " allow_failures:" + + forM_ headGhcVers $ \gv -> do + let cvs = disp' (lookupCabVer gv) + gvs = disp' gv + putStrLn $ concat [ " - env: CABALVER=", cvs, " GHCVER=", gvs ] + + putStrLn "" + putStrLn "before_install:" + putStrLn " - unset CC" + putStrLn $ " - export PATH=" ++ intercalate ":" pathBits + + putStrLn "" + + putStr $ unlines + [ "install:" + , " - cabal --version" + , " - echo \"$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]\"" + , " - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];" + , " then" + , " zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >" + , " $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;" + , " fi" + , " - travis_retry cabal update -v" + , " - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config" + , " - cabal install --only-dependencies --enable-tests --enable-benchmarks --flags='" ++ flags ++ "' --dry -v > installplan.txt" + , " - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt" + , "" + , "# check whether current requested install-plan matches cached package-db snapshot" + , " - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;" + , " then" + , " echo \"cabal build-cache HIT\";" + , " rm -rfv .ghc;" + , " cp -a $HOME/.cabsnap/ghc $HOME/.ghc;" + , " cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;" + , " else" + , " echo \"cabal build-cache MISS\";" + , " rm -rf $HOME/.cabsnap;" + , " mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;" + -- TODO: shouldn't gtk3 et al build-depend on gtk2hs-buildtools? We have to do + -- this incantation twice because gtk2hs-buildtools may not be installed before + -- the things that secretly depend on its presence. Silly. + , " travis_retry cabal install --only-dependencies --enable-tests --enable-benchmarks --flags='" ++ flags ++ "';" + , " fi" + , " " + , "# snapshot package-db on cache miss" + , " - if [ ! -d $HOME/.cabsnap ];" + , " then" + , " echo \"snapshotting package-db to build-cache\";" + , " mkdir $HOME/.cabsnap;" + , " cp -a $HOME/.ghc $HOME/.cabsnap/ghc;" + , " cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;" + , " fi" + , "" + , "# 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:" + , " - if [ -f configure.ac ]; then autoreconf -i; fi" + , " - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging" + , " - cabal build # this builds all libraries and executables (including tests/benchmarks)" + -- FIXME + -- , " - cabal test" + , " - ./dist/setup/setup test" + , " - cabal check" + , " - cabal sdist # tests that a source-distribution can be generated" + , "" + , "# Check that the resulting source distribution can be built & installed." + , "# If there are no other `.tar.gz` files in `dist`, this can be even simpler:" + , "# `cabal install --force-reinstalls dist/*-*.tar.gz`" + , " - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&" + , " (cd dist && cabal install --force-reinstalls \"$SRC_TGZ\")" + , "" + , "# EOF" + ] + + return () + where + knownGhcVersions :: [Version] + knownGhcVersions = fmap (`Version` []) + [ [7,0,1], [7,0,2], [7,0,3], [7,0,4] + , [7,2,1], [7,2,2] + , [7,4,1], [7,4,2] + , [7,6,1], [7,6,2], [7,6,3] + , [7,8,1], [7,8,2], [7,8,3], [7,8,4] + , [7,10,1] + -- 7.10.2 is not in the magic whitelist at + -- https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise + --, [7,10,2] + , [7,11] -- HEAD + ] + + lookupCabVer :: Version -> Version + lookupCabVer (Version (x:y:_) _) = maybe (error "internal error") id $ lookup (x,y) cabalVerMap + where + cabalVerMap = fmap (fmap (`Version` [])) + [ ((7, 0), [1,16]) + , ((7, 2), [1,16]) + , ((7, 4), [1,16]) + , ((7, 6), [1,16]) + , ((7, 8), [1,18]) + , ((7,10), [1,22]) + , ((7,11), [1,23]) -- HEAD + ] + + isHead (Version (_:y:_) _) = odd (y :: Int) + + disp' v | isHead v = "head" + | otherwise = display v + + pathForPackage :: String -> Maybe String + pathForPackage xpkg = do + i <- findIndex (== '-') xpkg + let (p, _:ver) = splitAt i xpkg + guard $ p `elem` ["happy", "alex"] + return $ "/opt/" ++ p ++ "/" ++ ver ++ "/bin" + |