public
Last active

Example CABAL Setup.hs file for automatic package versioning via `git describe`

  • Download Gist
Setup.hs
Haskell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
import Control.Exception
import Control.Monad
import Data.Maybe
import Data.Version
import Distribution.PackageDescription (PackageDescription(..), HookedBuildInfo, GenericPackageDescription(..))
import Distribution.Package (PackageIdentifier(..))
import Distribution.Simple (defaultMainWithHooks, simpleUserHooks, UserHooks(..))
import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..))
import Distribution.Simple.Setup (BuildFlags(..), ConfigFlags(..))
import Distribution.Simple.Utils (die)
import System.Process (readProcess)
import Text.ParserCombinators.ReadP (readP_to_S)
 
main :: IO ()
main = defaultMainWithHooks simpleUserHooks
{ confHook = myConfHook
, buildHook = myBuildHook
}
 
-- configure hook
myConfHook :: (GenericPackageDescription, HookedBuildInfo)
-> ConfigFlags
-> IO LocalBuildInfo
myConfHook (gpdesc, hbinfo) cfg = do
gitVersion <- inferVersionFromGit
 
let GenericPackageDescription {
packageDescription = pdesc@PackageDescription {
package = pkgIden }} = gpdesc
 
let gpdesc' = gpdesc {
packageDescription = pdesc {
package = pkgIden { pkgVersion = gitVersion } } }
 
-- putStrLn $ showVersion gitVersion
 
confHook simpleUserHooks (gpdesc', hbinfo) cfg
 
 
-- build hook
myBuildHook :: PackageDescription
-> LocalBuildInfo
-> UserHooks
-> BuildFlags
-> IO ()
myBuildHook pdesc lbinfo uhooks bflags = do
gitVersion <- inferVersionFromGit
 
let lastVersion = pkgVersion $ package pdesc
 
when (gitVersion /= lastVersion) $
die("The version reported by git '" ++ showVersion gitVersion ++
"' has changed since last time this package was configured (version was '" ++
showVersion lastVersion ++ "' back then), please re-configure package")
 
buildHook simpleUserHooks pdesc lbinfo uhooks bflags
 
-- |Infer package version from Git tags. Uses `git describe` to infer 'Version'.
inferVersionFromGit :: IO Version
inferVersionFromGit = do
ver_line <- init `liftM` readProcess "git"
[ "describe"
, "--abbrev=5"
, "--tags"
, "--match=v[0-9].[0-9][0-9]"
, "--dirty"
, "--long"
] ""
 
-- ver_line <- return "v0.1-42-gf9f4eb3-dirty"
 
let versionStr = (head ver_line == 'v') `assert` replaceFirst '-' '.' (tail ver_line)
Just version = listToMaybe [ p | (p, "") <- readP_to_S parseVersion versionStr ]
 
return version
 
-- |Helper for replacing first occurence of character by another one.
replaceFirst :: Eq a => a -> a -> [a] -> [a]
replaceFirst _ _ [] = []
replaceFirst o r (x:xs) | o == x = r : xs
| otherwise = x : replaceFirst o r xs

Note that this approach is no longer valid, as Cabal does not permit tags in package versions. A shame, because I feel this approach is cleaner than generating a new module, although I understand why the Cabal developers made the choice.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.