Add the "smtpdelay" config option
[stgit] / stgit / commands / branch.py
CommitLineData
7b1ba1a6
CL
1"""Branch command
2"""
3
4__copyright__ = """
5Copyright (C) 2005, Chuck Lever <cel@netapp.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
cc3db2b1 21import sys, os, time
7b1ba1a6
CL
22from optparse import OptionParser, make_option
23
24from stgit.commands.common import *
25from stgit.utils import *
26from stgit import stack, git
27
28
29help = 'manage development branches'
30usage = """%prog [options] branch-name [commit-id]
31
cc3db2b1 32Create, clone, switch between, rename, or delete development branches
7b1ba1a6
CL
33within a git repository. By default, a single branch called 'master'
34is always created in a new repository. This subcommand allows you to
cc3db2b1 35manage several patch series in the same repository via GIT branches.
7b1ba1a6
CL
36
37When displaying the branches, the names can be prefixed with
a8032a85
CL
38's' (StGIT managed) or 'p' (protected).
39
40If not given any options, switch to the named branch."""
7b1ba1a6
CL
41
42options = [make_option('-c', '--create',
43 help = 'create a new development branch',
44 action = 'store_true'),
cc3db2b1
CL
45 make_option('--clone',
46 help = 'clone the contents of the current branch',
47 action = 'store_true'),
bad9dcfc
CL
48 make_option('--convert',
49 help = 'switch between old and new format branches',
50 action = 'store_true'),
7b1ba1a6
CL
51 make_option('--delete',
52 help = 'delete an existing development branch',
53 action = 'store_true'),
54 make_option('--force',
55 help = 'force a delete when the series is not empty',
56 action = 'store_true'),
57 make_option('-l', '--list',
58 help = 'list branches contained in this repository',
59 action = 'store_true'),
0b4b9499
CL
60 make_option('-p', '--protect',
61 help = 'prevent "stg pull" from modifying this branch',
62 action = 'store_true'),
7b1ba1a6
CL
63 make_option('-r', '--rename',
64 help = 'rename an existing development branch',
0b4b9499
CL
65 action = 'store_true'),
66 make_option('-u', '--unprotect',
67 help = 'allow "stg pull" to modify this branch',
7b1ba1a6
CL
68 action = 'store_true')]
69
70
fe4f6d58
CM
71def __is_current_branch(branch_name):
72 return crt_series.get_branch() == branch_name
7b1ba1a6 73
862ba51a 74def __print_branch(branch_name, length):
7b1ba1a6
CL
75 initialized = ' '
76 current = ' '
0b4b9499 77 protected = ' '
ebfd0156
CL
78
79 branch = stack.Series(branch_name)
80
2d00440c 81 if branch.is_initialised():
7b1ba1a6 82 initialized = 's'
fe4f6d58 83 if __is_current_branch(branch_name):
7b1ba1a6 84 current = '>'
ebfd0156 85 if branch.get_protected():
0b4b9499 86 protected = 'p'
862ba51a
CL
87 print current + ' ' + initialized + protected + '\t' + \
88 branch_name.ljust(length) + ' | ' + branch.get_description()
7b1ba1a6 89
fe4f6d58 90def __delete_branch(doomed_name, force = False):
ebfd0156
CL
91 doomed = stack.Series(doomed_name)
92
93 if doomed.get_protected():
0b4b9499
CL
94 raise CmdException, 'This branch is protected. Delete is not permitted'
95
fe4f6d58
CM
96 print 'Deleting branch "%s"...' % doomed_name,
97 sys.stdout.flush()
98
99 if __is_current_branch(doomed_name):
100 check_local_changes()
101 check_conflicts()
102 check_head_top_equal()
103
104 if doomed_name != 'master':
105 git.switch_branch('master')
7b1ba1a6 106
ebfd0156 107 doomed.delete(force)
7b1ba1a6
CL
108
109 if doomed_name != 'master':
110 git.delete_branch(doomed_name)
111
fe4f6d58 112 print 'done'
7b1ba1a6 113
7b1ba1a6
CL
114def func(parser, options, args):
115
116 if options.create:
117
118 if len(args) == 0 or len(args) > 2:
119 parser.error('incorrect number of arguments')
fe4f6d58
CM
120
121 check_local_changes()
122 check_conflicts()
123 check_head_top_equal()
124
7b1ba1a6
CL
125 tree_id = None
126 if len(args) == 2:
2fef9462 127 tree_id = git_id(args[1])
7b1ba1a6
CL
128
129 git.create_branch(args[0], tree_id)
130 stack.Series(args[0]).init()
131
132 print 'Branch "%s" created.' % args[0]
133 return
134
cc3db2b1
CL
135 elif options.clone:
136
137 if len(args) == 0:
138 clone = crt_series.get_branch() + \
139 time.strftime('-%C%y%m%d-%H%M%S')
140 elif len(args) == 1:
141 clone = args[0]
142 else:
143 parser.error('incorrect number of arguments')
144
145 check_local_changes()
146 check_conflicts()
147 check_head_top_equal()
148
149 print 'Cloning current branch to "%s"...' % clone,
150 sys.stdout.flush()
151 crt_series.clone(clone)
152 print 'done'
153
154 return
155
bad9dcfc
CL
156 elif options.convert:
157
158 if len(args) != 0:
159 parser.error('incorrect number of arguments')
160
161 crt_series.convert()
162 return
163
7b1ba1a6
CL
164 elif options.delete:
165
166 if len(args) != 1:
167 parser.error('incorrect number of arguments')
fe4f6d58 168 __delete_branch(args[0], options.force)
7b1ba1a6
CL
169 return
170
171 elif options.list:
172
173 if len(args) != 0:
174 parser.error('incorrect number of arguments')
175
bae29ddd 176 branches = os.listdir(os.path.join(git.get_base_dir(), 'refs', 'heads'))
7b1ba1a6 177 branches.sort()
862ba51a 178 max_len = max([len(i) for i in branches])
7b1ba1a6
CL
179
180 print 'Available branches:'
181 for i in branches:
862ba51a 182 __print_branch(i, max_len)
7b1ba1a6
CL
183 return
184
0b4b9499
CL
185 elif options.protect:
186
187 if len(args) == 0:
5fab7247 188 branch_name = crt_series.get_branch()
0b4b9499 189 elif len(args) == 1:
2d00440c 190 branch_name = args[0]
0b4b9499
CL
191 else:
192 parser.error('incorrect number of arguments')
2d00440c 193 branch = stack.Series(branch_name)
0b4b9499 194
2d00440c 195 if not branch.is_initialised():
fe4f6d58
CM
196 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
197 % branch_name
0b4b9499 198
2d00440c 199 print 'Protecting branch "%s"...' % branch_name,
fa08ec08 200 sys.stdout.flush()
2d00440c 201 branch.protect()
fa08ec08
CM
202 print 'done'
203
0b4b9499
CL
204 return
205
7b1ba1a6
CL
206 elif options.rename:
207
208 if len(args) != 2:
209 parser.error('incorrect number of arguments')
660ba985 210
fe4f6d58
CM
211 if __is_current_branch(args[0]):
212 raise CmdException, 'Renaming the current branch is not supported'
213
660ba985
CL
214 stack.Series(args[0]).rename(args[1])
215
216 print 'Renamed branch "%s" as "%s".' % (args[0], args[1])
217
7b1ba1a6
CL
218 return
219
0b4b9499
CL
220 elif options.unprotect:
221
222 if len(args) == 0:
5fab7247 223 branch_name = crt_series.get_branch()
0b4b9499 224 elif len(args) == 1:
2d00440c 225 branch_name = args[0]
0b4b9499
CL
226 else:
227 parser.error('incorrect number of arguments')
2d00440c 228 branch = stack.Series(branch_name)
0b4b9499 229
2d00440c 230 if not branch.is_initialised():
fe4f6d58
CM
231 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
232 % branch_name
0b4b9499 233
2d00440c 234 print 'Unprotecting branch "%s"...' % branch_name,
fa08ec08 235 sys.stdout.flush()
2d00440c 236 branch.unprotect()
fa08ec08
CM
237 print 'done'
238
0b4b9499
CL
239 return
240
7b1ba1a6
CL
241 elif len(args) == 1:
242
fe4f6d58
CM
243 if __is_current_branch(args[0]):
244 raise CmdException, 'Branch "%s" is already the current branch' \
245 % args[0]
246
247 check_local_changes()
248 check_conflicts()
249 check_head_top_equal()
9756a202 250
7b1ba1a6
CL
251 print 'Switching to branch "%s"...' % args[0],
252 sys.stdout.flush()
253
254 git.switch_branch(args[0])
255
256 print 'done'
257 return
258
259 # default action: print the current branch
260 if len(args) != 0:
261 parser.error('incorrect number of arguments')
262
5fab7247 263 print crt_series.get_branch()