~jojo/Carth

f5de3cd22e973b420fe213b53e860c6e889bbb6a — JoJo 1 year, 7 months ago aad7ebb
Add `carth version`. Bake package.yaml version & commit into binary

Bake uses templatehaskell. At compiletime of the carth compiler,
version numbers are read from package.yaml and commit hash & date is
gotten from shell command.

Something to keep in mind is that the file with the baked values is
not recompiled by default. Luckily it was solved easily. Any
modification of package.yaml forces rebuild, so changing version in
the file will change version in the binary. To force recompilation
when git status changes, use templatehaskell "command"
`qAddDependentFile ".git/index"`, which seems to add that file to some
watchlist in the metadata of the compiled library? It works anywho.
3 files changed, 63 insertions(+), 1 deletions(-)

M app/GetConfig.hs
A app/Prebaked.hs
M package.yaml
M app/GetConfig.hs => app/GetConfig.hs +18 -1
@@ 1,4 1,4 @@
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TupleSections, TemplateHaskell #-}

-- | Read all the different kinds of configurtion options for Carth. Command
--   line options, config files, environment variables, etc.


@@ 13,6 13,7 @@ import Data.Function
import Control.Monad

import Config
import Prebaked


getConfig :: IO Config


@@ 28,6 29,7 @@ getConfig = do
            putStrLn usageSubs
            exitFailure
        "help" : a : _ | subCompile a -> usageCompile
        "version" : _ -> printVersion >> exitSuccess
        a : _ -> do
            putStrLn ("Error: `" ++ a ++ "` is not a valid subcommand\n")
            putStrLn usageSubs


@@ 43,6 45,7 @@ usageSubs = unlines
    , ""
    , "Available subcommands are:"
    , "  c, compile       Compile a source file"
    , "     version       Show version information"
    , ""
    , "See `carth help SUBCOMMAND` for help on a specific subcommand"
    ]


@@ 92,3 95,17 @@ compileOpts =
        "Output filepath"
    , Option [] ["debug"] (NoArg (\c -> c { debug = True })) "Enable debugging"
    ]

printVersion :: IO ()
printVersion = do
    let (major, minor, patch) = version
    let versionStr = concat [show major, ".", show minor, ".", show patch]
    putStrLn ("Carth " ++ versionStr)
    putStrLn ("git: " ++ commitHash ++ " (" ++ commitDate ++ ")")

version :: (Int, Int, Int)
version = $(readCompilerVersion)

commitHash :: String
commitDate :: String
(commitHash, commitDate) = $(getCommit)

A app/Prebaked.hs => app/Prebaked.hs +44 -0
@@ 0,0 1,44 @@
module Prebaked (readCompilerVersion, getCommit) where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax (Lift(..), qAddDependentFile)
import Data.Maybe
import qualified Text.Megaparsec as M
import qualified Text.Megaparsec.Char as MC
import qualified Text.Megaparsec.Char.Lexer as ML
import Data.Void
import System.Process

type Parser = M.Parsec Void String

pversion :: Parser (Int, Int, Int, Int)
pversion = do
    MC.string "version:" >> MC.space
    a <- num
    b <- dot >> num
    c <- dot >> num
    d <- dot >> num
    pure (a, b, c, d)
  where
    num = ML.decimal
    dot = MC.char '.'

readCompilerVersion :: Q Exp
readCompilerVersion = do
    s <- runIO (readFile "package.yaml")
    let (_, major, minor, patch) =
            head (catMaybes (map (M.parseMaybe pversion) (lines s)))
    lift (major, minor, patch)

getCommit :: Q Exp
getCommit =
    qAddDependentFile ".git/index"
        >> runIO
            (do
                c <- fmap (head . lines)
                    $ readProcess "git" ["rev-parse", "--short", "HEAD"] ""
                d <- fmap (head . lines)
                    $ readProcess "git" ["show", "-s", "--format=%ci", c] ""
                pure (c, d)
            )
        >>= lift

M package.yaml => package.yaml +1 -0
@@ 33,6 33,7 @@ dependencies:
- bytestring
- utf8-string
- process
- template-haskell

library:
  source-dirs: src