{-# LANGUAGE OverloadedStrings #-}
module Main where
import Prelude
import System.Exit (exitFailure, exitSuccess)
import Control.Applicative ((<$>), (<*>),optional,pure)
import Data.Monoid (mempty, (<>))
import Data.Maybe (fromMaybe)
import Github.Data (Repo(..), GithubOwner(..), RepoRef(..))
import Github.Repos (userRepo)
import System.IO (hGetContents)
import System.Process (createProcess,StdStream(CreatePipe),proc,std_out)
import qualified Text.ParserCombinators.Parsec as P
import Data.Char (isSpace)
import System.Environment (getArgs, getProgName)
import qualified Options.Applicative.Builder.Internal as X
import qualified Options.Applicative as O
import qualified Options.Applicative.Help.Core as C
import qualified Options.Applicative.Help.Chunk as Ch
import qualified Text.PrettyPrint.ANSI.Leijen as L
data Repository = Repository {
repositoryName :: String
, userName :: String
} deriving Show
data Options = Options { repo :: Maybe Repository
, usingCwd :: Bool
} deriving Show
main :: IO ()
main = O.execParser (O.info (O.helper <*> choices) mempty) >>= start
choices :: O.Parser Options
choices = Options
<$> optional repository
<*> O.switch ( O.long "using-cwd" <>
O.help "Use git and current directory to obtain upstream." )
repository :: O.Parser Repository
repository = Repository
<$> O.strOption ( O.short 'r' <> O.long "repo" <>
O.help "Name of the repository that we will look up." )
<*> O.strOption ( O.short 'u' <> O.long "user" <>
O.help "Name of the user that we will look this repo up on." )
defStr :: String -> X.Mod X.ArgumentFields String -> O.Parser String
defStr a = def a . O.argument O.str
def :: a -> O.Parser a -> O.Parser a
def a = fmap (fromMaybe a) . O.optional
defaultPrefs = O.prefs mempty
usageHelp programName =
let i = (O.info (O.helper <*> choices) mempty)
str = (`L.displayS` "")
$ L.renderPretty 1.0 (O.prefColumns defaultPrefs)
$ C.helpText
$ C.usageHelp $ Ch.vcatChunks
[ pure . C.parserUsage defaultPrefs (O.infoParser i) . unwords $ programName : []
, fmap (L.indent 2) . O.infoProgDesc $ i ]
in putStrLn str
start :: Options -> IO ()
start opts = do
r <-
case repo opts of
Nothing -> case usingCwd opts of
True -> obtainOriginFromCurrentDirectory >>= \res ->
case res of
(Just (repo,user)) -> return (Just (Repository repo user))
_ -> putStrLn "Could not find git origin remote for current directory." >> return Nothing
False -> getProgName >>= usageHelp >> return Nothing
_ -> return (repo opts)
case r of
Just (Repository repo user) -> do
d <- userRepo user repo
case d of
Right repo -> inferUpstream repo
Left err -> do
putStrLn $ show err
exitFailure
_ -> exitFailure
obtainUpstreamRepo :: RepoRef -> IO ()
obtainUpstreamRepo (RepoRef ghUser repoName) = do
rd <- userRepo (githubOwnerLogin ghUser) repoName
case rd of
-- Print put the ssh repo url
Right repo -> putStrLn (repoSshUrl repo)
Left err -> do
putStrLn $ show err
exitFailure
inferUpstream :: Repo -> IO ()
inferUpstream repo = do
case (repoParent repo) of
Just repoParent -> obtainUpstreamRepo repoParent
Nothing -> exitSuccess -- No upstream, say nothing.
originParser = do
sequence (map P.char "origin")
P.many1 P.space
sequence (map P.char "https://github.com/") P.<|> sequence (map P.char "git@github.com:")
user <- P.many1 (P.satisfy ( \x -> not (isSpace x || x=='/' || x == '.')))
P.char '/'
repo <- P.many1 (P.satisfy ( \x -> not (isSpace x || x=='/' || x == '.')))
return (repo,user)
obtainOriginFromCurrentDirectory = do
(_, Just hout, _, _) <-
createProcess (proc "git" ["remote","-v"]){ std_out = CreatePipe }
originInfo <- hGetContents hout >>= return . lines >>= return . take 1 . filter isRight . map (P.parse originParser "")
return (case originInfo of
[Right x] -> Just x
_ -> Nothing)
isRight r = case r of
(Right _) -> True
_ -> False