module GitHUD.Git.Parse.Base (
  getGitRepoState
  ) where

import Control.Applicative ((<$>))
import Control.Concurrent (forkIO)
import Control.Concurrent.MVar (newEmptyMVar, takeMVar)

import GitHUD.Git.Types
import GitHUD.Git.Command
import GitHUD.Git.Parse.Status
import GitHUD.Git.Parse.Branch
import GitHUD.Git.Parse.Count

removeEndingNewline :: String -> String
removeEndingNewline :: String -> String
removeEndingNewline String
str = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
str

getGitRepoState :: IO GitRepoState
getGitRepoState :: IO GitRepoState
getGitRepoState = do
  -- Preparing MVars
  MVar String
mvLocalBranch <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvGitStatus <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvRemoteName <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvStashCount <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvCommitShortSHA <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvCommitTag <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar

  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ MVar String -> IO ()
gitCmdLocalBranchName MVar String
mvLocalBranch
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ MVar String -> IO ()
gitCmdPorcelainStatus MVar String
mvGitStatus
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ MVar String -> IO ()
gitCmdStashCount MVar String
mvStashCount
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ MVar String -> IO ()
gitCmdCommitShortSHA MVar String
mvCommitShortSHA
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ MVar String -> IO ()
gitCmdCommitTag MVar String
mvCommitTag

  String
localBranchName <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvLocalBranch)
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> MVar String -> IO ()
gitCmdRemoteName String
localBranchName MVar String
mvRemoteName

  String
remoteName <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvRemoteName
  GitLocalRepoChanges
repoState <- String -> GitLocalRepoChanges
gitParseStatus (String -> GitLocalRepoChanges)
-> IO String -> IO GitLocalRepoChanges
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvGitStatus
  String
stashCountStr <- MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvStashCount
  String
commitShortSHA <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvCommitShortSHA
  String
commitTag <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvCommitTag

  GitRepoState -> IO GitRepoState
fillGitRemoteRepoState GitRepoState
zeroGitRepoState {
    gitLocalRepoChanges :: GitLocalRepoChanges
gitLocalRepoChanges = GitLocalRepoChanges
repoState
    , gitRemote :: String
gitRemote = String
remoteName
    , gitLocalBranch :: String
gitLocalBranch = String
localBranchName
    , gitCommitShortSHA :: String
gitCommitShortSHA = String
commitShortSHA
    , gitCommitTag :: String
gitCommitTag = String
commitTag
    , gitStashCount :: Int
gitStashCount = (String -> Int
getCount String
stashCountStr)
  }

fillGitRemoteRepoState :: GitRepoState
                       -> IO GitRepoState
fillGitRemoteRepoState :: GitRepoState -> IO GitRepoState
fillGitRemoteRepoState repoState :: GitRepoState
repoState@( GitRepoState { gitRemote :: GitRepoState -> String
gitRemote = String
""} ) = GitRepoState -> IO GitRepoState
forall (m :: * -> *) a. Monad m => a -> m a
return GitRepoState
repoState
fillGitRemoteRepoState GitRepoState
repoState = do
  MVar String
mvRemoteBranchName <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvMergeBase <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvCommitsToPull <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvCommitsToPush <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar

  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> MVar String -> IO ()
gitCmdRemoteBranchName (GitRepoState -> String
gitLocalBranch GitRepoState
repoState) MVar String
mvRemoteBranchName
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> MVar String -> IO ()
gitCmdMergeBase (GitRepoState -> String
gitLocalBranch GitRepoState
repoState) MVar String
mvMergeBase
  String
remoteBranch <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvRemoteBranchName)
  String
mergeBase <- String -> String
removeEndingNewline (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvMergeBase)

  let fullRemoteBranchName :: String
fullRemoteBranchName = String -> String -> String
buildFullyQualifiedRemoteBranchName (GitRepoState -> String
gitRemote GitRepoState
repoState) String
remoteBranch

  -- TODO: gbataille - Check for merge-base. If none, don't execute remote part
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> String -> MVar String -> IO ()
gitCmdRevToPush String
fullRemoteBranchName String
"HEAD" MVar String
mvCommitsToPush
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> String -> MVar String -> IO ()
gitCmdRevToPull String
fullRemoteBranchName String
"HEAD" MVar String
mvCommitsToPull

  (Int
mergeBranchToPull, Int
mergeBranchToPush) <- String -> String -> IO (Int, Int)
getRemoteMasterMergeState String
mergeBase String
fullRemoteBranchName

  String
commitsToPushStr <- MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvCommitsToPush
  let commitsToPush :: Int
commitsToPush = String -> Int
getCount String
commitsToPushStr
  String
commitsToPullStr <- MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvCommitsToPull
  let commitsToPull :: Int
commitsToPull = String -> Int
getCount String
commitsToPullStr

  GitRepoState -> IO GitRepoState
forall (m :: * -> *) a. Monad m => a -> m a
return GitRepoState
repoState {
    gitRemoteTrackingBranch :: String
gitRemoteTrackingBranch = String
remoteBranch
    , gitCommitsToPull :: Int
gitCommitsToPull = Int
commitsToPull
    , gitCommitsToPush :: Int
gitCommitsToPush = Int
commitsToPush
    , gitMergeBranchCommitsToPull :: Int
gitMergeBranchCommitsToPull = Int
mergeBranchToPull
    , gitMergeBranchCommitsToPush :: Int
gitMergeBranchCommitsToPush = Int
mergeBranchToPush
  }

getRemoteMasterMergeState :: String     -- ^ the merge base
                          -> String     -- ^ the fully qualified remote branch name
                          -> IO (Int, Int)    -- ^ tuple containing (to pull, to push)
getRemoteMasterMergeState :: String -> String -> IO (Int, Int)
getRemoteMasterMergeState String
"" String
_ = (Int, Int) -> IO (Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
0, Int
0)
getRemoteMasterMergeState String
_ String
fullRemoteBranchName = do
  MVar String
mvMergeBranchCommitsToPull <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar
  MVar String
mvMergeBranchCommitsToPush <- IO (MVar String)
forall a. IO (MVar a)
newEmptyMVar

  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> String -> MVar String -> IO ()
gitCmdRevToPush String
"origin/master" String
fullRemoteBranchName MVar String
mvMergeBranchCommitsToPush
  IO () -> IO ThreadId
forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ String -> String -> MVar String -> IO ()
gitCmdRevToPull String
"origin/master" String
fullRemoteBranchName MVar String
mvMergeBranchCommitsToPull

  String
mergeBranchCommitsToRMasterStr <- MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvMergeBranchCommitsToPull
  let mergeBranchCommitsToRMaster :: Int
mergeBranchCommitsToRMaster = String -> Int
getCount String
mergeBranchCommitsToRMasterStr
  String
mergeBranchCommitsToMergeStr <- MVar String -> IO String
forall a. MVar a -> IO a
takeMVar MVar String
mvMergeBranchCommitsToPush
  let mergeBranchCommitsToMerge :: Int
mergeBranchCommitsToMerge = String -> Int
getCount String
mergeBranchCommitsToMergeStr

  (Int, Int) -> IO (Int, Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
mergeBranchCommitsToRMaster, Int
mergeBranchCommitsToMerge)