packages feed

githash (empty) → 0.1.0.0

raw patch · 8 files changed

+339/−0 lines, 8 filesdep +basedep +bytestringdep +directorysetup-changed

Dependencies added: base, bytestring, directory, filepath, githash, hspec, process, template-haskell, temporary

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# ChangeLog for githash++## 0.1.0.0++* Initial release
+ LICENSE view
@@ -0,0 +1,28 @@+Copyright (c) 2018, Michael Snoyman, 2015, Adam C. Foltzer+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+  list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+  this list of conditions and the following disclaimer in the documentation+  and/or other materials provided with the distribution.++* Neither the name of gitrev nor the names of its+  contributors may be used to endorse or promote products derived from+  this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ README.md view
@@ -0,0 +1,22 @@+# githash++[![Build Status](https://travis-ci.org/snoyberg/githash.svg?branch=master)](https://travis-ci.org/snoyberg/githash)+[![Build status](https://ci.appveyor.com/api/projects/status/g5asio63nfjjhx50/branch/master?svg=true)](https://ci.appveyor.com/project/snoyberg/githash/branch/master)++Some handy Template Haskell splices for including the current git hash+and branch in the code of your project. Useful for including in panic+messages, `--version` output, or diagnostic info for more informative+bug reports.++Most of the complication in the `GitHash` module is due to the various+places the current git hash might be stored:++1. Detached HEAD: the hash is in `.git/HEAD`+2. On a branch or tag: the hash is in a file pointed to by `.git/HEAD`+in a location like `.git/refs/heads`+3. On a branch or tag but in a repository with packed refs: the hash is+in `.git/packed-refs`++These situations all arise under normal development workflows, but+there might be further scenarios that cause problems. Let me know if+you run into them!
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ githash.cabal view
@@ -0,0 +1,62 @@+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 391f23a7714fa5cdd1e4919cca1972387f65d007ebba0047608a34231d283619++name:           githash+version:        0.1.0.0+synopsis:       Compile git revision info into Haskell projects+description:    Please see the README and documentation at <https://www.stackage.org/package/githash>+category:       Development+homepage:       https://github.com/snoyberg/githash#readme+bug-reports:    https://github.com/snoyberg/githash/issues+author:         Michael Snoyman, Adam C. Foltzer+maintainer:     michael@snoyman.com+license:        BSD3+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10+extra-source-files:+    ChangeLog.md+    README.md++source-repository head+  type: git+  location: https://github.com/snoyberg/githash++library+  exposed-modules:+      GitHash+  other-modules:+      Paths_githash+  hs-source-dirs:+      src+  build-depends:+      base >=4.9.1 && <5+    , bytestring+    , directory+    , filepath+    , process+    , template-haskell+  default-language: Haskell2010++test-suite githash-spec+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      GitHashSpec+      Paths_githash+  hs-source-dirs:+      test+  build-depends:+      base >=4.9.1 && <5+    , bytestring+    , directory+    , filepath+    , githash+    , hspec+    , process+    , template-haskell+    , temporary+  default-language: Haskell2010
+ src/GitHash.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module      :  $Header$+-- Copyright   :  (c) 2018 Michael Snoyman, 2015 Adam C. Foltzer+-- License     :  BSD3+-- Maintainer  :  michael@snoyman.com+-- Stability   :  provisional+-- Portability :  portable+--+-- Some handy Template Haskell splices for including the current git+-- hash and branch in the code of your project. Useful for including+-- in panic messages, @--version@ output, or diagnostic info for more+-- informative bug reports.+--+-- > {-# LANGUAGE TemplateHaskell #-}+-- > import GitHash+-- >+-- > panic :: String -> a+-- > panic msg = error panicMsg+-- >   where panicMsg =+-- >           concat [ "[panic ", $(gitBranch), "@", $(gitHash)+-- >                  , " (", $(gitCommitDate), ")"+-- >                  , " (", $(gitCommitCount), " commits in HEAD)"+-- >                  , dirty, "] ", msg ]+-- >         dirty | $(gitDirty) = " (uncommitted files present)"+-- >               | otherwise   = ""+-- >+-- > main = panic "oh no!"+--+-- > % stack runghc Example.hs+-- > Example.hs: [panic master@2ae047ba5e4a6f0f3e705a43615363ac006099c1 (Mon Jan 11 11:50:59 2016 -0800) (14 commits in HEAD) (uncommitted files present)] oh no!+--+-- @since 0.1.0.0+module GitHash+  ( -- * Types+    GitInfo+  , GitHashException (..)+    -- ** Getters+  , giHash+  , giBranch+  , giDirty+  , giCommitDate+  , giCommitCount+    -- * Creators+  , getGitInfo+  , getGitRoot+    -- * Template Haskell+  , tGitInfo+  , tGitInfoCwd+  ) where++import Control.Applicative+import Control.Exception+import Control.Monad+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import Data.Maybe+import Data.Typeable (Typeable)+import Language.Haskell.TH+import Language.Haskell.TH.Syntax+import System.Directory+import System.Exit+import System.FilePath+import System.IO.Error (isDoesNotExistError)+import System.Process+import Text.Read (readMaybe)++-- | Various pieces of information about a Git repository.+--+-- @since 0.1.0.0+data GitInfo = GitInfo+  { _giHash :: !String+  , _giBranch :: !String+  , _giDirty :: !Bool+  , _giCommitDate :: !String+  , _giCommitCount :: !Int+  , _giFiles :: ![FilePath]+  }+  deriving (Lift, Show)++-- | The hash of the most recent commit.+--+-- @since 0.1.0.0+giHash :: GitInfo -> String+giHash = _giHash++-- | The hash of the most recent commit.+--+-- @since 0.1.0.0+giBranch :: GitInfo -> String+giBranch = _giBranch++giDirty :: GitInfo -> Bool+giDirty = _giDirty++giCommitDate :: GitInfo -> String+giCommitDate = _giCommitDate++giCommitCount :: GitInfo -> Int+giCommitCount = _giCommitCount++-- | Get the 'GitInfo' for the given root directory. Root directory+-- should be the directory containing the @.git@ directory.+--+-- @since 0.1.0.0+getGitInfo :: FilePath -> IO (Either GitHashException GitInfo)+getGitInfo root = try $ do+  -- a lot of bookkeeping to record the right dependencies+  let hd         = root </> ".git" </> "HEAD"+      index      = root </> ".git" </> "index"+      packedRefs = root </> ".git" </> "packed-refs"+  ehdRef <- try $ B.readFile hd+  files1 <-+    case ehdRef of+      Left e+        | isDoesNotExistError e -> return []+        | otherwise -> throwIO $ GHECouldn'tReadFile hd e+      Right hdRef -> do+        -- the HEAD file either contains the hash of a detached head+        -- or a pointer to the file that contains the hash of the head+        case B.splitAt 5 hdRef of+          -- pointer to ref+          ("ref: ", relRef) -> do+            let ref = root </> ".git" </> B8.unpack relRef+            refExists <- doesFileExist ref+            return $ if refExists then [ref] else []+          -- detached head+          _hash -> return [hd]+  -- add the index if it exists to set the dirty flag+  indexExists <- doesFileExist index+  let files2 = if indexExists then [index] else []+  -- if the refs have been packed, the info we're looking for+  -- might be in that file rather than the one-file-per-ref case+  -- handled above+  packedExists <- doesFileExist packedRefs+  let files3 = if packedExists then [packedRefs] else []++      _giFiles = concat [files1, files2, files3]+      run args = do+        eres <- runGit root args+        case eres of+          Left e -> throwIO e+          Right str -> return $ takeWhile (/= '\n') str++  _giHash <- run ["rev-parse", "HEAD"]+  _giBranch <- run ["rev-parse", "--abbrev-ref", "HEAD"]++  dirtyString <- run ["status", "--porcelain"]+  let _giDirty = not $ null (dirtyString :: String)++  commitCount <- run ["rev-list", "HEAD", "--count"]+  _giCommitCount <-+    case readMaybe commitCount of+      Nothing -> throwIO $ GHEInvalidCommitCount root commitCount+      Just x -> return x++  _giCommitDate <- run ["log", "HEAD", "-1", "--format=%cd"]++  return GitInfo {..}++-- | Get the root directory of the Git repo containing the given file+-- path.+--+-- @since 0.1.0.0+getGitRoot :: FilePath -> IO (Either GitHashException FilePath)+getGitRoot dir = fmap (takeWhile (/= '\n')) `fmap` (runGit dir ["rev-parse", "--show-toplevel"])++runGit root args = do+  let cp = (proc "git" args) { cwd = Just root }+  (ec, out, err) <- readCreateProcessWithExitCode cp ""+  case ec of+    ExitSuccess -> return $ Right out+    ExitFailure _ -> return $ Left $ GHEGitRunFailed root args ec out err++-- | Exceptions which can occur when using this library's functions.+--+-- @since 0.1.0.0+data GitHashException+  = GHECouldn'tReadFile !FilePath !IOException+  | GHEInvalidCommitCount !FilePath !String+  | GHEGitRunFailed !FilePath ![String] !ExitCode !String !String+  deriving (Show, Typeable)+instance Exception GitHashException++-- | Load up the 'GitInfo' value at compile time for the given+-- directory.+--+-- @since 0.1.0.0+tGitInfo :: FilePath -> Q (TExp GitInfo)+tGitInfo fp = unsafeTExpCoerce $ do+  gi <- runIO $+    getGitRoot fp >>=+    either throwIO return >>=+    getGitInfo >>=+    either throwIO return+  mapM_ addDependentFile (_giFiles gi)+  lift (gi :: GitInfo) -- adding type sig to make the unsafe look slightly better++-- | Load up the 'GitInfo' value at compile time for the current+-- working directory.+--+-- @since 0.1.0.0+tGitInfoCwd :: Q (TExp GitInfo)+tGitInfoCwd = tGitInfo "."
+ test/GitHashSpec.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE TemplateHaskell #-}+module GitHashSpec+  ( spec+  ) where++import GitHash+import Test.Hspec++spec :: Spec+spec = do+  it "sanity" $ do+    let gi = $$tGitInfoCwd+    giCommitCount gi `shouldSatisfy` (>= 1)
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}