{-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- -- Module : VCSWrapper.Git -- Copyright : 2011 Stephan Fortelny, Harald Jagenteufel -- License : GPL -- -- Maintainer : stephanfortelny at gmail.com, h.jagenteufel at gmail.com -- Stability : -- Portability : -- -- | Provides high-level Git functions like @commit@, @checkout@, @status@, @log@,... -- -- All functions of this module run in the 'Ctx' monad, common to all VCS. -- On unexpected behavior, these functions will throw a 'VCSException'. ----------------------------------------------------------------------------- module VCSWrapper.Git ( initDB , add , rm , commit , checkout , status , simpleLog , localBranches , revparse , remote , pull , push -- , clone -- reexport from VCSWrapper.Git.Process , runVcs , module VCSWrapper.Git.Types ) where import System.Directory import Control.Monad.Trans import qualified Control.Exception as Exc import VCSWrapper.Git.Parsers import VCSWrapper.Git.Process import VCSWrapper.Git.Types import VCSWrapper.Common.VCSMonad (runVcs) import Data.Maybe import qualified Data.List import Data.Text (Text) import qualified Data.Text as T (strip, pack) import Data.Monoid ((<>)) {- | Initialize a new git repository. Executes @git init@. -} initDB :: Bool -- ^ if 'True', this repository will be initialized as a bare repository (appends @--bare@ to the git command) -> Ctx () initDB bare = do let opts = if bare then ["--bare"] else [] gitExecWithoutResult "init-db" opts [] {- | Add files to the index. Executes @git add@. -} add :: [ FilePath ] -- ^ 'FilePath's to add to the index. -> Ctx () add paths = do let opts = "--" : paths gitExecWithoutResult "add" (map T.pack opts) [] {- | Remove files from the index and the working directory. Executes @git rm@. -} rm :: [ FilePath ] -- ^ 'FilePath's to remove. -> Ctx () rm paths = do let opts = "--" : map T.pack paths gitExecWithoutResult "rm" opts [] {- | Commit the current index or the specified files to the repository. Executes @git commit@. -} commit :: [ FilePath ] -- ^ 'FilePath's to be commited instead of the current index. Leave empty to commit the index. -> Maybe (Text, Text) -- ^ (Author name, email) -> Text -- ^ Commit message. Don't leave this empty. -> [Text] -- ^ Options to be passed to the git executable. -> Ctx () commit rsrcs mbAuthor logmsg extraopts = do case mbAuthor of Just (author, author_email) -> commit' (map T.pack rsrcs) logmsg extraopts ["--author", author <> " <" <> author_email <> ">"] Nothing -> commit' (map T.pack rsrcs) logmsg extraopts [] where commit' files logmsg extraopts authopts = do let msgopts = [ "-m", logmsg ] let opts = authopts ++ msgopts ++ extraopts ++ [ "--" ] ++ files gitExecWithoutResult "commit" opts [] {- | Checkout the index to some commit ID. Executes @git checkout@. -} checkout :: Maybe Text -- ^ Commit ID -> Maybe Text -- ^ Branchname. If specified, @git checkout -b \@ will be executed. -> Ctx () checkout rev branch = do let bopt = maybe [] (\b -> [ "-b", b ]) branch let copt = maybeToList rev gitExecWithoutResult "checkout" (bopt ++ copt) [] {- | Return status of the repository as a list of 'Status'. Executes @git status@. -} status :: Ctx [Status] status = do o <- gitExec "status" ["--porcelain"] [] return $ parseStatus o {- | Get all commit messages. Executes @git log@. -} simpleLog :: Maybe Text -- ^ The branch from which to get the commit messages. (If 'Nothing', the current branch will be used). -> Ctx [LogEntry] simpleLog mbBranch = do -- double dash on end prevent crash if branch and filename are equal o <- gitExec "log" ((branch mbBranch) ++ ["--pretty=tformat:commit:%H%n%an%n%ae%n%ai%n%s%n%b%x00", "--"]) [] return $ parseSimpleLog o where branch Nothing = [] branch (Just b) = [b] {- | Get all local branches. Executes @git branch@. -} localBranches :: Ctx (Text, [Text]) -- ^ (currently checked out branch, list of all other branches) localBranches = do o <- gitExec "branch" [] [] return $ parseBranches o {- | Get all remotes. Executes @git remote@. -} remote :: Ctx [Text] remote = do o <- gitExec "remote" [] [] return $ parseRemotes o {- | Push changes to the remote as configured in the git configuration. Executes @git push@. -} push :: Ctx () push = gitExecWithoutResult "push" [] [] {- | Pull changes from the remote as configured in the git configuration. If a merge conflict is detected, the error message is returned, otherwise 'Right ()' is returned. Executes @git pull@. -} pull :: Ctx (Either Text ()) pull = do o <- gitExec' "pull" [] [] case o of Right _ -> return $ Right () Left exc@(VCSException _ out _ _ _) -> if (parsePullMergeConflict out) then return $ Left out else Exc.throw exc {- | Rev-parse a revision. Executes @git rev-parse@. -} revparse :: Text -- ^ Revision to pass to rev-parse. -> Ctx (Text) revparse commit = do o <- gitExec "rev-parse" [commit] [] return $ T.strip o