diff --git a/Makefile b/Makefile index 03766788b..a6c3302e8 100644 --- a/Makefile +++ b/Makefile @@ -193,12 +193,6 @@ DOCSOURCEFILES:= \ # We use hledger CLI's current version (XXX for all packages, which isn't quite right). VERSION=$(shell cat hledger/.version) -# the number of commits since the last tag -PATCHLEVEL=$(shell git describe --tags --match 'hledger-[0-9]*' --long | awk -F- '{print $$3}') -#PATCHLEVEL:=$(shell git describe --tags --match 'hledger-web-[0-9]*' --long | awk -F- '{print $$4}') -# the number of commits since the last_release tag -#PATCHLEVEL:=$(shell git rev-list last_release..HEAD | wc -l) - # flags for ghc builds WARNINGS:=\ @@ -223,7 +217,6 @@ BUILDFLAGS=\ $(WARNINGS) \ $(INCLUDEPATHS) \ $(GHCLOWMEMFLAGS) $(CABALMACROSFLAGS) \ - -DPATCHLEVEL=$(PATCHLEVEL) \ -DDEVELOPMENT \ -DVERSION="\"$(VERSION)\"" \ # -fhide-source-paths \ diff --git a/hledger-ui/Hledger/UI/UIOptions.hs b/hledger-ui/Hledger/UI/UIOptions.hs index daf401770..81d049298 100644 --- a/hledger-ui/Hledger/UI/UIOptions.hs +++ b/hledger-ui/Hledger/UI/UIOptions.hs @@ -18,18 +18,19 @@ import Hledger.UI.Theme (themes, themeNames) -- cf Hledger.Cli.Version -packageversion :: String +packageversion :: PackageVersion +packageversion = #ifdef VERSION -packageversion = VERSION + VERSION #else -packageversion = "" + "" #endif -progname :: String +progname :: ProgramName progname = "hledger-ui" -prognameandversion :: String -prognameandversion = versionStringForProgname progname +prognameandversion :: VersionString +prognameandversion = versionString progname packageversion uiflags = [ -- flagNone ["debug-ui"] (setboolopt "rules-file") "run with no terminal output, showing console" diff --git a/hledger-web/Hledger/Web/WebOptions.hs b/hledger-web/Hledger/Web/WebOptions.hs index 35a1ac348..0ca73604c 100644 --- a/hledger-web/Hledger/Web/WebOptions.hs +++ b/hledger-web/Hledger/Web/WebOptions.hs @@ -20,18 +20,19 @@ import Hledger.Web.Settings (defhost, defport, defbaseurl) -- cf Hledger.Cli.Version -packageversion :: String +packageversion :: PackageVersion +packageversion = #ifdef VERSION -packageversion = VERSION + VERSION #else -packageversion = "" + "" #endif -progname :: String +progname :: ProgramName progname = "hledger-web" -prognameandversion :: String -prognameandversion = versionStringForProgname progname +prognameandversion :: VersionString +prognameandversion = versionString progname packageversion webflags :: [Flag RawOpts] diff --git a/hledger/Hledger/Cli.hs b/hledger/Hledger/Cli.hs index fea48cfee..4df9f4b27 100644 --- a/hledger/Hledger/Cli.hs +++ b/hledger/Hledger/Cli.hs @@ -17,7 +17,7 @@ module Hledger.Cli ( module Hledger, module System.Console.CmdArgs.Explicit, prognameandversion, - versionStringForProgname + versionString ) where @@ -31,9 +31,21 @@ import Hledger.Cli.DocFiles import Hledger.Cli.Utils import Hledger.Cli.Version --- | The program name and the best version information we can obtain --- from git describe or build variables. -prognameandversion = versionStringForProgname progname -versionStringForProgname = versionStringFor $$tGitInfoCwdTry +-- | The program name and version string for this build of the hledger tool, +-- including any git info available at build time. +prognameandversion :: String +prognameandversion = versionString progname packageversion + +-- | A helper to generate the best version string we can from the given +-- program name and package version strings, current os and architecture, +-- and any git info available at build time (commit hash, commit date, branch +-- name, patchlevel since latest release tag for that program's package). +-- Typically called for programs "hledger", "hledger-ui", or "hledger-web". +-- +-- The git info changes whenever any file in the repository changes. +-- Keeping this template haskell call here and not down in Hledger.Cli.Version +-- helps reduce the number of modules recompiled. +versionString :: ProgramName -> PackageVersion -> String +versionString = versionStringWith $$tGitInfoCwdTry -- unit tests (tests_Hledger_Cli) are defined in Hledger.Cli.Commands diff --git a/hledger/Hledger/Cli/Version.hs b/hledger/Hledger/Cli/Version.hs index 56aef68ae..74636ebed 100644 --- a/hledger/Hledger/Cli/Version.hs +++ b/hledger/Hledger/Cli/Version.hs @@ -4,79 +4,91 @@ Version number-related utilities. See also the Makefile. -} module Hledger.Cli.Version ( + ProgramName, + PackageVersion, + VersionString, packageversion, progname, - versionStringFor, + versionStringWith, ) where -import GitHash (GitInfo, giDescribe) +import GitHash (GitInfo, giHash, giCommitDate) import System.Info (os, arch) -import Hledger.Utils +import Data.List (intercalate) +import Data.Maybe (fromMaybe) --- | This package's version, passed in as VERSION build variable, or a generic description. -packageversion :: String +type ProgramName = String +type PackageVersion = String +type VersionString = String + +-- | The VERSION string defined with -D in this package's package.yaml/.cabal file +-- (by Shake setversion), if any. Normally a dotted number string with 1-3 components. +packageversion :: PackageVersion +packageversion = #ifdef VERSION -packageversion = VERSION + VERSION #else -packageversion = "dev build" + "" #endif --- | A period and the patch level (number of patches added since the package version), --- passed in as PATCHLEVEL build variable, or the empty string. --- If PATCHLEVEL is defined it must be a number, or this will fail. -patchlevel :: String -#ifdef PATCHLEVEL -patchlevel = "." ++ show (PATCHLEVEL :: Int) -#else -patchlevel = "" -#endif - --- | The version and patchlevel passed in as build variables, combined and prettified. --- This will raise an error if VERSION is has <1 or >3 components, --- or if PATCHLEVEL is defined but not a number. --- Used as a fallback if git describe is unavailable. -buildversion :: String -buildversion = prettify . splitAtElement '.' $ packageversion ++ patchlevel - where - prettify [major,minor,bugfix,patches] = - major ++ "." ++ minor ++ bugfix' ++ patches' - where - bugfix' = if bugfix == "0" then "" else '.' : bugfix - patches' = if patches == "0" then "" else '+' : patches - prettify [major,minor,bugfix] = prettify [major,minor,bugfix,"0"] - prettify [major,minor] = prettify [major,minor,"0","0"] - prettify [major] = prettify [major,"0","0","0"] - prettify [] = error' "VERSION is empty, please fix" -- PARTIAL: - prettify _ = error' "VERSION has too many components, please fix" - -- | The name of this package's main executable. -progname :: String +progname :: ProgramName progname = "hledger" --- | Given a program name, make a version string consisting of: +-- | Given possible git state info from the build directory (or an error message, which is ignored), +-- the name of a program (executable) in the currently building package, +-- and the package's version, make a complete version string. Here is the logic: +-- +-- * Program name, OS and architecture are always shown. +-- * The package version is always shown. +-- * If there is git info at build time, the latest commit hash and commit date are shown. +-- * (TODO, requires adding --match support to githash: +-- If there are tags matching THISPKG-[0-9]*, the latest one is used to calculate patch level +-- (number of commits since tag), and if non-zero, it and the branch name are shown.) -- --- * the program name --- * the output of "git describe" in the current repo at build time --- (last tag, commit count since then, HEAD's git hash); --- or if that fails, buildversion --- * the platform (OS) name --- * the processor architecture name. +-- Some example outputs: -- -versionStringFor :: Either String GitInfo -> String -> String -versionStringFor gitinfo progname = concat [ - progname - , " " - , either (const buildversion) giDescribe gitinfo - , ", " - , os' - , "-" - , arch - ] +-- * A homebrew binary, not built in git repo: hledger-ui 1.24, mac-aarch64 +-- * A CI release build, built in git repo at release tag: hledger-ui 1.24.1-g455b35293-20211210, mac-x86_64 +-- * (TODO) A dev build, built in git repo: hledger-ui 1.24.1+1-g4abd8ef10-20211210 (1.24-branch), mac-x86_64 +-- +-- This function requires git log to show the default (rfc2822-style) date format, +-- so that must not be overridden by a log.date git config variable. +-- +versionStringWith :: Either String GitInfo -> ProgramName -> PackageVersion -> VersionString +versionStringWith egitinfo progname packageversion = + concat [ progname , " " , version , ", " , os' , "-" , arch ] where os' | os == "darwin" = "mac" | os == "mingw32" = "windows" | otherwise = os + version = case egitinfo of + Left _err -> packageversion + Right gitinfo -> intercalate "-" [packageversion , hash, date] + where + hash = 'g' : take 9 (giHash gitinfo) -- like git describe + date = concat [year,mm,dd] + where + -- XXX PARTIAL: depends on git log's date format, which by default + -- is --date=default ("similar to --date=rfc2822"), but could be + -- overridden by a log.date config variable in repo or user git config. + _weekday:mon:day:_localtime:year:_offset:_ = words $ giCommitDate gitinfo + mm = fromMaybe mon $ lookup mon $ [ + ("Jan","01") + ,("Feb","02") + ,("Mar","03") + ,("Apr","04") + ,("May","05") + ,("Jun","06") + ,("Jul","07") + ,("Aug","08") + ,("Sep","09") + ,("Oct","10") + ,("Nov","11") + ,("Dec","12") + ] + dd = (if length day < 2 then ('0':) else id) day -- -- | Given a program name, return a precise platform-specific executable -- -- name suitable for naming downloadable binaries. Can raise an error if