1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE RecordWildCards #-}
module Opts where
import Paths_git_deli (version)
import Data.Version (showVersion)
import Options.Applicative
data DeliOpts = DeliOpts
{ doParents :: [String]
, doBranches :: [String]
} deriving (Show)
deliOpts :: Parser DeliOpts
deliOpts = do
doParents <-
many . strOption
$ short 'p'
<> long "parent"
<> help
"force the new delinearized commit to be a descendant of this commit"
doBranches <-
many . strOption
$ short 'b'
<> long "branch"
<> help
"delinearize the commit into a given named branch, updating the branch to the new commit (implies commit descendancy from the original branch)"
pure DeliOpts {..}
data Cmd
= CmdHead
{ chMsg :: Maybe String
, chSetBase :: [String]
}
| CmdEat
{ ceBase :: Maybe String
, ceTarget :: Maybe String
, ceOntoHead :: Maybe String
, ceDOpts :: DeliOpts
}
| CmdCommit
{ ccGitCommitArgs :: [String]
, ccDOpts :: DeliOpts
}
deriving (Show)
cmdHead = do
chMsg <-
optional
$ strOption
(short 'm'
<> long "msg"
<> metavar "message"
<> value "DELI-HEAD"
<> showDefault
<> help "commit message on the head")
chSetBase <-
asum
[ some
(strOption
$ short 'b'
<> long "base"
<> metavar "ref"
<> help
"set the base commit manually (can be specified multiple times; default: HEAD)")
, flag' [] $ long "no-base" <> help "do not set any base commit"
, pure ["HEAD"]
]
pure CmdHead {..}
-- TODO this deserves ApplicativeDo (probably name the combnations of possibilities)
cmdEat =
let ceBT =
asum
[ (Nothing, ) . Just
<$> strArgument
(metavar "TARGET"
<> help
"eat commits towards TARGET from a merge-base with DELI-HEAD (if unspecified, assumes current HEAD)")
, (,)
<$> fmap
Just
(strArgument
$ metavar "RANGE-BASE"
<> help "parent of the first commit to eat")
<*> fmap
Just
(strArgument
$ metavar "RANGE-END" <> help "last commit to eat")
, pure (Nothing, Nothing)
]
ceOntoHead =
optional . strOption
$ long "onto"
<> metavar "DELI-HEAD"
<> help
"transplant commits onto a given deli-head (if unspecified, git-deli tries to use the first one that appears in linear history)"
in uncurry CmdEat <$> ceBT <*> ceOntoHead <*> deliOpts
cmdCommit = do
ccDOpts <- deliOpts
ccGitCommitArgs <-
many
$ strArgument
(metavar "git-commit-option"
<> help "arguments passed to git-commit(1)")
pure CmdCommit {..}
-- TODO invent a front-end for merging of 2 different deli-heads
-- TODO: base commit management
cmd :: Parser Cmd
cmd =
hsubparser
$ mconcat
[ command "head"
$ info cmdHead
$ progDesc "Create and manage multi-branch heads"
, command "eat"
$ info cmdEat
$ progDesc "Delinearize commit histories"
, command "commit"
$ info cmdCommit
$ progDesc "Record changes to the repository"
]
data Opts = Opts
{ oCmd :: Cmd
} deriving (Show)
opts :: Parser Opts
opts = Opts <$> cmd
parseOpts :: IO Opts
parseOpts =
customExecParser (prefs $ showHelpOnEmpty)
$ info
(opts <**> helper <**> simpleVersioner (showVersion version))
(fullDesc
<> header "git-deli -- delinearized git workflow"
<> (footer
"This program is free software; see LICENSE file for details."))
|