Skip to content
Create a gist now

Instantly share code, notes, and snippets.

@hvr /Setup.hs
Created Oct 31, 2010

Example CABAL Setup.hs file for automatic package versioning via `git describe`
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
@hvr
Owner
hvr commented Oct 31, 2010

Alternative approach to the one described in http://www.hyperedsoftware.com/blog/entries/build-info-gen.html

@Athas
Athas commented Apr 16, 2014

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.