##// END OF EJS Templates
mq: add --no-backup for qpush/qpop/qgoto
Patrick Mezard -
r16635:9d76320d stable
parent child Browse files
Show More
@@ -1,3455 +1,3462 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''manage a stack of patches
8 '''manage a stack of patches
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use :hg:`help command` for more details)::
17 Common tasks (use :hg:`help command` for more details)::
18
18
19 create new patch qnew
19 create new patch qnew
20 import existing patch qimport
20 import existing patch qimport
21
21
22 print patch series qseries
22 print patch series qseries
23 print applied patches qapplied
23 print applied patches qapplied
24
24
25 add known patch to applied stack qpush
25 add known patch to applied stack qpush
26 remove patch from applied stack qpop
26 remove patch from applied stack qpop
27 refresh contents of top applied patch qrefresh
27 refresh contents of top applied patch qrefresh
28
28
29 By default, mq will automatically use git patches when required to
29 By default, mq will automatically use git patches when required to
30 avoid losing file mode changes, copy records, binary files or empty
30 avoid losing file mode changes, copy records, binary files or empty
31 files creations or deletions. This behaviour can be configured with::
31 files creations or deletions. This behaviour can be configured with::
32
32
33 [mq]
33 [mq]
34 git = auto/keep/yes/no
34 git = auto/keep/yes/no
35
35
36 If set to 'keep', mq will obey the [diff] section configuration while
36 If set to 'keep', mq will obey the [diff] section configuration while
37 preserving existing git patches upon qrefresh. If set to 'yes' or
37 preserving existing git patches upon qrefresh. If set to 'yes' or
38 'no', mq will override the [diff] section and always generate git or
38 'no', mq will override the [diff] section and always generate git or
39 regular patches, possibly losing data in the second case.
39 regular patches, possibly losing data in the second case.
40
40
41 It may be desirable for mq changesets to be kept in the secret phase (see
41 It may be desirable for mq changesets to be kept in the secret phase (see
42 :hg:`help phases`), which can be enabled with the following setting::
42 :hg:`help phases`), which can be enabled with the following setting::
43
43
44 [mq]
44 [mq]
45 secret = True
45 secret = True
46
46
47 You will by default be managing a patch queue named "patches". You can
47 You will by default be managing a patch queue named "patches". You can
48 create other, independent patch queues with the :hg:`qqueue` command.
48 create other, independent patch queues with the :hg:`qqueue` command.
49 '''
49 '''
50
50
51 from mercurial.i18n import _
51 from mercurial.i18n import _
52 from mercurial.node import bin, hex, short, nullid, nullrev
52 from mercurial.node import bin, hex, short, nullid, nullrev
53 from mercurial.lock import release
53 from mercurial.lock import release
54 from mercurial import commands, cmdutil, hg, scmutil, util, revset
54 from mercurial import commands, cmdutil, hg, scmutil, util, revset
55 from mercurial import repair, extensions, url, error, phases
55 from mercurial import repair, extensions, url, error, phases
56 from mercurial import patch as patchmod
56 from mercurial import patch as patchmod
57 import os, re, errno, shutil
57 import os, re, errno, shutil
58
58
59 commands.norepo += " qclone"
59 commands.norepo += " qclone"
60
60
61 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
61 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
62
62
63 cmdtable = {}
63 cmdtable = {}
64 command = cmdutil.command(cmdtable)
64 command = cmdutil.command(cmdtable)
65
65
66 # Patch names looks like unix-file names.
66 # Patch names looks like unix-file names.
67 # They must be joinable with queue directory and result in the patch path.
67 # They must be joinable with queue directory and result in the patch path.
68 normname = util.normpath
68 normname = util.normpath
69
69
70 class statusentry(object):
70 class statusentry(object):
71 def __init__(self, node, name):
71 def __init__(self, node, name):
72 self.node, self.name = node, name
72 self.node, self.name = node, name
73 def __repr__(self):
73 def __repr__(self):
74 return hex(self.node) + ':' + self.name
74 return hex(self.node) + ':' + self.name
75
75
76 class patchheader(object):
76 class patchheader(object):
77 def __init__(self, pf, plainmode=False):
77 def __init__(self, pf, plainmode=False):
78 def eatdiff(lines):
78 def eatdiff(lines):
79 while lines:
79 while lines:
80 l = lines[-1]
80 l = lines[-1]
81 if (l.startswith("diff -") or
81 if (l.startswith("diff -") or
82 l.startswith("Index:") or
82 l.startswith("Index:") or
83 l.startswith("===========")):
83 l.startswith("===========")):
84 del lines[-1]
84 del lines[-1]
85 else:
85 else:
86 break
86 break
87 def eatempty(lines):
87 def eatempty(lines):
88 while lines:
88 while lines:
89 if not lines[-1].strip():
89 if not lines[-1].strip():
90 del lines[-1]
90 del lines[-1]
91 else:
91 else:
92 break
92 break
93
93
94 message = []
94 message = []
95 comments = []
95 comments = []
96 user = None
96 user = None
97 date = None
97 date = None
98 parent = None
98 parent = None
99 format = None
99 format = None
100 subject = None
100 subject = None
101 branch = None
101 branch = None
102 nodeid = None
102 nodeid = None
103 diffstart = 0
103 diffstart = 0
104
104
105 for line in file(pf):
105 for line in file(pf):
106 line = line.rstrip()
106 line = line.rstrip()
107 if (line.startswith('diff --git')
107 if (line.startswith('diff --git')
108 or (diffstart and line.startswith('+++ '))):
108 or (diffstart and line.startswith('+++ '))):
109 diffstart = 2
109 diffstart = 2
110 break
110 break
111 diffstart = 0 # reset
111 diffstart = 0 # reset
112 if line.startswith("--- "):
112 if line.startswith("--- "):
113 diffstart = 1
113 diffstart = 1
114 continue
114 continue
115 elif format == "hgpatch":
115 elif format == "hgpatch":
116 # parse values when importing the result of an hg export
116 # parse values when importing the result of an hg export
117 if line.startswith("# User "):
117 if line.startswith("# User "):
118 user = line[7:]
118 user = line[7:]
119 elif line.startswith("# Date "):
119 elif line.startswith("# Date "):
120 date = line[7:]
120 date = line[7:]
121 elif line.startswith("# Parent "):
121 elif line.startswith("# Parent "):
122 parent = line[9:].lstrip()
122 parent = line[9:].lstrip()
123 elif line.startswith("# Branch "):
123 elif line.startswith("# Branch "):
124 branch = line[9:]
124 branch = line[9:]
125 elif line.startswith("# Node ID "):
125 elif line.startswith("# Node ID "):
126 nodeid = line[10:]
126 nodeid = line[10:]
127 elif not line.startswith("# ") and line:
127 elif not line.startswith("# ") and line:
128 message.append(line)
128 message.append(line)
129 format = None
129 format = None
130 elif line == '# HG changeset patch':
130 elif line == '# HG changeset patch':
131 message = []
131 message = []
132 format = "hgpatch"
132 format = "hgpatch"
133 elif (format != "tagdone" and (line.startswith("Subject: ") or
133 elif (format != "tagdone" and (line.startswith("Subject: ") or
134 line.startswith("subject: "))):
134 line.startswith("subject: "))):
135 subject = line[9:]
135 subject = line[9:]
136 format = "tag"
136 format = "tag"
137 elif (format != "tagdone" and (line.startswith("From: ") or
137 elif (format != "tagdone" and (line.startswith("From: ") or
138 line.startswith("from: "))):
138 line.startswith("from: "))):
139 user = line[6:]
139 user = line[6:]
140 format = "tag"
140 format = "tag"
141 elif (format != "tagdone" and (line.startswith("Date: ") or
141 elif (format != "tagdone" and (line.startswith("Date: ") or
142 line.startswith("date: "))):
142 line.startswith("date: "))):
143 date = line[6:]
143 date = line[6:]
144 format = "tag"
144 format = "tag"
145 elif format == "tag" and line == "":
145 elif format == "tag" and line == "":
146 # when looking for tags (subject: from: etc) they
146 # when looking for tags (subject: from: etc) they
147 # end once you find a blank line in the source
147 # end once you find a blank line in the source
148 format = "tagdone"
148 format = "tagdone"
149 elif message or line:
149 elif message or line:
150 message.append(line)
150 message.append(line)
151 comments.append(line)
151 comments.append(line)
152
152
153 eatdiff(message)
153 eatdiff(message)
154 eatdiff(comments)
154 eatdiff(comments)
155 # Remember the exact starting line of the patch diffs before consuming
155 # Remember the exact starting line of the patch diffs before consuming
156 # empty lines, for external use by TortoiseHg and others
156 # empty lines, for external use by TortoiseHg and others
157 self.diffstartline = len(comments)
157 self.diffstartline = len(comments)
158 eatempty(message)
158 eatempty(message)
159 eatempty(comments)
159 eatempty(comments)
160
160
161 # make sure message isn't empty
161 # make sure message isn't empty
162 if format and format.startswith("tag") and subject:
162 if format and format.startswith("tag") and subject:
163 message.insert(0, "")
163 message.insert(0, "")
164 message.insert(0, subject)
164 message.insert(0, subject)
165
165
166 self.message = message
166 self.message = message
167 self.comments = comments
167 self.comments = comments
168 self.user = user
168 self.user = user
169 self.date = date
169 self.date = date
170 self.parent = parent
170 self.parent = parent
171 # nodeid and branch are for external use by TortoiseHg and others
171 # nodeid and branch are for external use by TortoiseHg and others
172 self.nodeid = nodeid
172 self.nodeid = nodeid
173 self.branch = branch
173 self.branch = branch
174 self.haspatch = diffstart > 1
174 self.haspatch = diffstart > 1
175 self.plainmode = plainmode
175 self.plainmode = plainmode
176
176
177 def setuser(self, user):
177 def setuser(self, user):
178 if not self.updateheader(['From: ', '# User '], user):
178 if not self.updateheader(['From: ', '# User '], user):
179 try:
179 try:
180 patchheaderat = self.comments.index('# HG changeset patch')
180 patchheaderat = self.comments.index('# HG changeset patch')
181 self.comments.insert(patchheaderat + 1, '# User ' + user)
181 self.comments.insert(patchheaderat + 1, '# User ' + user)
182 except ValueError:
182 except ValueError:
183 if self.plainmode or self._hasheader(['Date: ']):
183 if self.plainmode or self._hasheader(['Date: ']):
184 self.comments = ['From: ' + user] + self.comments
184 self.comments = ['From: ' + user] + self.comments
185 else:
185 else:
186 tmp = ['# HG changeset patch', '# User ' + user, '']
186 tmp = ['# HG changeset patch', '# User ' + user, '']
187 self.comments = tmp + self.comments
187 self.comments = tmp + self.comments
188 self.user = user
188 self.user = user
189
189
190 def setdate(self, date):
190 def setdate(self, date):
191 if not self.updateheader(['Date: ', '# Date '], date):
191 if not self.updateheader(['Date: ', '# Date '], date):
192 try:
192 try:
193 patchheaderat = self.comments.index('# HG changeset patch')
193 patchheaderat = self.comments.index('# HG changeset patch')
194 self.comments.insert(patchheaderat + 1, '# Date ' + date)
194 self.comments.insert(patchheaderat + 1, '# Date ' + date)
195 except ValueError:
195 except ValueError:
196 if self.plainmode or self._hasheader(['From: ']):
196 if self.plainmode or self._hasheader(['From: ']):
197 self.comments = ['Date: ' + date] + self.comments
197 self.comments = ['Date: ' + date] + self.comments
198 else:
198 else:
199 tmp = ['# HG changeset patch', '# Date ' + date, '']
199 tmp = ['# HG changeset patch', '# Date ' + date, '']
200 self.comments = tmp + self.comments
200 self.comments = tmp + self.comments
201 self.date = date
201 self.date = date
202
202
203 def setparent(self, parent):
203 def setparent(self, parent):
204 if not self.updateheader(['# Parent '], parent):
204 if not self.updateheader(['# Parent '], parent):
205 try:
205 try:
206 patchheaderat = self.comments.index('# HG changeset patch')
206 patchheaderat = self.comments.index('# HG changeset patch')
207 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
207 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
208 except ValueError:
208 except ValueError:
209 pass
209 pass
210 self.parent = parent
210 self.parent = parent
211
211
212 def setmessage(self, message):
212 def setmessage(self, message):
213 if self.comments:
213 if self.comments:
214 self._delmsg()
214 self._delmsg()
215 self.message = [message]
215 self.message = [message]
216 self.comments += self.message
216 self.comments += self.message
217
217
218 def updateheader(self, prefixes, new):
218 def updateheader(self, prefixes, new):
219 '''Update all references to a field in the patch header.
219 '''Update all references to a field in the patch header.
220 Return whether the field is present.'''
220 Return whether the field is present.'''
221 res = False
221 res = False
222 for prefix in prefixes:
222 for prefix in prefixes:
223 for i in xrange(len(self.comments)):
223 for i in xrange(len(self.comments)):
224 if self.comments[i].startswith(prefix):
224 if self.comments[i].startswith(prefix):
225 self.comments[i] = prefix + new
225 self.comments[i] = prefix + new
226 res = True
226 res = True
227 break
227 break
228 return res
228 return res
229
229
230 def _hasheader(self, prefixes):
230 def _hasheader(self, prefixes):
231 '''Check if a header starts with any of the given prefixes.'''
231 '''Check if a header starts with any of the given prefixes.'''
232 for prefix in prefixes:
232 for prefix in prefixes:
233 for comment in self.comments:
233 for comment in self.comments:
234 if comment.startswith(prefix):
234 if comment.startswith(prefix):
235 return True
235 return True
236 return False
236 return False
237
237
238 def __str__(self):
238 def __str__(self):
239 if not self.comments:
239 if not self.comments:
240 return ''
240 return ''
241 return '\n'.join(self.comments) + '\n\n'
241 return '\n'.join(self.comments) + '\n\n'
242
242
243 def _delmsg(self):
243 def _delmsg(self):
244 '''Remove existing message, keeping the rest of the comments fields.
244 '''Remove existing message, keeping the rest of the comments fields.
245 If comments contains 'subject: ', message will prepend
245 If comments contains 'subject: ', message will prepend
246 the field and a blank line.'''
246 the field and a blank line.'''
247 if self.message:
247 if self.message:
248 subj = 'subject: ' + self.message[0].lower()
248 subj = 'subject: ' + self.message[0].lower()
249 for i in xrange(len(self.comments)):
249 for i in xrange(len(self.comments)):
250 if subj == self.comments[i].lower():
250 if subj == self.comments[i].lower():
251 del self.comments[i]
251 del self.comments[i]
252 self.message = self.message[2:]
252 self.message = self.message[2:]
253 break
253 break
254 ci = 0
254 ci = 0
255 for mi in self.message:
255 for mi in self.message:
256 while mi != self.comments[ci]:
256 while mi != self.comments[ci]:
257 ci += 1
257 ci += 1
258 del self.comments[ci]
258 del self.comments[ci]
259
259
260 def newcommit(repo, phase, *args, **kwargs):
260 def newcommit(repo, phase, *args, **kwargs):
261 """helper dedicated to ensure a commit respect mq.secret setting
261 """helper dedicated to ensure a commit respect mq.secret setting
262
262
263 It should be used instead of repo.commit inside the mq source for operation
263 It should be used instead of repo.commit inside the mq source for operation
264 creating new changeset.
264 creating new changeset.
265 """
265 """
266 if phase is None:
266 if phase is None:
267 if repo.ui.configbool('mq', 'secret', False):
267 if repo.ui.configbool('mq', 'secret', False):
268 phase = phases.secret
268 phase = phases.secret
269 if phase is not None:
269 if phase is not None:
270 backup = repo.ui.backupconfig('phases', 'new-commit')
270 backup = repo.ui.backupconfig('phases', 'new-commit')
271 # Marking the repository as committing an mq patch can be used
271 # Marking the repository as committing an mq patch can be used
272 # to optimize operations like _branchtags().
272 # to optimize operations like _branchtags().
273 repo._committingpatch = True
273 repo._committingpatch = True
274 try:
274 try:
275 if phase is not None:
275 if phase is not None:
276 repo.ui.setconfig('phases', 'new-commit', phase)
276 repo.ui.setconfig('phases', 'new-commit', phase)
277 return repo.commit(*args, **kwargs)
277 return repo.commit(*args, **kwargs)
278 finally:
278 finally:
279 repo._committingpatch = False
279 repo._committingpatch = False
280 if phase is not None:
280 if phase is not None:
281 repo.ui.restoreconfig(backup)
281 repo.ui.restoreconfig(backup)
282
282
283 class queue(object):
283 class queue(object):
284 def __init__(self, ui, path, patchdir=None):
284 def __init__(self, ui, path, patchdir=None):
285 self.basepath = path
285 self.basepath = path
286 try:
286 try:
287 fh = open(os.path.join(path, 'patches.queue'))
287 fh = open(os.path.join(path, 'patches.queue'))
288 cur = fh.read().rstrip()
288 cur = fh.read().rstrip()
289 fh.close()
289 fh.close()
290 if not cur:
290 if not cur:
291 curpath = os.path.join(path, 'patches')
291 curpath = os.path.join(path, 'patches')
292 else:
292 else:
293 curpath = os.path.join(path, 'patches-' + cur)
293 curpath = os.path.join(path, 'patches-' + cur)
294 except IOError:
294 except IOError:
295 curpath = os.path.join(path, 'patches')
295 curpath = os.path.join(path, 'patches')
296 self.path = patchdir or curpath
296 self.path = patchdir or curpath
297 self.opener = scmutil.opener(self.path)
297 self.opener = scmutil.opener(self.path)
298 self.ui = ui
298 self.ui = ui
299 self.applieddirty = False
299 self.applieddirty = False
300 self.seriesdirty = False
300 self.seriesdirty = False
301 self.added = []
301 self.added = []
302 self.seriespath = "series"
302 self.seriespath = "series"
303 self.statuspath = "status"
303 self.statuspath = "status"
304 self.guardspath = "guards"
304 self.guardspath = "guards"
305 self.activeguards = None
305 self.activeguards = None
306 self.guardsdirty = False
306 self.guardsdirty = False
307 # Handle mq.git as a bool with extended values
307 # Handle mq.git as a bool with extended values
308 try:
308 try:
309 gitmode = ui.configbool('mq', 'git', None)
309 gitmode = ui.configbool('mq', 'git', None)
310 if gitmode is None:
310 if gitmode is None:
311 raise error.ConfigError()
311 raise error.ConfigError()
312 self.gitmode = gitmode and 'yes' or 'no'
312 self.gitmode = gitmode and 'yes' or 'no'
313 except error.ConfigError:
313 except error.ConfigError:
314 self.gitmode = ui.config('mq', 'git', 'auto').lower()
314 self.gitmode = ui.config('mq', 'git', 'auto').lower()
315 self.plainmode = ui.configbool('mq', 'plain', False)
315 self.plainmode = ui.configbool('mq', 'plain', False)
316
316
317 @util.propertycache
317 @util.propertycache
318 def applied(self):
318 def applied(self):
319 def parselines(lines):
319 def parselines(lines):
320 for l in lines:
320 for l in lines:
321 entry = l.split(':', 1)
321 entry = l.split(':', 1)
322 if len(entry) > 1:
322 if len(entry) > 1:
323 n, name = entry
323 n, name = entry
324 yield statusentry(bin(n), name)
324 yield statusentry(bin(n), name)
325 elif l.strip():
325 elif l.strip():
326 self.ui.warn(_('malformated mq status line: %s\n') % entry)
326 self.ui.warn(_('malformated mq status line: %s\n') % entry)
327 # else we ignore empty lines
327 # else we ignore empty lines
328 try:
328 try:
329 lines = self.opener.read(self.statuspath).splitlines()
329 lines = self.opener.read(self.statuspath).splitlines()
330 return list(parselines(lines))
330 return list(parselines(lines))
331 except IOError, e:
331 except IOError, e:
332 if e.errno == errno.ENOENT:
332 if e.errno == errno.ENOENT:
333 return []
333 return []
334 raise
334 raise
335
335
336 @util.propertycache
336 @util.propertycache
337 def fullseries(self):
337 def fullseries(self):
338 try:
338 try:
339 return self.opener.read(self.seriespath).splitlines()
339 return self.opener.read(self.seriespath).splitlines()
340 except IOError, e:
340 except IOError, e:
341 if e.errno == errno.ENOENT:
341 if e.errno == errno.ENOENT:
342 return []
342 return []
343 raise
343 raise
344
344
345 @util.propertycache
345 @util.propertycache
346 def series(self):
346 def series(self):
347 self.parseseries()
347 self.parseseries()
348 return self.series
348 return self.series
349
349
350 @util.propertycache
350 @util.propertycache
351 def seriesguards(self):
351 def seriesguards(self):
352 self.parseseries()
352 self.parseseries()
353 return self.seriesguards
353 return self.seriesguards
354
354
355 def invalidate(self):
355 def invalidate(self):
356 for a in 'applied fullseries series seriesguards'.split():
356 for a in 'applied fullseries series seriesguards'.split():
357 if a in self.__dict__:
357 if a in self.__dict__:
358 delattr(self, a)
358 delattr(self, a)
359 self.applieddirty = False
359 self.applieddirty = False
360 self.seriesdirty = False
360 self.seriesdirty = False
361 self.guardsdirty = False
361 self.guardsdirty = False
362 self.activeguards = None
362 self.activeguards = None
363
363
364 def diffopts(self, opts={}, patchfn=None):
364 def diffopts(self, opts={}, patchfn=None):
365 diffopts = patchmod.diffopts(self.ui, opts)
365 diffopts = patchmod.diffopts(self.ui, opts)
366 if self.gitmode == 'auto':
366 if self.gitmode == 'auto':
367 diffopts.upgrade = True
367 diffopts.upgrade = True
368 elif self.gitmode == 'keep':
368 elif self.gitmode == 'keep':
369 pass
369 pass
370 elif self.gitmode in ('yes', 'no'):
370 elif self.gitmode in ('yes', 'no'):
371 diffopts.git = self.gitmode == 'yes'
371 diffopts.git = self.gitmode == 'yes'
372 else:
372 else:
373 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
373 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
374 ' got %s') % self.gitmode)
374 ' got %s') % self.gitmode)
375 if patchfn:
375 if patchfn:
376 diffopts = self.patchopts(diffopts, patchfn)
376 diffopts = self.patchopts(diffopts, patchfn)
377 return diffopts
377 return diffopts
378
378
379 def patchopts(self, diffopts, *patches):
379 def patchopts(self, diffopts, *patches):
380 """Return a copy of input diff options with git set to true if
380 """Return a copy of input diff options with git set to true if
381 referenced patch is a git patch and should be preserved as such.
381 referenced patch is a git patch and should be preserved as such.
382 """
382 """
383 diffopts = diffopts.copy()
383 diffopts = diffopts.copy()
384 if not diffopts.git and self.gitmode == 'keep':
384 if not diffopts.git and self.gitmode == 'keep':
385 for patchfn in patches:
385 for patchfn in patches:
386 patchf = self.opener(patchfn, 'r')
386 patchf = self.opener(patchfn, 'r')
387 # if the patch was a git patch, refresh it as a git patch
387 # if the patch was a git patch, refresh it as a git patch
388 for line in patchf:
388 for line in patchf:
389 if line.startswith('diff --git'):
389 if line.startswith('diff --git'):
390 diffopts.git = True
390 diffopts.git = True
391 break
391 break
392 patchf.close()
392 patchf.close()
393 return diffopts
393 return diffopts
394
394
395 def join(self, *p):
395 def join(self, *p):
396 return os.path.join(self.path, *p)
396 return os.path.join(self.path, *p)
397
397
398 def findseries(self, patch):
398 def findseries(self, patch):
399 def matchpatch(l):
399 def matchpatch(l):
400 l = l.split('#', 1)[0]
400 l = l.split('#', 1)[0]
401 return l.strip() == patch
401 return l.strip() == patch
402 for index, l in enumerate(self.fullseries):
402 for index, l in enumerate(self.fullseries):
403 if matchpatch(l):
403 if matchpatch(l):
404 return index
404 return index
405 return None
405 return None
406
406
407 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
407 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
408
408
409 def parseseries(self):
409 def parseseries(self):
410 self.series = []
410 self.series = []
411 self.seriesguards = []
411 self.seriesguards = []
412 for l in self.fullseries:
412 for l in self.fullseries:
413 h = l.find('#')
413 h = l.find('#')
414 if h == -1:
414 if h == -1:
415 patch = l
415 patch = l
416 comment = ''
416 comment = ''
417 elif h == 0:
417 elif h == 0:
418 continue
418 continue
419 else:
419 else:
420 patch = l[:h]
420 patch = l[:h]
421 comment = l[h:]
421 comment = l[h:]
422 patch = patch.strip()
422 patch = patch.strip()
423 if patch:
423 if patch:
424 if patch in self.series:
424 if patch in self.series:
425 raise util.Abort(_('%s appears more than once in %s') %
425 raise util.Abort(_('%s appears more than once in %s') %
426 (patch, self.join(self.seriespath)))
426 (patch, self.join(self.seriespath)))
427 self.series.append(patch)
427 self.series.append(patch)
428 self.seriesguards.append(self.guard_re.findall(comment))
428 self.seriesguards.append(self.guard_re.findall(comment))
429
429
430 def checkguard(self, guard):
430 def checkguard(self, guard):
431 if not guard:
431 if not guard:
432 return _('guard cannot be an empty string')
432 return _('guard cannot be an empty string')
433 bad_chars = '# \t\r\n\f'
433 bad_chars = '# \t\r\n\f'
434 first = guard[0]
434 first = guard[0]
435 if first in '-+':
435 if first in '-+':
436 return (_('guard %r starts with invalid character: %r') %
436 return (_('guard %r starts with invalid character: %r') %
437 (guard, first))
437 (guard, first))
438 for c in bad_chars:
438 for c in bad_chars:
439 if c in guard:
439 if c in guard:
440 return _('invalid character in guard %r: %r') % (guard, c)
440 return _('invalid character in guard %r: %r') % (guard, c)
441
441
442 def setactive(self, guards):
442 def setactive(self, guards):
443 for guard in guards:
443 for guard in guards:
444 bad = self.checkguard(guard)
444 bad = self.checkguard(guard)
445 if bad:
445 if bad:
446 raise util.Abort(bad)
446 raise util.Abort(bad)
447 guards = sorted(set(guards))
447 guards = sorted(set(guards))
448 self.ui.debug('active guards: %s\n' % ' '.join(guards))
448 self.ui.debug('active guards: %s\n' % ' '.join(guards))
449 self.activeguards = guards
449 self.activeguards = guards
450 self.guardsdirty = True
450 self.guardsdirty = True
451
451
452 def active(self):
452 def active(self):
453 if self.activeguards is None:
453 if self.activeguards is None:
454 self.activeguards = []
454 self.activeguards = []
455 try:
455 try:
456 guards = self.opener.read(self.guardspath).split()
456 guards = self.opener.read(self.guardspath).split()
457 except IOError, err:
457 except IOError, err:
458 if err.errno != errno.ENOENT:
458 if err.errno != errno.ENOENT:
459 raise
459 raise
460 guards = []
460 guards = []
461 for i, guard in enumerate(guards):
461 for i, guard in enumerate(guards):
462 bad = self.checkguard(guard)
462 bad = self.checkguard(guard)
463 if bad:
463 if bad:
464 self.ui.warn('%s:%d: %s\n' %
464 self.ui.warn('%s:%d: %s\n' %
465 (self.join(self.guardspath), i + 1, bad))
465 (self.join(self.guardspath), i + 1, bad))
466 else:
466 else:
467 self.activeguards.append(guard)
467 self.activeguards.append(guard)
468 return self.activeguards
468 return self.activeguards
469
469
470 def setguards(self, idx, guards):
470 def setguards(self, idx, guards):
471 for g in guards:
471 for g in guards:
472 if len(g) < 2:
472 if len(g) < 2:
473 raise util.Abort(_('guard %r too short') % g)
473 raise util.Abort(_('guard %r too short') % g)
474 if g[0] not in '-+':
474 if g[0] not in '-+':
475 raise util.Abort(_('guard %r starts with invalid char') % g)
475 raise util.Abort(_('guard %r starts with invalid char') % g)
476 bad = self.checkguard(g[1:])
476 bad = self.checkguard(g[1:])
477 if bad:
477 if bad:
478 raise util.Abort(bad)
478 raise util.Abort(bad)
479 drop = self.guard_re.sub('', self.fullseries[idx])
479 drop = self.guard_re.sub('', self.fullseries[idx])
480 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
480 self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
481 self.parseseries()
481 self.parseseries()
482 self.seriesdirty = True
482 self.seriesdirty = True
483
483
484 def pushable(self, idx):
484 def pushable(self, idx):
485 if isinstance(idx, str):
485 if isinstance(idx, str):
486 idx = self.series.index(idx)
486 idx = self.series.index(idx)
487 patchguards = self.seriesguards[idx]
487 patchguards = self.seriesguards[idx]
488 if not patchguards:
488 if not patchguards:
489 return True, None
489 return True, None
490 guards = self.active()
490 guards = self.active()
491 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
491 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
492 if exactneg:
492 if exactneg:
493 return False, repr(exactneg[0])
493 return False, repr(exactneg[0])
494 pos = [g for g in patchguards if g[0] == '+']
494 pos = [g for g in patchguards if g[0] == '+']
495 exactpos = [g for g in pos if g[1:] in guards]
495 exactpos = [g for g in pos if g[1:] in guards]
496 if pos:
496 if pos:
497 if exactpos:
497 if exactpos:
498 return True, repr(exactpos[0])
498 return True, repr(exactpos[0])
499 return False, ' '.join(map(repr, pos))
499 return False, ' '.join(map(repr, pos))
500 return True, ''
500 return True, ''
501
501
502 def explainpushable(self, idx, all_patches=False):
502 def explainpushable(self, idx, all_patches=False):
503 write = all_patches and self.ui.write or self.ui.warn
503 write = all_patches and self.ui.write or self.ui.warn
504 if all_patches or self.ui.verbose:
504 if all_patches or self.ui.verbose:
505 if isinstance(idx, str):
505 if isinstance(idx, str):
506 idx = self.series.index(idx)
506 idx = self.series.index(idx)
507 pushable, why = self.pushable(idx)
507 pushable, why = self.pushable(idx)
508 if all_patches and pushable:
508 if all_patches and pushable:
509 if why is None:
509 if why is None:
510 write(_('allowing %s - no guards in effect\n') %
510 write(_('allowing %s - no guards in effect\n') %
511 self.series[idx])
511 self.series[idx])
512 else:
512 else:
513 if not why:
513 if not why:
514 write(_('allowing %s - no matching negative guards\n') %
514 write(_('allowing %s - no matching negative guards\n') %
515 self.series[idx])
515 self.series[idx])
516 else:
516 else:
517 write(_('allowing %s - guarded by %s\n') %
517 write(_('allowing %s - guarded by %s\n') %
518 (self.series[idx], why))
518 (self.series[idx], why))
519 if not pushable:
519 if not pushable:
520 if why:
520 if why:
521 write(_('skipping %s - guarded by %s\n') %
521 write(_('skipping %s - guarded by %s\n') %
522 (self.series[idx], why))
522 (self.series[idx], why))
523 else:
523 else:
524 write(_('skipping %s - no matching guards\n') %
524 write(_('skipping %s - no matching guards\n') %
525 self.series[idx])
525 self.series[idx])
526
526
527 def savedirty(self):
527 def savedirty(self):
528 def writelist(items, path):
528 def writelist(items, path):
529 fp = self.opener(path, 'w')
529 fp = self.opener(path, 'w')
530 for i in items:
530 for i in items:
531 fp.write("%s\n" % i)
531 fp.write("%s\n" % i)
532 fp.close()
532 fp.close()
533 if self.applieddirty:
533 if self.applieddirty:
534 writelist(map(str, self.applied), self.statuspath)
534 writelist(map(str, self.applied), self.statuspath)
535 self.applieddirty = False
535 self.applieddirty = False
536 if self.seriesdirty:
536 if self.seriesdirty:
537 writelist(self.fullseries, self.seriespath)
537 writelist(self.fullseries, self.seriespath)
538 self.seriesdirty = False
538 self.seriesdirty = False
539 if self.guardsdirty:
539 if self.guardsdirty:
540 writelist(self.activeguards, self.guardspath)
540 writelist(self.activeguards, self.guardspath)
541 self.guardsdirty = False
541 self.guardsdirty = False
542 if self.added:
542 if self.added:
543 qrepo = self.qrepo()
543 qrepo = self.qrepo()
544 if qrepo:
544 if qrepo:
545 qrepo[None].add(f for f in self.added if f not in qrepo[None])
545 qrepo[None].add(f for f in self.added if f not in qrepo[None])
546 self.added = []
546 self.added = []
547
547
548 def removeundo(self, repo):
548 def removeundo(self, repo):
549 undo = repo.sjoin('undo')
549 undo = repo.sjoin('undo')
550 if not os.path.exists(undo):
550 if not os.path.exists(undo):
551 return
551 return
552 try:
552 try:
553 os.unlink(undo)
553 os.unlink(undo)
554 except OSError, inst:
554 except OSError, inst:
555 self.ui.warn(_('error removing undo: %s\n') % str(inst))
555 self.ui.warn(_('error removing undo: %s\n') % str(inst))
556
556
557 def backup(self, repo, files, copy=False):
557 def backup(self, repo, files, copy=False):
558 # backup local changes in --force case
558 # backup local changes in --force case
559 for f in sorted(files):
559 for f in sorted(files):
560 absf = repo.wjoin(f)
560 absf = repo.wjoin(f)
561 if os.path.lexists(absf):
561 if os.path.lexists(absf):
562 self.ui.note(_('saving current version of %s as %s\n') %
562 self.ui.note(_('saving current version of %s as %s\n') %
563 (f, f + '.orig'))
563 (f, f + '.orig'))
564 if copy:
564 if copy:
565 util.copyfile(absf, absf + '.orig')
565 util.copyfile(absf, absf + '.orig')
566 else:
566 else:
567 util.rename(absf, absf + '.orig')
567 util.rename(absf, absf + '.orig')
568
568
569 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
569 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
570 fp=None, changes=None, opts={}):
570 fp=None, changes=None, opts={}):
571 stat = opts.get('stat')
571 stat = opts.get('stat')
572 m = scmutil.match(repo[node1], files, opts)
572 m = scmutil.match(repo[node1], files, opts)
573 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
573 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
574 changes, stat, fp)
574 changes, stat, fp)
575
575
576 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
576 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
577 # first try just applying the patch
577 # first try just applying the patch
578 (err, n) = self.apply(repo, [patch], update_status=False,
578 (err, n) = self.apply(repo, [patch], update_status=False,
579 strict=True, merge=rev)
579 strict=True, merge=rev)
580
580
581 if err == 0:
581 if err == 0:
582 return (err, n)
582 return (err, n)
583
583
584 if n is None:
584 if n is None:
585 raise util.Abort(_("apply failed for patch %s") % patch)
585 raise util.Abort(_("apply failed for patch %s") % patch)
586
586
587 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
587 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
588
588
589 # apply failed, strip away that rev and merge.
589 # apply failed, strip away that rev and merge.
590 hg.clean(repo, head)
590 hg.clean(repo, head)
591 self.strip(repo, [n], update=False, backup='strip')
591 self.strip(repo, [n], update=False, backup='strip')
592
592
593 ctx = repo[rev]
593 ctx = repo[rev]
594 ret = hg.merge(repo, rev)
594 ret = hg.merge(repo, rev)
595 if ret:
595 if ret:
596 raise util.Abort(_("update returned %d") % ret)
596 raise util.Abort(_("update returned %d") % ret)
597 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
597 n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
598 if n is None:
598 if n is None:
599 raise util.Abort(_("repo commit failed"))
599 raise util.Abort(_("repo commit failed"))
600 try:
600 try:
601 ph = patchheader(mergeq.join(patch), self.plainmode)
601 ph = patchheader(mergeq.join(patch), self.plainmode)
602 except:
602 except:
603 raise util.Abort(_("unable to read %s") % patch)
603 raise util.Abort(_("unable to read %s") % patch)
604
604
605 diffopts = self.patchopts(diffopts, patch)
605 diffopts = self.patchopts(diffopts, patch)
606 patchf = self.opener(patch, "w")
606 patchf = self.opener(patch, "w")
607 comments = str(ph)
607 comments = str(ph)
608 if comments:
608 if comments:
609 patchf.write(comments)
609 patchf.write(comments)
610 self.printdiff(repo, diffopts, head, n, fp=patchf)
610 self.printdiff(repo, diffopts, head, n, fp=patchf)
611 patchf.close()
611 patchf.close()
612 self.removeundo(repo)
612 self.removeundo(repo)
613 return (0, n)
613 return (0, n)
614
614
615 def qparents(self, repo, rev=None):
615 def qparents(self, repo, rev=None):
616 if rev is None:
616 if rev is None:
617 (p1, p2) = repo.dirstate.parents()
617 (p1, p2) = repo.dirstate.parents()
618 if p2 == nullid:
618 if p2 == nullid:
619 return p1
619 return p1
620 if not self.applied:
620 if not self.applied:
621 return None
621 return None
622 return self.applied[-1].node
622 return self.applied[-1].node
623 p1, p2 = repo.changelog.parents(rev)
623 p1, p2 = repo.changelog.parents(rev)
624 if p2 != nullid and p2 in [x.node for x in self.applied]:
624 if p2 != nullid and p2 in [x.node for x in self.applied]:
625 return p2
625 return p2
626 return p1
626 return p1
627
627
628 def mergepatch(self, repo, mergeq, series, diffopts):
628 def mergepatch(self, repo, mergeq, series, diffopts):
629 if not self.applied:
629 if not self.applied:
630 # each of the patches merged in will have two parents. This
630 # each of the patches merged in will have two parents. This
631 # can confuse the qrefresh, qdiff, and strip code because it
631 # can confuse the qrefresh, qdiff, and strip code because it
632 # needs to know which parent is actually in the patch queue.
632 # needs to know which parent is actually in the patch queue.
633 # so, we insert a merge marker with only one parent. This way
633 # so, we insert a merge marker with only one parent. This way
634 # the first patch in the queue is never a merge patch
634 # the first patch in the queue is never a merge patch
635 #
635 #
636 pname = ".hg.patches.merge.marker"
636 pname = ".hg.patches.merge.marker"
637 n = newcommit(repo, None, '[mq]: merge marker', force=True)
637 n = newcommit(repo, None, '[mq]: merge marker', force=True)
638 self.removeundo(repo)
638 self.removeundo(repo)
639 self.applied.append(statusentry(n, pname))
639 self.applied.append(statusentry(n, pname))
640 self.applieddirty = True
640 self.applieddirty = True
641
641
642 head = self.qparents(repo)
642 head = self.qparents(repo)
643
643
644 for patch in series:
644 for patch in series:
645 patch = mergeq.lookup(patch, strict=True)
645 patch = mergeq.lookup(patch, strict=True)
646 if not patch:
646 if not patch:
647 self.ui.warn(_("patch %s does not exist\n") % patch)
647 self.ui.warn(_("patch %s does not exist\n") % patch)
648 return (1, None)
648 return (1, None)
649 pushable, reason = self.pushable(patch)
649 pushable, reason = self.pushable(patch)
650 if not pushable:
650 if not pushable:
651 self.explainpushable(patch, all_patches=True)
651 self.explainpushable(patch, all_patches=True)
652 continue
652 continue
653 info = mergeq.isapplied(patch)
653 info = mergeq.isapplied(patch)
654 if not info:
654 if not info:
655 self.ui.warn(_("patch %s is not applied\n") % patch)
655 self.ui.warn(_("patch %s is not applied\n") % patch)
656 return (1, None)
656 return (1, None)
657 rev = info[1]
657 rev = info[1]
658 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
658 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
659 if head:
659 if head:
660 self.applied.append(statusentry(head, patch))
660 self.applied.append(statusentry(head, patch))
661 self.applieddirty = True
661 self.applieddirty = True
662 if err:
662 if err:
663 return (err, head)
663 return (err, head)
664 self.savedirty()
664 self.savedirty()
665 return (0, head)
665 return (0, head)
666
666
667 def patch(self, repo, patchfile):
667 def patch(self, repo, patchfile):
668 '''Apply patchfile to the working directory.
668 '''Apply patchfile to the working directory.
669 patchfile: name of patch file'''
669 patchfile: name of patch file'''
670 files = set()
670 files = set()
671 try:
671 try:
672 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
672 fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
673 files=files, eolmode=None)
673 files=files, eolmode=None)
674 return (True, list(files), fuzz)
674 return (True, list(files), fuzz)
675 except Exception, inst:
675 except Exception, inst:
676 self.ui.note(str(inst) + '\n')
676 self.ui.note(str(inst) + '\n')
677 if not self.ui.verbose:
677 if not self.ui.verbose:
678 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
678 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
679 self.ui.traceback()
679 self.ui.traceback()
680 return (False, list(files), False)
680 return (False, list(files), False)
681
681
682 def apply(self, repo, series, list=False, update_status=True,
682 def apply(self, repo, series, list=False, update_status=True,
683 strict=False, patchdir=None, merge=None, all_files=None,
683 strict=False, patchdir=None, merge=None, all_files=None,
684 tobackup=None):
684 tobackup=None):
685 wlock = lock = tr = None
685 wlock = lock = tr = None
686 try:
686 try:
687 wlock = repo.wlock()
687 wlock = repo.wlock()
688 lock = repo.lock()
688 lock = repo.lock()
689 tr = repo.transaction("qpush")
689 tr = repo.transaction("qpush")
690 try:
690 try:
691 ret = self._apply(repo, series, list, update_status,
691 ret = self._apply(repo, series, list, update_status,
692 strict, patchdir, merge, all_files=all_files,
692 strict, patchdir, merge, all_files=all_files,
693 tobackup=tobackup)
693 tobackup=tobackup)
694 tr.close()
694 tr.close()
695 self.savedirty()
695 self.savedirty()
696 return ret
696 return ret
697 except:
697 except:
698 try:
698 try:
699 tr.abort()
699 tr.abort()
700 finally:
700 finally:
701 repo.invalidate()
701 repo.invalidate()
702 repo.dirstate.invalidate()
702 repo.dirstate.invalidate()
703 self.invalidate()
703 self.invalidate()
704 raise
704 raise
705 finally:
705 finally:
706 release(tr, lock, wlock)
706 release(tr, lock, wlock)
707 self.removeundo(repo)
707 self.removeundo(repo)
708
708
709 def _apply(self, repo, series, list=False, update_status=True,
709 def _apply(self, repo, series, list=False, update_status=True,
710 strict=False, patchdir=None, merge=None, all_files=None,
710 strict=False, patchdir=None, merge=None, all_files=None,
711 tobackup=None):
711 tobackup=None):
712 """returns (error, hash)
712 """returns (error, hash)
713
713
714 error = 1 for unable to read, 2 for patch failed, 3 for patch
714 error = 1 for unable to read, 2 for patch failed, 3 for patch
715 fuzz. tobackup is None or a set of files to backup before they
715 fuzz. tobackup is None or a set of files to backup before they
716 are modified by a patch.
716 are modified by a patch.
717 """
717 """
718 # TODO unify with commands.py
718 # TODO unify with commands.py
719 if not patchdir:
719 if not patchdir:
720 patchdir = self.path
720 patchdir = self.path
721 err = 0
721 err = 0
722 n = None
722 n = None
723 for patchname in series:
723 for patchname in series:
724 pushable, reason = self.pushable(patchname)
724 pushable, reason = self.pushable(patchname)
725 if not pushable:
725 if not pushable:
726 self.explainpushable(patchname, all_patches=True)
726 self.explainpushable(patchname, all_patches=True)
727 continue
727 continue
728 self.ui.status(_("applying %s\n") % patchname)
728 self.ui.status(_("applying %s\n") % patchname)
729 pf = os.path.join(patchdir, patchname)
729 pf = os.path.join(patchdir, patchname)
730
730
731 try:
731 try:
732 ph = patchheader(self.join(patchname), self.plainmode)
732 ph = patchheader(self.join(patchname), self.plainmode)
733 except IOError:
733 except IOError:
734 self.ui.warn(_("unable to read %s\n") % patchname)
734 self.ui.warn(_("unable to read %s\n") % patchname)
735 err = 1
735 err = 1
736 break
736 break
737
737
738 message = ph.message
738 message = ph.message
739 if not message:
739 if not message:
740 # The commit message should not be translated
740 # The commit message should not be translated
741 message = "imported patch %s\n" % patchname
741 message = "imported patch %s\n" % patchname
742 else:
742 else:
743 if list:
743 if list:
744 # The commit message should not be translated
744 # The commit message should not be translated
745 message.append("\nimported patch %s" % patchname)
745 message.append("\nimported patch %s" % patchname)
746 message = '\n'.join(message)
746 message = '\n'.join(message)
747
747
748 if ph.haspatch:
748 if ph.haspatch:
749 if tobackup:
749 if tobackup:
750 touched = patchmod.changedfiles(self.ui, repo, pf)
750 touched = patchmod.changedfiles(self.ui, repo, pf)
751 touched = set(touched) & tobackup
751 touched = set(touched) & tobackup
752 self.backup(repo, touched, copy=True)
752 self.backup(repo, touched, copy=True)
753 tobackup = tobackup - touched
753 tobackup = tobackup - touched
754 (patcherr, files, fuzz) = self.patch(repo, pf)
754 (patcherr, files, fuzz) = self.patch(repo, pf)
755 if all_files is not None:
755 if all_files is not None:
756 all_files.update(files)
756 all_files.update(files)
757 patcherr = not patcherr
757 patcherr = not patcherr
758 else:
758 else:
759 self.ui.warn(_("patch %s is empty\n") % patchname)
759 self.ui.warn(_("patch %s is empty\n") % patchname)
760 patcherr, files, fuzz = 0, [], 0
760 patcherr, files, fuzz = 0, [], 0
761
761
762 if merge and files:
762 if merge and files:
763 # Mark as removed/merged and update dirstate parent info
763 # Mark as removed/merged and update dirstate parent info
764 removed = []
764 removed = []
765 merged = []
765 merged = []
766 for f in files:
766 for f in files:
767 if os.path.lexists(repo.wjoin(f)):
767 if os.path.lexists(repo.wjoin(f)):
768 merged.append(f)
768 merged.append(f)
769 else:
769 else:
770 removed.append(f)
770 removed.append(f)
771 for f in removed:
771 for f in removed:
772 repo.dirstate.remove(f)
772 repo.dirstate.remove(f)
773 for f in merged:
773 for f in merged:
774 repo.dirstate.merge(f)
774 repo.dirstate.merge(f)
775 p1, p2 = repo.dirstate.parents()
775 p1, p2 = repo.dirstate.parents()
776 repo.setparents(p1, merge)
776 repo.setparents(p1, merge)
777
777
778 match = scmutil.matchfiles(repo, files or [])
778 match = scmutil.matchfiles(repo, files or [])
779 oldtip = repo['tip']
779 oldtip = repo['tip']
780 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
780 n = newcommit(repo, None, message, ph.user, ph.date, match=match,
781 force=True)
781 force=True)
782 if repo['tip'] == oldtip:
782 if repo['tip'] == oldtip:
783 raise util.Abort(_("qpush exactly duplicates child changeset"))
783 raise util.Abort(_("qpush exactly duplicates child changeset"))
784 if n is None:
784 if n is None:
785 raise util.Abort(_("repository commit failed"))
785 raise util.Abort(_("repository commit failed"))
786
786
787 if update_status:
787 if update_status:
788 self.applied.append(statusentry(n, patchname))
788 self.applied.append(statusentry(n, patchname))
789
789
790 if patcherr:
790 if patcherr:
791 self.ui.warn(_("patch failed, rejects left in working dir\n"))
791 self.ui.warn(_("patch failed, rejects left in working dir\n"))
792 err = 2
792 err = 2
793 break
793 break
794
794
795 if fuzz and strict:
795 if fuzz and strict:
796 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
796 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
797 err = 3
797 err = 3
798 break
798 break
799 return (err, n)
799 return (err, n)
800
800
801 def _cleanup(self, patches, numrevs, keep=False):
801 def _cleanup(self, patches, numrevs, keep=False):
802 if not keep:
802 if not keep:
803 r = self.qrepo()
803 r = self.qrepo()
804 if r:
804 if r:
805 r[None].forget(patches)
805 r[None].forget(patches)
806 for p in patches:
806 for p in patches:
807 os.unlink(self.join(p))
807 os.unlink(self.join(p))
808
808
809 qfinished = []
809 qfinished = []
810 if numrevs:
810 if numrevs:
811 qfinished = self.applied[:numrevs]
811 qfinished = self.applied[:numrevs]
812 del self.applied[:numrevs]
812 del self.applied[:numrevs]
813 self.applieddirty = True
813 self.applieddirty = True
814
814
815 unknown = []
815 unknown = []
816
816
817 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
817 for (i, p) in sorted([(self.findseries(p), p) for p in patches],
818 reverse=True):
818 reverse=True):
819 if i is not None:
819 if i is not None:
820 del self.fullseries[i]
820 del self.fullseries[i]
821 else:
821 else:
822 unknown.append(p)
822 unknown.append(p)
823
823
824 if unknown:
824 if unknown:
825 if numrevs:
825 if numrevs:
826 rev = dict((entry.name, entry.node) for entry in qfinished)
826 rev = dict((entry.name, entry.node) for entry in qfinished)
827 for p in unknown:
827 for p in unknown:
828 msg = _('revision %s refers to unknown patches: %s\n')
828 msg = _('revision %s refers to unknown patches: %s\n')
829 self.ui.warn(msg % (short(rev[p]), p))
829 self.ui.warn(msg % (short(rev[p]), p))
830 else:
830 else:
831 msg = _('unknown patches: %s\n')
831 msg = _('unknown patches: %s\n')
832 raise util.Abort(''.join(msg % p for p in unknown))
832 raise util.Abort(''.join(msg % p for p in unknown))
833
833
834 self.parseseries()
834 self.parseseries()
835 self.seriesdirty = True
835 self.seriesdirty = True
836 return [entry.node for entry in qfinished]
836 return [entry.node for entry in qfinished]
837
837
838 def _revpatches(self, repo, revs):
838 def _revpatches(self, repo, revs):
839 firstrev = repo[self.applied[0].node].rev()
839 firstrev = repo[self.applied[0].node].rev()
840 patches = []
840 patches = []
841 for i, rev in enumerate(revs):
841 for i, rev in enumerate(revs):
842
842
843 if rev < firstrev:
843 if rev < firstrev:
844 raise util.Abort(_('revision %d is not managed') % rev)
844 raise util.Abort(_('revision %d is not managed') % rev)
845
845
846 ctx = repo[rev]
846 ctx = repo[rev]
847 base = self.applied[i].node
847 base = self.applied[i].node
848 if ctx.node() != base:
848 if ctx.node() != base:
849 msg = _('cannot delete revision %d above applied patches')
849 msg = _('cannot delete revision %d above applied patches')
850 raise util.Abort(msg % rev)
850 raise util.Abort(msg % rev)
851
851
852 patch = self.applied[i].name
852 patch = self.applied[i].name
853 for fmt in ('[mq]: %s', 'imported patch %s'):
853 for fmt in ('[mq]: %s', 'imported patch %s'):
854 if ctx.description() == fmt % patch:
854 if ctx.description() == fmt % patch:
855 msg = _('patch %s finalized without changeset message\n')
855 msg = _('patch %s finalized without changeset message\n')
856 repo.ui.status(msg % patch)
856 repo.ui.status(msg % patch)
857 break
857 break
858
858
859 patches.append(patch)
859 patches.append(patch)
860 return patches
860 return patches
861
861
862 def finish(self, repo, revs):
862 def finish(self, repo, revs):
863 # Manually trigger phase computation to ensure phasedefaults is
863 # Manually trigger phase computation to ensure phasedefaults is
864 # executed before we remove the patches.
864 # executed before we remove the patches.
865 repo._phaserev
865 repo._phaserev
866 patches = self._revpatches(repo, sorted(revs))
866 patches = self._revpatches(repo, sorted(revs))
867 qfinished = self._cleanup(patches, len(patches))
867 qfinished = self._cleanup(patches, len(patches))
868 if qfinished and repo.ui.configbool('mq', 'secret', False):
868 if qfinished and repo.ui.configbool('mq', 'secret', False):
869 # only use this logic when the secret option is added
869 # only use this logic when the secret option is added
870 oldqbase = repo[qfinished[0]]
870 oldqbase = repo[qfinished[0]]
871 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
871 tphase = repo.ui.config('phases', 'new-commit', phases.draft)
872 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
872 if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
873 phases.advanceboundary(repo, tphase, qfinished)
873 phases.advanceboundary(repo, tphase, qfinished)
874
874
875 def delete(self, repo, patches, opts):
875 def delete(self, repo, patches, opts):
876 if not patches and not opts.get('rev'):
876 if not patches and not opts.get('rev'):
877 raise util.Abort(_('qdelete requires at least one revision or '
877 raise util.Abort(_('qdelete requires at least one revision or '
878 'patch name'))
878 'patch name'))
879
879
880 realpatches = []
880 realpatches = []
881 for patch in patches:
881 for patch in patches:
882 patch = self.lookup(patch, strict=True)
882 patch = self.lookup(patch, strict=True)
883 info = self.isapplied(patch)
883 info = self.isapplied(patch)
884 if info:
884 if info:
885 raise util.Abort(_("cannot delete applied patch %s") % patch)
885 raise util.Abort(_("cannot delete applied patch %s") % patch)
886 if patch not in self.series:
886 if patch not in self.series:
887 raise util.Abort(_("patch %s not in series file") % patch)
887 raise util.Abort(_("patch %s not in series file") % patch)
888 if patch not in realpatches:
888 if patch not in realpatches:
889 realpatches.append(patch)
889 realpatches.append(patch)
890
890
891 numrevs = 0
891 numrevs = 0
892 if opts.get('rev'):
892 if opts.get('rev'):
893 if not self.applied:
893 if not self.applied:
894 raise util.Abort(_('no patches applied'))
894 raise util.Abort(_('no patches applied'))
895 revs = scmutil.revrange(repo, opts.get('rev'))
895 revs = scmutil.revrange(repo, opts.get('rev'))
896 if len(revs) > 1 and revs[0] > revs[1]:
896 if len(revs) > 1 and revs[0] > revs[1]:
897 revs.reverse()
897 revs.reverse()
898 revpatches = self._revpatches(repo, revs)
898 revpatches = self._revpatches(repo, revs)
899 realpatches += revpatches
899 realpatches += revpatches
900 numrevs = len(revpatches)
900 numrevs = len(revpatches)
901
901
902 self._cleanup(realpatches, numrevs, opts.get('keep'))
902 self._cleanup(realpatches, numrevs, opts.get('keep'))
903
903
904 def checktoppatch(self, repo):
904 def checktoppatch(self, repo):
905 if self.applied:
905 if self.applied:
906 top = self.applied[-1].node
906 top = self.applied[-1].node
907 patch = self.applied[-1].name
907 patch = self.applied[-1].name
908 pp = repo.dirstate.parents()
908 pp = repo.dirstate.parents()
909 if top not in pp:
909 if top not in pp:
910 raise util.Abort(_("working directory revision is not qtip"))
910 raise util.Abort(_("working directory revision is not qtip"))
911 return top, patch
911 return top, patch
912 return None, None
912 return None, None
913
913
914 def checksubstate(self, repo):
914 def checksubstate(self, repo):
915 '''return list of subrepos at a different revision than substate.
915 '''return list of subrepos at a different revision than substate.
916 Abort if any subrepos have uncommitted changes.'''
916 Abort if any subrepos have uncommitted changes.'''
917 inclsubs = []
917 inclsubs = []
918 wctx = repo[None]
918 wctx = repo[None]
919 for s in wctx.substate:
919 for s in wctx.substate:
920 if wctx.sub(s).dirty(True):
920 if wctx.sub(s).dirty(True):
921 raise util.Abort(
921 raise util.Abort(
922 _("uncommitted changes in subrepository %s") % s)
922 _("uncommitted changes in subrepository %s") % s)
923 elif wctx.sub(s).dirty():
923 elif wctx.sub(s).dirty():
924 inclsubs.append(s)
924 inclsubs.append(s)
925 return inclsubs
925 return inclsubs
926
926
927 def localchangesfound(self, refresh=True):
927 def localchangesfound(self, refresh=True):
928 if refresh:
928 if refresh:
929 raise util.Abort(_("local changes found, refresh first"))
929 raise util.Abort(_("local changes found, refresh first"))
930 else:
930 else:
931 raise util.Abort(_("local changes found"))
931 raise util.Abort(_("local changes found"))
932
932
933 def checklocalchanges(self, repo, force=False, refresh=True):
933 def checklocalchanges(self, repo, force=False, refresh=True):
934 m, a, r, d = repo.status()[:4]
934 m, a, r, d = repo.status()[:4]
935 if (m or a or r or d) and not force:
935 if (m or a or r or d) and not force:
936 self.localchangesfound(refresh)
936 self.localchangesfound(refresh)
937 return m, a, r, d
937 return m, a, r, d
938
938
939 _reserved = ('series', 'status', 'guards', '.', '..')
939 _reserved = ('series', 'status', 'guards', '.', '..')
940 def checkreservedname(self, name):
940 def checkreservedname(self, name):
941 if name in self._reserved:
941 if name in self._reserved:
942 raise util.Abort(_('"%s" cannot be used as the name of a patch')
942 raise util.Abort(_('"%s" cannot be used as the name of a patch')
943 % name)
943 % name)
944 for prefix in ('.hg', '.mq'):
944 for prefix in ('.hg', '.mq'):
945 if name.startswith(prefix):
945 if name.startswith(prefix):
946 raise util.Abort(_('patch name cannot begin with "%s"')
946 raise util.Abort(_('patch name cannot begin with "%s"')
947 % prefix)
947 % prefix)
948 for c in ('#', ':'):
948 for c in ('#', ':'):
949 if c in name:
949 if c in name:
950 raise util.Abort(_('"%s" cannot be used in the name of a patch')
950 raise util.Abort(_('"%s" cannot be used in the name of a patch')
951 % c)
951 % c)
952
952
953 def checkpatchname(self, name, force=False):
953 def checkpatchname(self, name, force=False):
954 self.checkreservedname(name)
954 self.checkreservedname(name)
955 if not force and os.path.exists(self.join(name)):
955 if not force and os.path.exists(self.join(name)):
956 if os.path.isdir(self.join(name)):
956 if os.path.isdir(self.join(name)):
957 raise util.Abort(_('"%s" already exists as a directory')
957 raise util.Abort(_('"%s" already exists as a directory')
958 % name)
958 % name)
959 else:
959 else:
960 raise util.Abort(_('patch "%s" already exists') % name)
960 raise util.Abort(_('patch "%s" already exists') % name)
961
961
962 def new(self, repo, patchfn, *pats, **opts):
962 def new(self, repo, patchfn, *pats, **opts):
963 """options:
963 """options:
964 msg: a string or a no-argument function returning a string
964 msg: a string or a no-argument function returning a string
965 """
965 """
966 msg = opts.get('msg')
966 msg = opts.get('msg')
967 user = opts.get('user')
967 user = opts.get('user')
968 date = opts.get('date')
968 date = opts.get('date')
969 if date:
969 if date:
970 date = util.parsedate(date)
970 date = util.parsedate(date)
971 diffopts = self.diffopts({'git': opts.get('git')})
971 diffopts = self.diffopts({'git': opts.get('git')})
972 if opts.get('checkname', True):
972 if opts.get('checkname', True):
973 self.checkpatchname(patchfn)
973 self.checkpatchname(patchfn)
974 inclsubs = self.checksubstate(repo)
974 inclsubs = self.checksubstate(repo)
975 if inclsubs:
975 if inclsubs:
976 inclsubs.append('.hgsubstate')
976 inclsubs.append('.hgsubstate')
977 substatestate = repo.dirstate['.hgsubstate']
977 substatestate = repo.dirstate['.hgsubstate']
978 if opts.get('include') or opts.get('exclude') or pats:
978 if opts.get('include') or opts.get('exclude') or pats:
979 if inclsubs:
979 if inclsubs:
980 pats = list(pats or []) + inclsubs
980 pats = list(pats or []) + inclsubs
981 match = scmutil.match(repo[None], pats, opts)
981 match = scmutil.match(repo[None], pats, opts)
982 # detect missing files in pats
982 # detect missing files in pats
983 def badfn(f, msg):
983 def badfn(f, msg):
984 if f != '.hgsubstate': # .hgsubstate is auto-created
984 if f != '.hgsubstate': # .hgsubstate is auto-created
985 raise util.Abort('%s: %s' % (f, msg))
985 raise util.Abort('%s: %s' % (f, msg))
986 match.bad = badfn
986 match.bad = badfn
987 changes = repo.status(match=match)
987 changes = repo.status(match=match)
988 m, a, r, d = changes[:4]
988 m, a, r, d = changes[:4]
989 else:
989 else:
990 changes = self.checklocalchanges(repo, force=True)
990 changes = self.checklocalchanges(repo, force=True)
991 m, a, r, d = changes
991 m, a, r, d = changes
992 match = scmutil.matchfiles(repo, m + a + r + inclsubs)
992 match = scmutil.matchfiles(repo, m + a + r + inclsubs)
993 if len(repo[None].parents()) > 1:
993 if len(repo[None].parents()) > 1:
994 raise util.Abort(_('cannot manage merge changesets'))
994 raise util.Abort(_('cannot manage merge changesets'))
995 commitfiles = m + a + r
995 commitfiles = m + a + r
996 self.checktoppatch(repo)
996 self.checktoppatch(repo)
997 insert = self.fullseriesend()
997 insert = self.fullseriesend()
998 wlock = repo.wlock()
998 wlock = repo.wlock()
999 try:
999 try:
1000 try:
1000 try:
1001 # if patch file write fails, abort early
1001 # if patch file write fails, abort early
1002 p = self.opener(patchfn, "w")
1002 p = self.opener(patchfn, "w")
1003 except IOError, e:
1003 except IOError, e:
1004 raise util.Abort(_('cannot write patch "%s": %s')
1004 raise util.Abort(_('cannot write patch "%s": %s')
1005 % (patchfn, e.strerror))
1005 % (patchfn, e.strerror))
1006 try:
1006 try:
1007 if self.plainmode:
1007 if self.plainmode:
1008 if user:
1008 if user:
1009 p.write("From: " + user + "\n")
1009 p.write("From: " + user + "\n")
1010 if not date:
1010 if not date:
1011 p.write("\n")
1011 p.write("\n")
1012 if date:
1012 if date:
1013 p.write("Date: %d %d\n\n" % date)
1013 p.write("Date: %d %d\n\n" % date)
1014 else:
1014 else:
1015 p.write("# HG changeset patch\n")
1015 p.write("# HG changeset patch\n")
1016 p.write("# Parent "
1016 p.write("# Parent "
1017 + hex(repo[None].p1().node()) + "\n")
1017 + hex(repo[None].p1().node()) + "\n")
1018 if user:
1018 if user:
1019 p.write("# User " + user + "\n")
1019 p.write("# User " + user + "\n")
1020 if date:
1020 if date:
1021 p.write("# Date %s %s\n\n" % date)
1021 p.write("# Date %s %s\n\n" % date)
1022 if util.safehasattr(msg, '__call__'):
1022 if util.safehasattr(msg, '__call__'):
1023 msg = msg()
1023 msg = msg()
1024 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
1024 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
1025 n = newcommit(repo, None, commitmsg, user, date, match=match,
1025 n = newcommit(repo, None, commitmsg, user, date, match=match,
1026 force=True)
1026 force=True)
1027 if n is None:
1027 if n is None:
1028 raise util.Abort(_("repo commit failed"))
1028 raise util.Abort(_("repo commit failed"))
1029 try:
1029 try:
1030 self.fullseries[insert:insert] = [patchfn]
1030 self.fullseries[insert:insert] = [patchfn]
1031 self.applied.append(statusentry(n, patchfn))
1031 self.applied.append(statusentry(n, patchfn))
1032 self.parseseries()
1032 self.parseseries()
1033 self.seriesdirty = True
1033 self.seriesdirty = True
1034 self.applieddirty = True
1034 self.applieddirty = True
1035 if msg:
1035 if msg:
1036 msg = msg + "\n\n"
1036 msg = msg + "\n\n"
1037 p.write(msg)
1037 p.write(msg)
1038 if commitfiles:
1038 if commitfiles:
1039 parent = self.qparents(repo, n)
1039 parent = self.qparents(repo, n)
1040 if inclsubs:
1040 if inclsubs:
1041 if substatestate in 'a?':
1041 if substatestate in 'a?':
1042 changes[1].append('.hgsubstate')
1042 changes[1].append('.hgsubstate')
1043 elif substatestate in 'r':
1043 elif substatestate in 'r':
1044 changes[2].append('.hgsubstate')
1044 changes[2].append('.hgsubstate')
1045 else: # modified
1045 else: # modified
1046 changes[0].append('.hgsubstate')
1046 changes[0].append('.hgsubstate')
1047 chunks = patchmod.diff(repo, node1=parent, node2=n,
1047 chunks = patchmod.diff(repo, node1=parent, node2=n,
1048 changes=changes, opts=diffopts)
1048 changes=changes, opts=diffopts)
1049 for chunk in chunks:
1049 for chunk in chunks:
1050 p.write(chunk)
1050 p.write(chunk)
1051 p.close()
1051 p.close()
1052 r = self.qrepo()
1052 r = self.qrepo()
1053 if r:
1053 if r:
1054 r[None].add([patchfn])
1054 r[None].add([patchfn])
1055 except:
1055 except:
1056 repo.rollback()
1056 repo.rollback()
1057 raise
1057 raise
1058 except Exception:
1058 except Exception:
1059 patchpath = self.join(patchfn)
1059 patchpath = self.join(patchfn)
1060 try:
1060 try:
1061 os.unlink(patchpath)
1061 os.unlink(patchpath)
1062 except:
1062 except:
1063 self.ui.warn(_('error unlinking %s\n') % patchpath)
1063 self.ui.warn(_('error unlinking %s\n') % patchpath)
1064 raise
1064 raise
1065 self.removeundo(repo)
1065 self.removeundo(repo)
1066 finally:
1066 finally:
1067 release(wlock)
1067 release(wlock)
1068
1068
1069 def strip(self, repo, revs, update=True, backup="all", force=None):
1069 def strip(self, repo, revs, update=True, backup="all", force=None):
1070 wlock = lock = None
1070 wlock = lock = None
1071 try:
1071 try:
1072 wlock = repo.wlock()
1072 wlock = repo.wlock()
1073 lock = repo.lock()
1073 lock = repo.lock()
1074
1074
1075 if update:
1075 if update:
1076 self.checklocalchanges(repo, force=force, refresh=False)
1076 self.checklocalchanges(repo, force=force, refresh=False)
1077 urev = self.qparents(repo, revs[0])
1077 urev = self.qparents(repo, revs[0])
1078 hg.clean(repo, urev)
1078 hg.clean(repo, urev)
1079 repo.dirstate.write()
1079 repo.dirstate.write()
1080
1080
1081 repair.strip(self.ui, repo, revs, backup)
1081 repair.strip(self.ui, repo, revs, backup)
1082 finally:
1082 finally:
1083 release(lock, wlock)
1083 release(lock, wlock)
1084
1084
1085 def isapplied(self, patch):
1085 def isapplied(self, patch):
1086 """returns (index, rev, patch)"""
1086 """returns (index, rev, patch)"""
1087 for i, a in enumerate(self.applied):
1087 for i, a in enumerate(self.applied):
1088 if a.name == patch:
1088 if a.name == patch:
1089 return (i, a.node, a.name)
1089 return (i, a.node, a.name)
1090 return None
1090 return None
1091
1091
1092 # if the exact patch name does not exist, we try a few
1092 # if the exact patch name does not exist, we try a few
1093 # variations. If strict is passed, we try only #1
1093 # variations. If strict is passed, we try only #1
1094 #
1094 #
1095 # 1) a number (as string) to indicate an offset in the series file
1095 # 1) a number (as string) to indicate an offset in the series file
1096 # 2) a unique substring of the patch name was given
1096 # 2) a unique substring of the patch name was given
1097 # 3) patchname[-+]num to indicate an offset in the series file
1097 # 3) patchname[-+]num to indicate an offset in the series file
1098 def lookup(self, patch, strict=False):
1098 def lookup(self, patch, strict=False):
1099 def partialname(s):
1099 def partialname(s):
1100 if s in self.series:
1100 if s in self.series:
1101 return s
1101 return s
1102 matches = [x for x in self.series if s in x]
1102 matches = [x for x in self.series if s in x]
1103 if len(matches) > 1:
1103 if len(matches) > 1:
1104 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1104 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
1105 for m in matches:
1105 for m in matches:
1106 self.ui.warn(' %s\n' % m)
1106 self.ui.warn(' %s\n' % m)
1107 return None
1107 return None
1108 if matches:
1108 if matches:
1109 return matches[0]
1109 return matches[0]
1110 if self.series and self.applied:
1110 if self.series and self.applied:
1111 if s == 'qtip':
1111 if s == 'qtip':
1112 return self.series[self.seriesend(True)-1]
1112 return self.series[self.seriesend(True)-1]
1113 if s == 'qbase':
1113 if s == 'qbase':
1114 return self.series[0]
1114 return self.series[0]
1115 return None
1115 return None
1116
1116
1117 if patch in self.series:
1117 if patch in self.series:
1118 return patch
1118 return patch
1119
1119
1120 if not os.path.isfile(self.join(patch)):
1120 if not os.path.isfile(self.join(patch)):
1121 try:
1121 try:
1122 sno = int(patch)
1122 sno = int(patch)
1123 except (ValueError, OverflowError):
1123 except (ValueError, OverflowError):
1124 pass
1124 pass
1125 else:
1125 else:
1126 if -len(self.series) <= sno < len(self.series):
1126 if -len(self.series) <= sno < len(self.series):
1127 return self.series[sno]
1127 return self.series[sno]
1128
1128
1129 if not strict:
1129 if not strict:
1130 res = partialname(patch)
1130 res = partialname(patch)
1131 if res:
1131 if res:
1132 return res
1132 return res
1133 minus = patch.rfind('-')
1133 minus = patch.rfind('-')
1134 if minus >= 0:
1134 if minus >= 0:
1135 res = partialname(patch[:minus])
1135 res = partialname(patch[:minus])
1136 if res:
1136 if res:
1137 i = self.series.index(res)
1137 i = self.series.index(res)
1138 try:
1138 try:
1139 off = int(patch[minus + 1:] or 1)
1139 off = int(patch[minus + 1:] or 1)
1140 except (ValueError, OverflowError):
1140 except (ValueError, OverflowError):
1141 pass
1141 pass
1142 else:
1142 else:
1143 if i - off >= 0:
1143 if i - off >= 0:
1144 return self.series[i - off]
1144 return self.series[i - off]
1145 plus = patch.rfind('+')
1145 plus = patch.rfind('+')
1146 if plus >= 0:
1146 if plus >= 0:
1147 res = partialname(patch[:plus])
1147 res = partialname(patch[:plus])
1148 if res:
1148 if res:
1149 i = self.series.index(res)
1149 i = self.series.index(res)
1150 try:
1150 try:
1151 off = int(patch[plus + 1:] or 1)
1151 off = int(patch[plus + 1:] or 1)
1152 except (ValueError, OverflowError):
1152 except (ValueError, OverflowError):
1153 pass
1153 pass
1154 else:
1154 else:
1155 if i + off < len(self.series):
1155 if i + off < len(self.series):
1156 return self.series[i + off]
1156 return self.series[i + off]
1157 raise util.Abort(_("patch %s not in series") % patch)
1157 raise util.Abort(_("patch %s not in series") % patch)
1158
1158
1159 def push(self, repo, patch=None, force=False, list=False,
1159 def push(self, repo, patch=None, force=False, list=False,
1160 mergeq=None, all=False, move=False, exact=False):
1160 mergeq=None, all=False, move=False, exact=False, nobackup=False):
1161 diffopts = self.diffopts()
1161 diffopts = self.diffopts()
1162 wlock = repo.wlock()
1162 wlock = repo.wlock()
1163 try:
1163 try:
1164 heads = []
1164 heads = []
1165 for b, ls in repo.branchmap().iteritems():
1165 for b, ls in repo.branchmap().iteritems():
1166 heads += ls
1166 heads += ls
1167 if not heads:
1167 if not heads:
1168 heads = [nullid]
1168 heads = [nullid]
1169 if repo.dirstate.p1() not in heads and not exact:
1169 if repo.dirstate.p1() not in heads and not exact:
1170 self.ui.status(_("(working directory not at a head)\n"))
1170 self.ui.status(_("(working directory not at a head)\n"))
1171
1171
1172 if not self.series:
1172 if not self.series:
1173 self.ui.warn(_('no patches in series\n'))
1173 self.ui.warn(_('no patches in series\n'))
1174 return 0
1174 return 0
1175
1175
1176 # Suppose our series file is: A B C and the current 'top'
1176 # Suppose our series file is: A B C and the current 'top'
1177 # patch is B. qpush C should be performed (moving forward)
1177 # patch is B. qpush C should be performed (moving forward)
1178 # qpush B is a NOP (no change) qpush A is an error (can't
1178 # qpush B is a NOP (no change) qpush A is an error (can't
1179 # go backwards with qpush)
1179 # go backwards with qpush)
1180 if patch:
1180 if patch:
1181 patch = self.lookup(patch)
1181 patch = self.lookup(patch)
1182 info = self.isapplied(patch)
1182 info = self.isapplied(patch)
1183 if info and info[0] >= len(self.applied) - 1:
1183 if info and info[0] >= len(self.applied) - 1:
1184 self.ui.warn(
1184 self.ui.warn(
1185 _('qpush: %s is already at the top\n') % patch)
1185 _('qpush: %s is already at the top\n') % patch)
1186 return 0
1186 return 0
1187
1187
1188 pushable, reason = self.pushable(patch)
1188 pushable, reason = self.pushable(patch)
1189 if pushable:
1189 if pushable:
1190 if self.series.index(patch) < self.seriesend():
1190 if self.series.index(patch) < self.seriesend():
1191 raise util.Abort(
1191 raise util.Abort(
1192 _("cannot push to a previous patch: %s") % patch)
1192 _("cannot push to a previous patch: %s") % patch)
1193 else:
1193 else:
1194 if reason:
1194 if reason:
1195 reason = _('guarded by %s') % reason
1195 reason = _('guarded by %s') % reason
1196 else:
1196 else:
1197 reason = _('no matching guards')
1197 reason = _('no matching guards')
1198 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1198 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1199 return 1
1199 return 1
1200 elif all:
1200 elif all:
1201 patch = self.series[-1]
1201 patch = self.series[-1]
1202 if self.isapplied(patch):
1202 if self.isapplied(patch):
1203 self.ui.warn(_('all patches are currently applied\n'))
1203 self.ui.warn(_('all patches are currently applied\n'))
1204 return 0
1204 return 0
1205
1205
1206 # Following the above example, starting at 'top' of B:
1206 # Following the above example, starting at 'top' of B:
1207 # qpush should be performed (pushes C), but a subsequent
1207 # qpush should be performed (pushes C), but a subsequent
1208 # qpush without an argument is an error (nothing to
1208 # qpush without an argument is an error (nothing to
1209 # apply). This allows a loop of "...while hg qpush..." to
1209 # apply). This allows a loop of "...while hg qpush..." to
1210 # work as it detects an error when done
1210 # work as it detects an error when done
1211 start = self.seriesend()
1211 start = self.seriesend()
1212 if start == len(self.series):
1212 if start == len(self.series):
1213 self.ui.warn(_('patch series already fully applied\n'))
1213 self.ui.warn(_('patch series already fully applied\n'))
1214 return 1
1214 return 1
1215 if not force:
1215 if not force:
1216 self.checklocalchanges(repo, refresh=self.applied)
1216 self.checklocalchanges(repo, refresh=self.applied)
1217
1217
1218 if exact:
1218 if exact:
1219 if move:
1219 if move:
1220 raise util.Abort(_("cannot use --exact and --move together"))
1220 raise util.Abort(_("cannot use --exact and --move together"))
1221 if self.applied:
1221 if self.applied:
1222 raise util.Abort(_("cannot push --exact with applied patches"))
1222 raise util.Abort(_("cannot push --exact with applied patches"))
1223 root = self.series[start]
1223 root = self.series[start]
1224 target = patchheader(self.join(root), self.plainmode).parent
1224 target = patchheader(self.join(root), self.plainmode).parent
1225 if not target:
1225 if not target:
1226 raise util.Abort(
1226 raise util.Abort(
1227 _("%s does not have a parent recorded") % root)
1227 _("%s does not have a parent recorded") % root)
1228 if not repo[target] == repo['.']:
1228 if not repo[target] == repo['.']:
1229 hg.update(repo, target)
1229 hg.update(repo, target)
1230
1230
1231 if move:
1231 if move:
1232 if not patch:
1232 if not patch:
1233 raise util.Abort(_("please specify the patch to move"))
1233 raise util.Abort(_("please specify the patch to move"))
1234 for fullstart, rpn in enumerate(self.fullseries):
1234 for fullstart, rpn in enumerate(self.fullseries):
1235 # strip markers for patch guards
1235 # strip markers for patch guards
1236 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1236 if self.guard_re.split(rpn, 1)[0] == self.series[start]:
1237 break
1237 break
1238 for i, rpn in enumerate(self.fullseries[fullstart:]):
1238 for i, rpn in enumerate(self.fullseries[fullstart:]):
1239 # strip markers for patch guards
1239 # strip markers for patch guards
1240 if self.guard_re.split(rpn, 1)[0] == patch:
1240 if self.guard_re.split(rpn, 1)[0] == patch:
1241 break
1241 break
1242 index = fullstart + i
1242 index = fullstart + i
1243 assert index < len(self.fullseries)
1243 assert index < len(self.fullseries)
1244 fullpatch = self.fullseries[index]
1244 fullpatch = self.fullseries[index]
1245 del self.fullseries[index]
1245 del self.fullseries[index]
1246 self.fullseries.insert(fullstart, fullpatch)
1246 self.fullseries.insert(fullstart, fullpatch)
1247 self.parseseries()
1247 self.parseseries()
1248 self.seriesdirty = True
1248 self.seriesdirty = True
1249
1249
1250 self.applieddirty = True
1250 self.applieddirty = True
1251 if start > 0:
1251 if start > 0:
1252 self.checktoppatch(repo)
1252 self.checktoppatch(repo)
1253 if not patch:
1253 if not patch:
1254 patch = self.series[start]
1254 patch = self.series[start]
1255 end = start + 1
1255 end = start + 1
1256 else:
1256 else:
1257 end = self.series.index(patch, start) + 1
1257 end = self.series.index(patch, start) + 1
1258
1258
1259 tobackup = set()
1259 tobackup = set()
1260 if force:
1260 if not nobackup and force:
1261 m, a, r, d = self.checklocalchanges(repo, force=True)
1261 m, a, r, d = self.checklocalchanges(repo, force=True)
1262 tobackup.update(m + a)
1262 tobackup.update(m + a)
1263
1263
1264 s = self.series[start:end]
1264 s = self.series[start:end]
1265 all_files = set()
1265 all_files = set()
1266 try:
1266 try:
1267 if mergeq:
1267 if mergeq:
1268 ret = self.mergepatch(repo, mergeq, s, diffopts)
1268 ret = self.mergepatch(repo, mergeq, s, diffopts)
1269 else:
1269 else:
1270 ret = self.apply(repo, s, list, all_files=all_files,
1270 ret = self.apply(repo, s, list, all_files=all_files,
1271 tobackup=tobackup)
1271 tobackup=tobackup)
1272 except:
1272 except:
1273 self.ui.warn(_('cleaning up working directory...'))
1273 self.ui.warn(_('cleaning up working directory...'))
1274 node = repo.dirstate.p1()
1274 node = repo.dirstate.p1()
1275 hg.revert(repo, node, None)
1275 hg.revert(repo, node, None)
1276 # only remove unknown files that we know we touched or
1276 # only remove unknown files that we know we touched or
1277 # created while patching
1277 # created while patching
1278 for f in all_files:
1278 for f in all_files:
1279 if f not in repo.dirstate:
1279 if f not in repo.dirstate:
1280 try:
1280 try:
1281 util.unlinkpath(repo.wjoin(f))
1281 util.unlinkpath(repo.wjoin(f))
1282 except OSError, inst:
1282 except OSError, inst:
1283 if inst.errno != errno.ENOENT:
1283 if inst.errno != errno.ENOENT:
1284 raise
1284 raise
1285 self.ui.warn(_('done\n'))
1285 self.ui.warn(_('done\n'))
1286 raise
1286 raise
1287
1287
1288 if not self.applied:
1288 if not self.applied:
1289 return ret[0]
1289 return ret[0]
1290 top = self.applied[-1].name
1290 top = self.applied[-1].name
1291 if ret[0] and ret[0] > 1:
1291 if ret[0] and ret[0] > 1:
1292 msg = _("errors during apply, please fix and refresh %s\n")
1292 msg = _("errors during apply, please fix and refresh %s\n")
1293 self.ui.write(msg % top)
1293 self.ui.write(msg % top)
1294 else:
1294 else:
1295 self.ui.write(_("now at: %s\n") % top)
1295 self.ui.write(_("now at: %s\n") % top)
1296 return ret[0]
1296 return ret[0]
1297
1297
1298 finally:
1298 finally:
1299 wlock.release()
1299 wlock.release()
1300
1300
1301 def pop(self, repo, patch=None, force=False, update=True, all=False):
1301 def pop(self, repo, patch=None, force=False, update=True, all=False,
1302 nobackup=False):
1302 wlock = repo.wlock()
1303 wlock = repo.wlock()
1303 try:
1304 try:
1304 if patch:
1305 if patch:
1305 # index, rev, patch
1306 # index, rev, patch
1306 info = self.isapplied(patch)
1307 info = self.isapplied(patch)
1307 if not info:
1308 if not info:
1308 patch = self.lookup(patch)
1309 patch = self.lookup(patch)
1309 info = self.isapplied(patch)
1310 info = self.isapplied(patch)
1310 if not info:
1311 if not info:
1311 raise util.Abort(_("patch %s is not applied") % patch)
1312 raise util.Abort(_("patch %s is not applied") % patch)
1312
1313
1313 if not self.applied:
1314 if not self.applied:
1314 # Allow qpop -a to work repeatedly,
1315 # Allow qpop -a to work repeatedly,
1315 # but not qpop without an argument
1316 # but not qpop without an argument
1316 self.ui.warn(_("no patches applied\n"))
1317 self.ui.warn(_("no patches applied\n"))
1317 return not all
1318 return not all
1318
1319
1319 if all:
1320 if all:
1320 start = 0
1321 start = 0
1321 elif patch:
1322 elif patch:
1322 start = info[0] + 1
1323 start = info[0] + 1
1323 else:
1324 else:
1324 start = len(self.applied) - 1
1325 start = len(self.applied) - 1
1325
1326
1326 if start >= len(self.applied):
1327 if start >= len(self.applied):
1327 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1328 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1328 return
1329 return
1329
1330
1330 if not update:
1331 if not update:
1331 parents = repo.dirstate.parents()
1332 parents = repo.dirstate.parents()
1332 rr = [x.node for x in self.applied]
1333 rr = [x.node for x in self.applied]
1333 for p in parents:
1334 for p in parents:
1334 if p in rr:
1335 if p in rr:
1335 self.ui.warn(_("qpop: forcing dirstate update\n"))
1336 self.ui.warn(_("qpop: forcing dirstate update\n"))
1336 update = True
1337 update = True
1337 else:
1338 else:
1338 parents = [p.node() for p in repo[None].parents()]
1339 parents = [p.node() for p in repo[None].parents()]
1339 needupdate = False
1340 needupdate = False
1340 for entry in self.applied[start:]:
1341 for entry in self.applied[start:]:
1341 if entry.node in parents:
1342 if entry.node in parents:
1342 needupdate = True
1343 needupdate = True
1343 break
1344 break
1344 update = needupdate
1345 update = needupdate
1345
1346
1346 tobackup = set()
1347 tobackup = set()
1347 if update:
1348 if update:
1348 m, a, r, d = self.checklocalchanges(repo, force=force)
1349 m, a, r, d = self.checklocalchanges(repo, force=force)
1349 tobackup.update(m + a)
1350 if not nobackup and force:
1351 tobackup.update(m + a)
1350
1352
1351 self.applieddirty = True
1353 self.applieddirty = True
1352 end = len(self.applied)
1354 end = len(self.applied)
1353 rev = self.applied[start].node
1355 rev = self.applied[start].node
1354 if update:
1356 if update:
1355 top = self.checktoppatch(repo)[0]
1357 top = self.checktoppatch(repo)[0]
1356
1358
1357 try:
1359 try:
1358 heads = repo.changelog.heads(rev)
1360 heads = repo.changelog.heads(rev)
1359 except error.LookupError:
1361 except error.LookupError:
1360 node = short(rev)
1362 node = short(rev)
1361 raise util.Abort(_('trying to pop unknown node %s') % node)
1363 raise util.Abort(_('trying to pop unknown node %s') % node)
1362
1364
1363 if heads != [self.applied[-1].node]:
1365 if heads != [self.applied[-1].node]:
1364 raise util.Abort(_("popping would remove a revision not "
1366 raise util.Abort(_("popping would remove a revision not "
1365 "managed by this patch queue"))
1367 "managed by this patch queue"))
1366 if not repo[self.applied[-1].node].mutable():
1368 if not repo[self.applied[-1].node].mutable():
1367 raise util.Abort(
1369 raise util.Abort(
1368 _("popping would remove an immutable revision"),
1370 _("popping would remove an immutable revision"),
1369 hint=_('see "hg help phases" for details'))
1371 hint=_('see "hg help phases" for details'))
1370
1372
1371 # we know there are no local changes, so we can make a simplified
1373 # we know there are no local changes, so we can make a simplified
1372 # form of hg.update.
1374 # form of hg.update.
1373 if update:
1375 if update:
1374 qp = self.qparents(repo, rev)
1376 qp = self.qparents(repo, rev)
1375 ctx = repo[qp]
1377 ctx = repo[qp]
1376 m, a, r, d = repo.status(qp, top)[:4]
1378 m, a, r, d = repo.status(qp, top)[:4]
1377 if d:
1379 if d:
1378 raise util.Abort(_("deletions found between repo revs"))
1380 raise util.Abort(_("deletions found between repo revs"))
1379
1381
1380 # backup local changes in --force case
1382 # backup local changes in --force case
1381 self.backup(repo, set(a + m + r) & tobackup)
1383 self.backup(repo, set(a + m + r) & tobackup)
1382
1384
1383 for f in a:
1385 for f in a:
1384 try:
1386 try:
1385 util.unlinkpath(repo.wjoin(f))
1387 util.unlinkpath(repo.wjoin(f))
1386 except OSError, e:
1388 except OSError, e:
1387 if e.errno != errno.ENOENT:
1389 if e.errno != errno.ENOENT:
1388 raise
1390 raise
1389 repo.dirstate.drop(f)
1391 repo.dirstate.drop(f)
1390 for f in m + r:
1392 for f in m + r:
1391 fctx = ctx[f]
1393 fctx = ctx[f]
1392 repo.wwrite(f, fctx.data(), fctx.flags())
1394 repo.wwrite(f, fctx.data(), fctx.flags())
1393 repo.dirstate.normal(f)
1395 repo.dirstate.normal(f)
1394 repo.setparents(qp, nullid)
1396 repo.setparents(qp, nullid)
1395 for patch in reversed(self.applied[start:end]):
1397 for patch in reversed(self.applied[start:end]):
1396 self.ui.status(_("popping %s\n") % patch.name)
1398 self.ui.status(_("popping %s\n") % patch.name)
1397 del self.applied[start:end]
1399 del self.applied[start:end]
1398 self.strip(repo, [rev], update=False, backup='strip')
1400 self.strip(repo, [rev], update=False, backup='strip')
1399 if self.applied:
1401 if self.applied:
1400 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1402 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1401 else:
1403 else:
1402 self.ui.write(_("patch queue now empty\n"))
1404 self.ui.write(_("patch queue now empty\n"))
1403 finally:
1405 finally:
1404 wlock.release()
1406 wlock.release()
1405
1407
1406 def diff(self, repo, pats, opts):
1408 def diff(self, repo, pats, opts):
1407 top, patch = self.checktoppatch(repo)
1409 top, patch = self.checktoppatch(repo)
1408 if not top:
1410 if not top:
1409 self.ui.write(_("no patches applied\n"))
1411 self.ui.write(_("no patches applied\n"))
1410 return
1412 return
1411 qp = self.qparents(repo, top)
1413 qp = self.qparents(repo, top)
1412 if opts.get('reverse'):
1414 if opts.get('reverse'):
1413 node1, node2 = None, qp
1415 node1, node2 = None, qp
1414 else:
1416 else:
1415 node1, node2 = qp, None
1417 node1, node2 = qp, None
1416 diffopts = self.diffopts(opts, patch)
1418 diffopts = self.diffopts(opts, patch)
1417 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1419 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1418
1420
1419 def refresh(self, repo, pats=None, **opts):
1421 def refresh(self, repo, pats=None, **opts):
1420 if not self.applied:
1422 if not self.applied:
1421 self.ui.write(_("no patches applied\n"))
1423 self.ui.write(_("no patches applied\n"))
1422 return 1
1424 return 1
1423 msg = opts.get('msg', '').rstrip()
1425 msg = opts.get('msg', '').rstrip()
1424 newuser = opts.get('user')
1426 newuser = opts.get('user')
1425 newdate = opts.get('date')
1427 newdate = opts.get('date')
1426 if newdate:
1428 if newdate:
1427 newdate = '%d %d' % util.parsedate(newdate)
1429 newdate = '%d %d' % util.parsedate(newdate)
1428 wlock = repo.wlock()
1430 wlock = repo.wlock()
1429
1431
1430 try:
1432 try:
1431 self.checktoppatch(repo)
1433 self.checktoppatch(repo)
1432 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1434 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1433 if repo.changelog.heads(top) != [top]:
1435 if repo.changelog.heads(top) != [top]:
1434 raise util.Abort(_("cannot refresh a revision with children"))
1436 raise util.Abort(_("cannot refresh a revision with children"))
1435 if not repo[top].mutable():
1437 if not repo[top].mutable():
1436 raise util.Abort(_("cannot refresh immutable revision"),
1438 raise util.Abort(_("cannot refresh immutable revision"),
1437 hint=_('see "hg help phases" for details'))
1439 hint=_('see "hg help phases" for details'))
1438
1440
1439 inclsubs = self.checksubstate(repo)
1441 inclsubs = self.checksubstate(repo)
1440
1442
1441 cparents = repo.changelog.parents(top)
1443 cparents = repo.changelog.parents(top)
1442 patchparent = self.qparents(repo, top)
1444 patchparent = self.qparents(repo, top)
1443 ph = patchheader(self.join(patchfn), self.plainmode)
1445 ph = patchheader(self.join(patchfn), self.plainmode)
1444 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1446 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1445 if msg:
1447 if msg:
1446 ph.setmessage(msg)
1448 ph.setmessage(msg)
1447 if newuser:
1449 if newuser:
1448 ph.setuser(newuser)
1450 ph.setuser(newuser)
1449 if newdate:
1451 if newdate:
1450 ph.setdate(newdate)
1452 ph.setdate(newdate)
1451 ph.setparent(hex(patchparent))
1453 ph.setparent(hex(patchparent))
1452
1454
1453 # only commit new patch when write is complete
1455 # only commit new patch when write is complete
1454 patchf = self.opener(patchfn, 'w', atomictemp=True)
1456 patchf = self.opener(patchfn, 'w', atomictemp=True)
1455
1457
1456 comments = str(ph)
1458 comments = str(ph)
1457 if comments:
1459 if comments:
1458 patchf.write(comments)
1460 patchf.write(comments)
1459
1461
1460 # update the dirstate in place, strip off the qtip commit
1462 # update the dirstate in place, strip off the qtip commit
1461 # and then commit.
1463 # and then commit.
1462 #
1464 #
1463 # this should really read:
1465 # this should really read:
1464 # mm, dd, aa = repo.status(top, patchparent)[:3]
1466 # mm, dd, aa = repo.status(top, patchparent)[:3]
1465 # but we do it backwards to take advantage of manifest/chlog
1467 # but we do it backwards to take advantage of manifest/chlog
1466 # caching against the next repo.status call
1468 # caching against the next repo.status call
1467 mm, aa, dd = repo.status(patchparent, top)[:3]
1469 mm, aa, dd = repo.status(patchparent, top)[:3]
1468 changes = repo.changelog.read(top)
1470 changes = repo.changelog.read(top)
1469 man = repo.manifest.read(changes[0])
1471 man = repo.manifest.read(changes[0])
1470 aaa = aa[:]
1472 aaa = aa[:]
1471 matchfn = scmutil.match(repo[None], pats, opts)
1473 matchfn = scmutil.match(repo[None], pats, opts)
1472 # in short mode, we only diff the files included in the
1474 # in short mode, we only diff the files included in the
1473 # patch already plus specified files
1475 # patch already plus specified files
1474 if opts.get('short'):
1476 if opts.get('short'):
1475 # if amending a patch, we start with existing
1477 # if amending a patch, we start with existing
1476 # files plus specified files - unfiltered
1478 # files plus specified files - unfiltered
1477 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1479 match = scmutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1478 # filter with inc/exl options
1480 # filter with inc/exl options
1479 matchfn = scmutil.match(repo[None], opts=opts)
1481 matchfn = scmutil.match(repo[None], opts=opts)
1480 else:
1482 else:
1481 match = scmutil.matchall(repo)
1483 match = scmutil.matchall(repo)
1482 m, a, r, d = repo.status(match=match)[:4]
1484 m, a, r, d = repo.status(match=match)[:4]
1483 mm = set(mm)
1485 mm = set(mm)
1484 aa = set(aa)
1486 aa = set(aa)
1485 dd = set(dd)
1487 dd = set(dd)
1486
1488
1487 # we might end up with files that were added between
1489 # we might end up with files that were added between
1488 # qtip and the dirstate parent, but then changed in the
1490 # qtip and the dirstate parent, but then changed in the
1489 # local dirstate. in this case, we want them to only
1491 # local dirstate. in this case, we want them to only
1490 # show up in the added section
1492 # show up in the added section
1491 for x in m:
1493 for x in m:
1492 if x not in aa:
1494 if x not in aa:
1493 mm.add(x)
1495 mm.add(x)
1494 # we might end up with files added by the local dirstate that
1496 # we might end up with files added by the local dirstate that
1495 # were deleted by the patch. In this case, they should only
1497 # were deleted by the patch. In this case, they should only
1496 # show up in the changed section.
1498 # show up in the changed section.
1497 for x in a:
1499 for x in a:
1498 if x in dd:
1500 if x in dd:
1499 dd.remove(x)
1501 dd.remove(x)
1500 mm.add(x)
1502 mm.add(x)
1501 else:
1503 else:
1502 aa.add(x)
1504 aa.add(x)
1503 # make sure any files deleted in the local dirstate
1505 # make sure any files deleted in the local dirstate
1504 # are not in the add or change column of the patch
1506 # are not in the add or change column of the patch
1505 forget = []
1507 forget = []
1506 for x in d + r:
1508 for x in d + r:
1507 if x in aa:
1509 if x in aa:
1508 aa.remove(x)
1510 aa.remove(x)
1509 forget.append(x)
1511 forget.append(x)
1510 continue
1512 continue
1511 else:
1513 else:
1512 mm.discard(x)
1514 mm.discard(x)
1513 dd.add(x)
1515 dd.add(x)
1514
1516
1515 m = list(mm)
1517 m = list(mm)
1516 r = list(dd)
1518 r = list(dd)
1517 a = list(aa)
1519 a = list(aa)
1518 c = [filter(matchfn, l) for l in (m, a, r)]
1520 c = [filter(matchfn, l) for l in (m, a, r)]
1519 match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
1521 match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
1520 chunks = patchmod.diff(repo, patchparent, match=match,
1522 chunks = patchmod.diff(repo, patchparent, match=match,
1521 changes=c, opts=diffopts)
1523 changes=c, opts=diffopts)
1522 for chunk in chunks:
1524 for chunk in chunks:
1523 patchf.write(chunk)
1525 patchf.write(chunk)
1524
1526
1525 try:
1527 try:
1526 if diffopts.git or diffopts.upgrade:
1528 if diffopts.git or diffopts.upgrade:
1527 copies = {}
1529 copies = {}
1528 for dst in a:
1530 for dst in a:
1529 src = repo.dirstate.copied(dst)
1531 src = repo.dirstate.copied(dst)
1530 # during qfold, the source file for copies may
1532 # during qfold, the source file for copies may
1531 # be removed. Treat this as a simple add.
1533 # be removed. Treat this as a simple add.
1532 if src is not None and src in repo.dirstate:
1534 if src is not None and src in repo.dirstate:
1533 copies.setdefault(src, []).append(dst)
1535 copies.setdefault(src, []).append(dst)
1534 repo.dirstate.add(dst)
1536 repo.dirstate.add(dst)
1535 # remember the copies between patchparent and qtip
1537 # remember the copies between patchparent and qtip
1536 for dst in aaa:
1538 for dst in aaa:
1537 f = repo.file(dst)
1539 f = repo.file(dst)
1538 src = f.renamed(man[dst])
1540 src = f.renamed(man[dst])
1539 if src:
1541 if src:
1540 copies.setdefault(src[0], []).extend(
1542 copies.setdefault(src[0], []).extend(
1541 copies.get(dst, []))
1543 copies.get(dst, []))
1542 if dst in a:
1544 if dst in a:
1543 copies[src[0]].append(dst)
1545 copies[src[0]].append(dst)
1544 # we can't copy a file created by the patch itself
1546 # we can't copy a file created by the patch itself
1545 if dst in copies:
1547 if dst in copies:
1546 del copies[dst]
1548 del copies[dst]
1547 for src, dsts in copies.iteritems():
1549 for src, dsts in copies.iteritems():
1548 for dst in dsts:
1550 for dst in dsts:
1549 repo.dirstate.copy(src, dst)
1551 repo.dirstate.copy(src, dst)
1550 else:
1552 else:
1551 for dst in a:
1553 for dst in a:
1552 repo.dirstate.add(dst)
1554 repo.dirstate.add(dst)
1553 # Drop useless copy information
1555 # Drop useless copy information
1554 for f in list(repo.dirstate.copies()):
1556 for f in list(repo.dirstate.copies()):
1555 repo.dirstate.copy(None, f)
1557 repo.dirstate.copy(None, f)
1556 for f in r:
1558 for f in r:
1557 repo.dirstate.remove(f)
1559 repo.dirstate.remove(f)
1558 # if the patch excludes a modified file, mark that
1560 # if the patch excludes a modified file, mark that
1559 # file with mtime=0 so status can see it.
1561 # file with mtime=0 so status can see it.
1560 mm = []
1562 mm = []
1561 for i in xrange(len(m)-1, -1, -1):
1563 for i in xrange(len(m)-1, -1, -1):
1562 if not matchfn(m[i]):
1564 if not matchfn(m[i]):
1563 mm.append(m[i])
1565 mm.append(m[i])
1564 del m[i]
1566 del m[i]
1565 for f in m:
1567 for f in m:
1566 repo.dirstate.normal(f)
1568 repo.dirstate.normal(f)
1567 for f in mm:
1569 for f in mm:
1568 repo.dirstate.normallookup(f)
1570 repo.dirstate.normallookup(f)
1569 for f in forget:
1571 for f in forget:
1570 repo.dirstate.drop(f)
1572 repo.dirstate.drop(f)
1571
1573
1572 if not msg:
1574 if not msg:
1573 if not ph.message:
1575 if not ph.message:
1574 message = "[mq]: %s\n" % patchfn
1576 message = "[mq]: %s\n" % patchfn
1575 else:
1577 else:
1576 message = "\n".join(ph.message)
1578 message = "\n".join(ph.message)
1577 else:
1579 else:
1578 message = msg
1580 message = msg
1579
1581
1580 user = ph.user or changes[1]
1582 user = ph.user or changes[1]
1581
1583
1582 oldphase = repo[top].phase()
1584 oldphase = repo[top].phase()
1583
1585
1584 # assumes strip can roll itself back if interrupted
1586 # assumes strip can roll itself back if interrupted
1585 repo.setparents(*cparents)
1587 repo.setparents(*cparents)
1586 self.applied.pop()
1588 self.applied.pop()
1587 self.applieddirty = True
1589 self.applieddirty = True
1588 self.strip(repo, [top], update=False,
1590 self.strip(repo, [top], update=False,
1589 backup='strip')
1591 backup='strip')
1590 except:
1592 except:
1591 repo.dirstate.invalidate()
1593 repo.dirstate.invalidate()
1592 raise
1594 raise
1593
1595
1594 try:
1596 try:
1595 # might be nice to attempt to roll back strip after this
1597 # might be nice to attempt to roll back strip after this
1596
1598
1597 # Ensure we create a new changeset in the same phase than
1599 # Ensure we create a new changeset in the same phase than
1598 # the old one.
1600 # the old one.
1599 n = newcommit(repo, oldphase, message, user, ph.date,
1601 n = newcommit(repo, oldphase, message, user, ph.date,
1600 match=match, force=True)
1602 match=match, force=True)
1601 # only write patch after a successful commit
1603 # only write patch after a successful commit
1602 patchf.close()
1604 patchf.close()
1603 self.applied.append(statusentry(n, patchfn))
1605 self.applied.append(statusentry(n, patchfn))
1604 except:
1606 except:
1605 ctx = repo[cparents[0]]
1607 ctx = repo[cparents[0]]
1606 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1608 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1607 self.savedirty()
1609 self.savedirty()
1608 self.ui.warn(_('refresh interrupted while patch was popped! '
1610 self.ui.warn(_('refresh interrupted while patch was popped! '
1609 '(revert --all, qpush to recover)\n'))
1611 '(revert --all, qpush to recover)\n'))
1610 raise
1612 raise
1611 finally:
1613 finally:
1612 wlock.release()
1614 wlock.release()
1613 self.removeundo(repo)
1615 self.removeundo(repo)
1614
1616
1615 def init(self, repo, create=False):
1617 def init(self, repo, create=False):
1616 if not create and os.path.isdir(self.path):
1618 if not create and os.path.isdir(self.path):
1617 raise util.Abort(_("patch queue directory already exists"))
1619 raise util.Abort(_("patch queue directory already exists"))
1618 try:
1620 try:
1619 os.mkdir(self.path)
1621 os.mkdir(self.path)
1620 except OSError, inst:
1622 except OSError, inst:
1621 if inst.errno != errno.EEXIST or not create:
1623 if inst.errno != errno.EEXIST or not create:
1622 raise
1624 raise
1623 if create:
1625 if create:
1624 return self.qrepo(create=True)
1626 return self.qrepo(create=True)
1625
1627
1626 def unapplied(self, repo, patch=None):
1628 def unapplied(self, repo, patch=None):
1627 if patch and patch not in self.series:
1629 if patch and patch not in self.series:
1628 raise util.Abort(_("patch %s is not in series file") % patch)
1630 raise util.Abort(_("patch %s is not in series file") % patch)
1629 if not patch:
1631 if not patch:
1630 start = self.seriesend()
1632 start = self.seriesend()
1631 else:
1633 else:
1632 start = self.series.index(patch) + 1
1634 start = self.series.index(patch) + 1
1633 unapplied = []
1635 unapplied = []
1634 for i in xrange(start, len(self.series)):
1636 for i in xrange(start, len(self.series)):
1635 pushable, reason = self.pushable(i)
1637 pushable, reason = self.pushable(i)
1636 if pushable:
1638 if pushable:
1637 unapplied.append((i, self.series[i]))
1639 unapplied.append((i, self.series[i]))
1638 self.explainpushable(i)
1640 self.explainpushable(i)
1639 return unapplied
1641 return unapplied
1640
1642
1641 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1643 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1642 summary=False):
1644 summary=False):
1643 def displayname(pfx, patchname, state):
1645 def displayname(pfx, patchname, state):
1644 if pfx:
1646 if pfx:
1645 self.ui.write(pfx)
1647 self.ui.write(pfx)
1646 if summary:
1648 if summary:
1647 ph = patchheader(self.join(patchname), self.plainmode)
1649 ph = patchheader(self.join(patchname), self.plainmode)
1648 msg = ph.message and ph.message[0] or ''
1650 msg = ph.message and ph.message[0] or ''
1649 if self.ui.formatted():
1651 if self.ui.formatted():
1650 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1652 width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
1651 if width > 0:
1653 if width > 0:
1652 msg = util.ellipsis(msg, width)
1654 msg = util.ellipsis(msg, width)
1653 else:
1655 else:
1654 msg = ''
1656 msg = ''
1655 self.ui.write(patchname, label='qseries.' + state)
1657 self.ui.write(patchname, label='qseries.' + state)
1656 self.ui.write(': ')
1658 self.ui.write(': ')
1657 self.ui.write(msg, label='qseries.message.' + state)
1659 self.ui.write(msg, label='qseries.message.' + state)
1658 else:
1660 else:
1659 self.ui.write(patchname, label='qseries.' + state)
1661 self.ui.write(patchname, label='qseries.' + state)
1660 self.ui.write('\n')
1662 self.ui.write('\n')
1661
1663
1662 applied = set([p.name for p in self.applied])
1664 applied = set([p.name for p in self.applied])
1663 if length is None:
1665 if length is None:
1664 length = len(self.series) - start
1666 length = len(self.series) - start
1665 if not missing:
1667 if not missing:
1666 if self.ui.verbose:
1668 if self.ui.verbose:
1667 idxwidth = len(str(start + length - 1))
1669 idxwidth = len(str(start + length - 1))
1668 for i in xrange(start, start + length):
1670 for i in xrange(start, start + length):
1669 patch = self.series[i]
1671 patch = self.series[i]
1670 if patch in applied:
1672 if patch in applied:
1671 char, state = 'A', 'applied'
1673 char, state = 'A', 'applied'
1672 elif self.pushable(i)[0]:
1674 elif self.pushable(i)[0]:
1673 char, state = 'U', 'unapplied'
1675 char, state = 'U', 'unapplied'
1674 else:
1676 else:
1675 char, state = 'G', 'guarded'
1677 char, state = 'G', 'guarded'
1676 pfx = ''
1678 pfx = ''
1677 if self.ui.verbose:
1679 if self.ui.verbose:
1678 pfx = '%*d %s ' % (idxwidth, i, char)
1680 pfx = '%*d %s ' % (idxwidth, i, char)
1679 elif status and status != char:
1681 elif status and status != char:
1680 continue
1682 continue
1681 displayname(pfx, patch, state)
1683 displayname(pfx, patch, state)
1682 else:
1684 else:
1683 msng_list = []
1685 msng_list = []
1684 for root, dirs, files in os.walk(self.path):
1686 for root, dirs, files in os.walk(self.path):
1685 d = root[len(self.path) + 1:]
1687 d = root[len(self.path) + 1:]
1686 for f in files:
1688 for f in files:
1687 fl = os.path.join(d, f)
1689 fl = os.path.join(d, f)
1688 if (fl not in self.series and
1690 if (fl not in self.series and
1689 fl not in (self.statuspath, self.seriespath,
1691 fl not in (self.statuspath, self.seriespath,
1690 self.guardspath)
1692 self.guardspath)
1691 and not fl.startswith('.')):
1693 and not fl.startswith('.')):
1692 msng_list.append(fl)
1694 msng_list.append(fl)
1693 for x in sorted(msng_list):
1695 for x in sorted(msng_list):
1694 pfx = self.ui.verbose and ('D ') or ''
1696 pfx = self.ui.verbose and ('D ') or ''
1695 displayname(pfx, x, 'missing')
1697 displayname(pfx, x, 'missing')
1696
1698
1697 def issaveline(self, l):
1699 def issaveline(self, l):
1698 if l.name == '.hg.patches.save.line':
1700 if l.name == '.hg.patches.save.line':
1699 return True
1701 return True
1700
1702
1701 def qrepo(self, create=False):
1703 def qrepo(self, create=False):
1702 ui = self.ui.copy()
1704 ui = self.ui.copy()
1703 ui.setconfig('paths', 'default', '', overlay=False)
1705 ui.setconfig('paths', 'default', '', overlay=False)
1704 ui.setconfig('paths', 'default-push', '', overlay=False)
1706 ui.setconfig('paths', 'default-push', '', overlay=False)
1705 if create or os.path.isdir(self.join(".hg")):
1707 if create or os.path.isdir(self.join(".hg")):
1706 return hg.repository(ui, path=self.path, create=create)
1708 return hg.repository(ui, path=self.path, create=create)
1707
1709
1708 def restore(self, repo, rev, delete=None, qupdate=None):
1710 def restore(self, repo, rev, delete=None, qupdate=None):
1709 desc = repo[rev].description().strip()
1711 desc = repo[rev].description().strip()
1710 lines = desc.splitlines()
1712 lines = desc.splitlines()
1711 i = 0
1713 i = 0
1712 datastart = None
1714 datastart = None
1713 series = []
1715 series = []
1714 applied = []
1716 applied = []
1715 qpp = None
1717 qpp = None
1716 for i, line in enumerate(lines):
1718 for i, line in enumerate(lines):
1717 if line == 'Patch Data:':
1719 if line == 'Patch Data:':
1718 datastart = i + 1
1720 datastart = i + 1
1719 elif line.startswith('Dirstate:'):
1721 elif line.startswith('Dirstate:'):
1720 l = line.rstrip()
1722 l = line.rstrip()
1721 l = l[10:].split(' ')
1723 l = l[10:].split(' ')
1722 qpp = [bin(x) for x in l]
1724 qpp = [bin(x) for x in l]
1723 elif datastart is not None:
1725 elif datastart is not None:
1724 l = line.rstrip()
1726 l = line.rstrip()
1725 n, name = l.split(':', 1)
1727 n, name = l.split(':', 1)
1726 if n:
1728 if n:
1727 applied.append(statusentry(bin(n), name))
1729 applied.append(statusentry(bin(n), name))
1728 else:
1730 else:
1729 series.append(l)
1731 series.append(l)
1730 if datastart is None:
1732 if datastart is None:
1731 self.ui.warn(_("No saved patch data found\n"))
1733 self.ui.warn(_("No saved patch data found\n"))
1732 return 1
1734 return 1
1733 self.ui.warn(_("restoring status: %s\n") % lines[0])
1735 self.ui.warn(_("restoring status: %s\n") % lines[0])
1734 self.fullseries = series
1736 self.fullseries = series
1735 self.applied = applied
1737 self.applied = applied
1736 self.parseseries()
1738 self.parseseries()
1737 self.seriesdirty = True
1739 self.seriesdirty = True
1738 self.applieddirty = True
1740 self.applieddirty = True
1739 heads = repo.changelog.heads()
1741 heads = repo.changelog.heads()
1740 if delete:
1742 if delete:
1741 if rev not in heads:
1743 if rev not in heads:
1742 self.ui.warn(_("save entry has children, leaving it alone\n"))
1744 self.ui.warn(_("save entry has children, leaving it alone\n"))
1743 else:
1745 else:
1744 self.ui.warn(_("removing save entry %s\n") % short(rev))
1746 self.ui.warn(_("removing save entry %s\n") % short(rev))
1745 pp = repo.dirstate.parents()
1747 pp = repo.dirstate.parents()
1746 if rev in pp:
1748 if rev in pp:
1747 update = True
1749 update = True
1748 else:
1750 else:
1749 update = False
1751 update = False
1750 self.strip(repo, [rev], update=update, backup='strip')
1752 self.strip(repo, [rev], update=update, backup='strip')
1751 if qpp:
1753 if qpp:
1752 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1754 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1753 (short(qpp[0]), short(qpp[1])))
1755 (short(qpp[0]), short(qpp[1])))
1754 if qupdate:
1756 if qupdate:
1755 self.ui.status(_("updating queue directory\n"))
1757 self.ui.status(_("updating queue directory\n"))
1756 r = self.qrepo()
1758 r = self.qrepo()
1757 if not r:
1759 if not r:
1758 self.ui.warn(_("Unable to load queue repository\n"))
1760 self.ui.warn(_("Unable to load queue repository\n"))
1759 return 1
1761 return 1
1760 hg.clean(r, qpp[0])
1762 hg.clean(r, qpp[0])
1761
1763
1762 def save(self, repo, msg=None):
1764 def save(self, repo, msg=None):
1763 if not self.applied:
1765 if not self.applied:
1764 self.ui.warn(_("save: no patches applied, exiting\n"))
1766 self.ui.warn(_("save: no patches applied, exiting\n"))
1765 return 1
1767 return 1
1766 if self.issaveline(self.applied[-1]):
1768 if self.issaveline(self.applied[-1]):
1767 self.ui.warn(_("status is already saved\n"))
1769 self.ui.warn(_("status is already saved\n"))
1768 return 1
1770 return 1
1769
1771
1770 if not msg:
1772 if not msg:
1771 msg = _("hg patches saved state")
1773 msg = _("hg patches saved state")
1772 else:
1774 else:
1773 msg = "hg patches: " + msg.rstrip('\r\n')
1775 msg = "hg patches: " + msg.rstrip('\r\n')
1774 r = self.qrepo()
1776 r = self.qrepo()
1775 if r:
1777 if r:
1776 pp = r.dirstate.parents()
1778 pp = r.dirstate.parents()
1777 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1779 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1778 msg += "\n\nPatch Data:\n"
1780 msg += "\n\nPatch Data:\n"
1779 msg += ''.join('%s\n' % x for x in self.applied)
1781 msg += ''.join('%s\n' % x for x in self.applied)
1780 msg += ''.join(':%s\n' % x for x in self.fullseries)
1782 msg += ''.join(':%s\n' % x for x in self.fullseries)
1781 n = repo.commit(msg, force=True)
1783 n = repo.commit(msg, force=True)
1782 if not n:
1784 if not n:
1783 self.ui.warn(_("repo commit failed\n"))
1785 self.ui.warn(_("repo commit failed\n"))
1784 return 1
1786 return 1
1785 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1787 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1786 self.applieddirty = True
1788 self.applieddirty = True
1787 self.removeundo(repo)
1789 self.removeundo(repo)
1788
1790
1789 def fullseriesend(self):
1791 def fullseriesend(self):
1790 if self.applied:
1792 if self.applied:
1791 p = self.applied[-1].name
1793 p = self.applied[-1].name
1792 end = self.findseries(p)
1794 end = self.findseries(p)
1793 if end is None:
1795 if end is None:
1794 return len(self.fullseries)
1796 return len(self.fullseries)
1795 return end + 1
1797 return end + 1
1796 return 0
1798 return 0
1797
1799
1798 def seriesend(self, all_patches=False):
1800 def seriesend(self, all_patches=False):
1799 """If all_patches is False, return the index of the next pushable patch
1801 """If all_patches is False, return the index of the next pushable patch
1800 in the series, or the series length. If all_patches is True, return the
1802 in the series, or the series length. If all_patches is True, return the
1801 index of the first patch past the last applied one.
1803 index of the first patch past the last applied one.
1802 """
1804 """
1803 end = 0
1805 end = 0
1804 def next(start):
1806 def next(start):
1805 if all_patches or start >= len(self.series):
1807 if all_patches or start >= len(self.series):
1806 return start
1808 return start
1807 for i in xrange(start, len(self.series)):
1809 for i in xrange(start, len(self.series)):
1808 p, reason = self.pushable(i)
1810 p, reason = self.pushable(i)
1809 if p:
1811 if p:
1810 return i
1812 return i
1811 self.explainpushable(i)
1813 self.explainpushable(i)
1812 return len(self.series)
1814 return len(self.series)
1813 if self.applied:
1815 if self.applied:
1814 p = self.applied[-1].name
1816 p = self.applied[-1].name
1815 try:
1817 try:
1816 end = self.series.index(p)
1818 end = self.series.index(p)
1817 except ValueError:
1819 except ValueError:
1818 return 0
1820 return 0
1819 return next(end + 1)
1821 return next(end + 1)
1820 return next(end)
1822 return next(end)
1821
1823
1822 def appliedname(self, index):
1824 def appliedname(self, index):
1823 pname = self.applied[index].name
1825 pname = self.applied[index].name
1824 if not self.ui.verbose:
1826 if not self.ui.verbose:
1825 p = pname
1827 p = pname
1826 else:
1828 else:
1827 p = str(self.series.index(pname)) + " " + pname
1829 p = str(self.series.index(pname)) + " " + pname
1828 return p
1830 return p
1829
1831
1830 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1832 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1831 force=None, git=False):
1833 force=None, git=False):
1832 def checkseries(patchname):
1834 def checkseries(patchname):
1833 if patchname in self.series:
1835 if patchname in self.series:
1834 raise util.Abort(_('patch %s is already in the series file')
1836 raise util.Abort(_('patch %s is already in the series file')
1835 % patchname)
1837 % patchname)
1836
1838
1837 if rev:
1839 if rev:
1838 if files:
1840 if files:
1839 raise util.Abort(_('option "-r" not valid when importing '
1841 raise util.Abort(_('option "-r" not valid when importing '
1840 'files'))
1842 'files'))
1841 rev = scmutil.revrange(repo, rev)
1843 rev = scmutil.revrange(repo, rev)
1842 rev.sort(reverse=True)
1844 rev.sort(reverse=True)
1843 if (len(files) > 1 or len(rev) > 1) and patchname:
1845 if (len(files) > 1 or len(rev) > 1) and patchname:
1844 raise util.Abort(_('option "-n" not valid when importing multiple '
1846 raise util.Abort(_('option "-n" not valid when importing multiple '
1845 'patches'))
1847 'patches'))
1846 imported = []
1848 imported = []
1847 if rev:
1849 if rev:
1848 # If mq patches are applied, we can only import revisions
1850 # If mq patches are applied, we can only import revisions
1849 # that form a linear path to qbase.
1851 # that form a linear path to qbase.
1850 # Otherwise, they should form a linear path to a head.
1852 # Otherwise, they should form a linear path to a head.
1851 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1853 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1852 if len(heads) > 1:
1854 if len(heads) > 1:
1853 raise util.Abort(_('revision %d is the root of more than one '
1855 raise util.Abort(_('revision %d is the root of more than one '
1854 'branch') % rev[-1])
1856 'branch') % rev[-1])
1855 if self.applied:
1857 if self.applied:
1856 base = repo.changelog.node(rev[0])
1858 base = repo.changelog.node(rev[0])
1857 if base in [n.node for n in self.applied]:
1859 if base in [n.node for n in self.applied]:
1858 raise util.Abort(_('revision %d is already managed')
1860 raise util.Abort(_('revision %d is already managed')
1859 % rev[0])
1861 % rev[0])
1860 if heads != [self.applied[-1].node]:
1862 if heads != [self.applied[-1].node]:
1861 raise util.Abort(_('revision %d is not the parent of '
1863 raise util.Abort(_('revision %d is not the parent of '
1862 'the queue') % rev[0])
1864 'the queue') % rev[0])
1863 base = repo.changelog.rev(self.applied[0].node)
1865 base = repo.changelog.rev(self.applied[0].node)
1864 lastparent = repo.changelog.parentrevs(base)[0]
1866 lastparent = repo.changelog.parentrevs(base)[0]
1865 else:
1867 else:
1866 if heads != [repo.changelog.node(rev[0])]:
1868 if heads != [repo.changelog.node(rev[0])]:
1867 raise util.Abort(_('revision %d has unmanaged children')
1869 raise util.Abort(_('revision %d has unmanaged children')
1868 % rev[0])
1870 % rev[0])
1869 lastparent = None
1871 lastparent = None
1870
1872
1871 diffopts = self.diffopts({'git': git})
1873 diffopts = self.diffopts({'git': git})
1872 for r in rev:
1874 for r in rev:
1873 if not repo[r].mutable():
1875 if not repo[r].mutable():
1874 raise util.Abort(_('revision %d is not mutable') % r,
1876 raise util.Abort(_('revision %d is not mutable') % r,
1875 hint=_('see "hg help phases" for details'))
1877 hint=_('see "hg help phases" for details'))
1876 p1, p2 = repo.changelog.parentrevs(r)
1878 p1, p2 = repo.changelog.parentrevs(r)
1877 n = repo.changelog.node(r)
1879 n = repo.changelog.node(r)
1878 if p2 != nullrev:
1880 if p2 != nullrev:
1879 raise util.Abort(_('cannot import merge revision %d') % r)
1881 raise util.Abort(_('cannot import merge revision %d') % r)
1880 if lastparent and lastparent != r:
1882 if lastparent and lastparent != r:
1881 raise util.Abort(_('revision %d is not the parent of %d')
1883 raise util.Abort(_('revision %d is not the parent of %d')
1882 % (r, lastparent))
1884 % (r, lastparent))
1883 lastparent = p1
1885 lastparent = p1
1884
1886
1885 if not patchname:
1887 if not patchname:
1886 patchname = normname('%d.diff' % r)
1888 patchname = normname('%d.diff' % r)
1887 checkseries(patchname)
1889 checkseries(patchname)
1888 self.checkpatchname(patchname, force)
1890 self.checkpatchname(patchname, force)
1889 self.fullseries.insert(0, patchname)
1891 self.fullseries.insert(0, patchname)
1890
1892
1891 patchf = self.opener(patchname, "w")
1893 patchf = self.opener(patchname, "w")
1892 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1894 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1893 patchf.close()
1895 patchf.close()
1894
1896
1895 se = statusentry(n, patchname)
1897 se = statusentry(n, patchname)
1896 self.applied.insert(0, se)
1898 self.applied.insert(0, se)
1897
1899
1898 self.added.append(patchname)
1900 self.added.append(patchname)
1899 imported.append(patchname)
1901 imported.append(patchname)
1900 patchname = None
1902 patchname = None
1901 if rev and repo.ui.configbool('mq', 'secret', False):
1903 if rev and repo.ui.configbool('mq', 'secret', False):
1902 # if we added anything with --rev, we must move the secret root
1904 # if we added anything with --rev, we must move the secret root
1903 phases.retractboundary(repo, phases.secret, [n])
1905 phases.retractboundary(repo, phases.secret, [n])
1904 self.parseseries()
1906 self.parseseries()
1905 self.applieddirty = True
1907 self.applieddirty = True
1906 self.seriesdirty = True
1908 self.seriesdirty = True
1907
1909
1908 for i, filename in enumerate(files):
1910 for i, filename in enumerate(files):
1909 if existing:
1911 if existing:
1910 if filename == '-':
1912 if filename == '-':
1911 raise util.Abort(_('-e is incompatible with import from -'))
1913 raise util.Abort(_('-e is incompatible with import from -'))
1912 filename = normname(filename)
1914 filename = normname(filename)
1913 self.checkreservedname(filename)
1915 self.checkreservedname(filename)
1914 originpath = self.join(filename)
1916 originpath = self.join(filename)
1915 if not os.path.isfile(originpath):
1917 if not os.path.isfile(originpath):
1916 raise util.Abort(_("patch %s does not exist") % filename)
1918 raise util.Abort(_("patch %s does not exist") % filename)
1917
1919
1918 if patchname:
1920 if patchname:
1919 self.checkpatchname(patchname, force)
1921 self.checkpatchname(patchname, force)
1920
1922
1921 self.ui.write(_('renaming %s to %s\n')
1923 self.ui.write(_('renaming %s to %s\n')
1922 % (filename, patchname))
1924 % (filename, patchname))
1923 util.rename(originpath, self.join(patchname))
1925 util.rename(originpath, self.join(patchname))
1924 else:
1926 else:
1925 patchname = filename
1927 patchname = filename
1926
1928
1927 else:
1929 else:
1928 if filename == '-' and not patchname:
1930 if filename == '-' and not patchname:
1929 raise util.Abort(_('need --name to import a patch from -'))
1931 raise util.Abort(_('need --name to import a patch from -'))
1930 elif not patchname:
1932 elif not patchname:
1931 patchname = normname(os.path.basename(filename.rstrip('/')))
1933 patchname = normname(os.path.basename(filename.rstrip('/')))
1932 self.checkpatchname(patchname, force)
1934 self.checkpatchname(patchname, force)
1933 try:
1935 try:
1934 if filename == '-':
1936 if filename == '-':
1935 text = self.ui.fin.read()
1937 text = self.ui.fin.read()
1936 else:
1938 else:
1937 fp = url.open(self.ui, filename)
1939 fp = url.open(self.ui, filename)
1938 text = fp.read()
1940 text = fp.read()
1939 fp.close()
1941 fp.close()
1940 except (OSError, IOError):
1942 except (OSError, IOError):
1941 raise util.Abort(_("unable to read file %s") % filename)
1943 raise util.Abort(_("unable to read file %s") % filename)
1942 patchf = self.opener(patchname, "w")
1944 patchf = self.opener(patchname, "w")
1943 patchf.write(text)
1945 patchf.write(text)
1944 patchf.close()
1946 patchf.close()
1945 if not force:
1947 if not force:
1946 checkseries(patchname)
1948 checkseries(patchname)
1947 if patchname not in self.series:
1949 if patchname not in self.series:
1948 index = self.fullseriesend() + i
1950 index = self.fullseriesend() + i
1949 self.fullseries[index:index] = [patchname]
1951 self.fullseries[index:index] = [patchname]
1950 self.parseseries()
1952 self.parseseries()
1951 self.seriesdirty = True
1953 self.seriesdirty = True
1952 self.ui.warn(_("adding %s to series file\n") % patchname)
1954 self.ui.warn(_("adding %s to series file\n") % patchname)
1953 self.added.append(patchname)
1955 self.added.append(patchname)
1954 imported.append(patchname)
1956 imported.append(patchname)
1955 patchname = None
1957 patchname = None
1956
1958
1957 self.removeundo(repo)
1959 self.removeundo(repo)
1958 return imported
1960 return imported
1959
1961
1960 @command("qdelete|qremove|qrm",
1962 @command("qdelete|qremove|qrm",
1961 [('k', 'keep', None, _('keep patch file')),
1963 [('k', 'keep', None, _('keep patch file')),
1962 ('r', 'rev', [],
1964 ('r', 'rev', [],
1963 _('stop managing a revision (DEPRECATED)'), _('REV'))],
1965 _('stop managing a revision (DEPRECATED)'), _('REV'))],
1964 _('hg qdelete [-k] [PATCH]...'))
1966 _('hg qdelete [-k] [PATCH]...'))
1965 def delete(ui, repo, *patches, **opts):
1967 def delete(ui, repo, *patches, **opts):
1966 """remove patches from queue
1968 """remove patches from queue
1967
1969
1968 The patches must not be applied, and at least one patch is required. Exact
1970 The patches must not be applied, and at least one patch is required. Exact
1969 patch identifiers must be given. With -k/--keep, the patch files are
1971 patch identifiers must be given. With -k/--keep, the patch files are
1970 preserved in the patch directory.
1972 preserved in the patch directory.
1971
1973
1972 To stop managing a patch and move it into permanent history,
1974 To stop managing a patch and move it into permanent history,
1973 use the :hg:`qfinish` command."""
1975 use the :hg:`qfinish` command."""
1974 q = repo.mq
1976 q = repo.mq
1975 q.delete(repo, patches, opts)
1977 q.delete(repo, patches, opts)
1976 q.savedirty()
1978 q.savedirty()
1977 return 0
1979 return 0
1978
1980
1979 @command("qapplied",
1981 @command("qapplied",
1980 [('1', 'last', None, _('show only the preceding applied patch'))
1982 [('1', 'last', None, _('show only the preceding applied patch'))
1981 ] + seriesopts,
1983 ] + seriesopts,
1982 _('hg qapplied [-1] [-s] [PATCH]'))
1984 _('hg qapplied [-1] [-s] [PATCH]'))
1983 def applied(ui, repo, patch=None, **opts):
1985 def applied(ui, repo, patch=None, **opts):
1984 """print the patches already applied
1986 """print the patches already applied
1985
1987
1986 Returns 0 on success."""
1988 Returns 0 on success."""
1987
1989
1988 q = repo.mq
1990 q = repo.mq
1989
1991
1990 if patch:
1992 if patch:
1991 if patch not in q.series:
1993 if patch not in q.series:
1992 raise util.Abort(_("patch %s is not in series file") % patch)
1994 raise util.Abort(_("patch %s is not in series file") % patch)
1993 end = q.series.index(patch) + 1
1995 end = q.series.index(patch) + 1
1994 else:
1996 else:
1995 end = q.seriesend(True)
1997 end = q.seriesend(True)
1996
1998
1997 if opts.get('last') and not end:
1999 if opts.get('last') and not end:
1998 ui.write(_("no patches applied\n"))
2000 ui.write(_("no patches applied\n"))
1999 return 1
2001 return 1
2000 elif opts.get('last') and end == 1:
2002 elif opts.get('last') and end == 1:
2001 ui.write(_("only one patch applied\n"))
2003 ui.write(_("only one patch applied\n"))
2002 return 1
2004 return 1
2003 elif opts.get('last'):
2005 elif opts.get('last'):
2004 start = end - 2
2006 start = end - 2
2005 end = 1
2007 end = 1
2006 else:
2008 else:
2007 start = 0
2009 start = 0
2008
2010
2009 q.qseries(repo, length=end, start=start, status='A',
2011 q.qseries(repo, length=end, start=start, status='A',
2010 summary=opts.get('summary'))
2012 summary=opts.get('summary'))
2011
2013
2012
2014
2013 @command("qunapplied",
2015 @command("qunapplied",
2014 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2016 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2015 _('hg qunapplied [-1] [-s] [PATCH]'))
2017 _('hg qunapplied [-1] [-s] [PATCH]'))
2016 def unapplied(ui, repo, patch=None, **opts):
2018 def unapplied(ui, repo, patch=None, **opts):
2017 """print the patches not yet applied
2019 """print the patches not yet applied
2018
2020
2019 Returns 0 on success."""
2021 Returns 0 on success."""
2020
2022
2021 q = repo.mq
2023 q = repo.mq
2022 if patch:
2024 if patch:
2023 if patch not in q.series:
2025 if patch not in q.series:
2024 raise util.Abort(_("patch %s is not in series file") % patch)
2026 raise util.Abort(_("patch %s is not in series file") % patch)
2025 start = q.series.index(patch) + 1
2027 start = q.series.index(patch) + 1
2026 else:
2028 else:
2027 start = q.seriesend(True)
2029 start = q.seriesend(True)
2028
2030
2029 if start == len(q.series) and opts.get('first'):
2031 if start == len(q.series) and opts.get('first'):
2030 ui.write(_("all patches applied\n"))
2032 ui.write(_("all patches applied\n"))
2031 return 1
2033 return 1
2032
2034
2033 length = opts.get('first') and 1 or None
2035 length = opts.get('first') and 1 or None
2034 q.qseries(repo, start=start, length=length, status='U',
2036 q.qseries(repo, start=start, length=length, status='U',
2035 summary=opts.get('summary'))
2037 summary=opts.get('summary'))
2036
2038
2037 @command("qimport",
2039 @command("qimport",
2038 [('e', 'existing', None, _('import file in patch directory')),
2040 [('e', 'existing', None, _('import file in patch directory')),
2039 ('n', 'name', '',
2041 ('n', 'name', '',
2040 _('name of patch file'), _('NAME')),
2042 _('name of patch file'), _('NAME')),
2041 ('f', 'force', None, _('overwrite existing files')),
2043 ('f', 'force', None, _('overwrite existing files')),
2042 ('r', 'rev', [],
2044 ('r', 'rev', [],
2043 _('place existing revisions under mq control'), _('REV')),
2045 _('place existing revisions under mq control'), _('REV')),
2044 ('g', 'git', None, _('use git extended diff format')),
2046 ('g', 'git', None, _('use git extended diff format')),
2045 ('P', 'push', None, _('qpush after importing'))],
2047 ('P', 'push', None, _('qpush after importing'))],
2046 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...'))
2048 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...'))
2047 def qimport(ui, repo, *filename, **opts):
2049 def qimport(ui, repo, *filename, **opts):
2048 """import a patch or existing changeset
2050 """import a patch or existing changeset
2049
2051
2050 The patch is inserted into the series after the last applied
2052 The patch is inserted into the series after the last applied
2051 patch. If no patches have been applied, qimport prepends the patch
2053 patch. If no patches have been applied, qimport prepends the patch
2052 to the series.
2054 to the series.
2053
2055
2054 The patch will have the same name as its source file unless you
2056 The patch will have the same name as its source file unless you
2055 give it a new one with -n/--name.
2057 give it a new one with -n/--name.
2056
2058
2057 You can register an existing patch inside the patch directory with
2059 You can register an existing patch inside the patch directory with
2058 the -e/--existing flag.
2060 the -e/--existing flag.
2059
2061
2060 With -f/--force, an existing patch of the same name will be
2062 With -f/--force, an existing patch of the same name will be
2061 overwritten.
2063 overwritten.
2062
2064
2063 An existing changeset may be placed under mq control with -r/--rev
2065 An existing changeset may be placed under mq control with -r/--rev
2064 (e.g. qimport --rev tip -n patch will place tip under mq control).
2066 (e.g. qimport --rev tip -n patch will place tip under mq control).
2065 With -g/--git, patches imported with --rev will use the git diff
2067 With -g/--git, patches imported with --rev will use the git diff
2066 format. See the diffs help topic for information on why this is
2068 format. See the diffs help topic for information on why this is
2067 important for preserving rename/copy information and permission
2069 important for preserving rename/copy information and permission
2068 changes. Use :hg:`qfinish` to remove changesets from mq control.
2070 changes. Use :hg:`qfinish` to remove changesets from mq control.
2069
2071
2070 To import a patch from standard input, pass - as the patch file.
2072 To import a patch from standard input, pass - as the patch file.
2071 When importing from standard input, a patch name must be specified
2073 When importing from standard input, a patch name must be specified
2072 using the --name flag.
2074 using the --name flag.
2073
2075
2074 To import an existing patch while renaming it::
2076 To import an existing patch while renaming it::
2075
2077
2076 hg qimport -e existing-patch -n new-name
2078 hg qimport -e existing-patch -n new-name
2077
2079
2078 Returns 0 if import succeeded.
2080 Returns 0 if import succeeded.
2079 """
2081 """
2080 lock = repo.lock() # cause this may move phase
2082 lock = repo.lock() # cause this may move phase
2081 try:
2083 try:
2082 q = repo.mq
2084 q = repo.mq
2083 try:
2085 try:
2084 imported = q.qimport(
2086 imported = q.qimport(
2085 repo, filename, patchname=opts.get('name'),
2087 repo, filename, patchname=opts.get('name'),
2086 existing=opts.get('existing'), force=opts.get('force'),
2088 existing=opts.get('existing'), force=opts.get('force'),
2087 rev=opts.get('rev'), git=opts.get('git'))
2089 rev=opts.get('rev'), git=opts.get('git'))
2088 finally:
2090 finally:
2089 q.savedirty()
2091 q.savedirty()
2090
2092
2091
2093
2092 if imported and opts.get('push') and not opts.get('rev'):
2094 if imported and opts.get('push') and not opts.get('rev'):
2093 return q.push(repo, imported[-1])
2095 return q.push(repo, imported[-1])
2094 finally:
2096 finally:
2095 lock.release()
2097 lock.release()
2096 return 0
2098 return 0
2097
2099
2098 def qinit(ui, repo, create):
2100 def qinit(ui, repo, create):
2099 """initialize a new queue repository
2101 """initialize a new queue repository
2100
2102
2101 This command also creates a series file for ordering patches, and
2103 This command also creates a series file for ordering patches, and
2102 an mq-specific .hgignore file in the queue repository, to exclude
2104 an mq-specific .hgignore file in the queue repository, to exclude
2103 the status and guards files (these contain mostly transient state).
2105 the status and guards files (these contain mostly transient state).
2104
2106
2105 Returns 0 if initialization succeeded."""
2107 Returns 0 if initialization succeeded."""
2106 q = repo.mq
2108 q = repo.mq
2107 r = q.init(repo, create)
2109 r = q.init(repo, create)
2108 q.savedirty()
2110 q.savedirty()
2109 if r:
2111 if r:
2110 if not os.path.exists(r.wjoin('.hgignore')):
2112 if not os.path.exists(r.wjoin('.hgignore')):
2111 fp = r.wopener('.hgignore', 'w')
2113 fp = r.wopener('.hgignore', 'w')
2112 fp.write('^\\.hg\n')
2114 fp.write('^\\.hg\n')
2113 fp.write('^\\.mq\n')
2115 fp.write('^\\.mq\n')
2114 fp.write('syntax: glob\n')
2116 fp.write('syntax: glob\n')
2115 fp.write('status\n')
2117 fp.write('status\n')
2116 fp.write('guards\n')
2118 fp.write('guards\n')
2117 fp.close()
2119 fp.close()
2118 if not os.path.exists(r.wjoin('series')):
2120 if not os.path.exists(r.wjoin('series')):
2119 r.wopener('series', 'w').close()
2121 r.wopener('series', 'w').close()
2120 r[None].add(['.hgignore', 'series'])
2122 r[None].add(['.hgignore', 'series'])
2121 commands.add(ui, r)
2123 commands.add(ui, r)
2122 return 0
2124 return 0
2123
2125
2124 @command("^qinit",
2126 @command("^qinit",
2125 [('c', 'create-repo', None, _('create queue repository'))],
2127 [('c', 'create-repo', None, _('create queue repository'))],
2126 _('hg qinit [-c]'))
2128 _('hg qinit [-c]'))
2127 def init(ui, repo, **opts):
2129 def init(ui, repo, **opts):
2128 """init a new queue repository (DEPRECATED)
2130 """init a new queue repository (DEPRECATED)
2129
2131
2130 The queue repository is unversioned by default. If
2132 The queue repository is unversioned by default. If
2131 -c/--create-repo is specified, qinit will create a separate nested
2133 -c/--create-repo is specified, qinit will create a separate nested
2132 repository for patches (qinit -c may also be run later to convert
2134 repository for patches (qinit -c may also be run later to convert
2133 an unversioned patch repository into a versioned one). You can use
2135 an unversioned patch repository into a versioned one). You can use
2134 qcommit to commit changes to this queue repository.
2136 qcommit to commit changes to this queue repository.
2135
2137
2136 This command is deprecated. Without -c, it's implied by other relevant
2138 This command is deprecated. Without -c, it's implied by other relevant
2137 commands. With -c, use :hg:`init --mq` instead."""
2139 commands. With -c, use :hg:`init --mq` instead."""
2138 return qinit(ui, repo, create=opts.get('create_repo'))
2140 return qinit(ui, repo, create=opts.get('create_repo'))
2139
2141
2140 @command("qclone",
2142 @command("qclone",
2141 [('', 'pull', None, _('use pull protocol to copy metadata')),
2143 [('', 'pull', None, _('use pull protocol to copy metadata')),
2142 ('U', 'noupdate', None, _('do not update the new working directories')),
2144 ('U', 'noupdate', None, _('do not update the new working directories')),
2143 ('', 'uncompressed', None,
2145 ('', 'uncompressed', None,
2144 _('use uncompressed transfer (fast over LAN)')),
2146 _('use uncompressed transfer (fast over LAN)')),
2145 ('p', 'patches', '',
2147 ('p', 'patches', '',
2146 _('location of source patch repository'), _('REPO')),
2148 _('location of source patch repository'), _('REPO')),
2147 ] + commands.remoteopts,
2149 ] + commands.remoteopts,
2148 _('hg qclone [OPTION]... SOURCE [DEST]'))
2150 _('hg qclone [OPTION]... SOURCE [DEST]'))
2149 def clone(ui, source, dest=None, **opts):
2151 def clone(ui, source, dest=None, **opts):
2150 '''clone main and patch repository at same time
2152 '''clone main and patch repository at same time
2151
2153
2152 If source is local, destination will have no patches applied. If
2154 If source is local, destination will have no patches applied. If
2153 source is remote, this command can not check if patches are
2155 source is remote, this command can not check if patches are
2154 applied in source, so cannot guarantee that patches are not
2156 applied in source, so cannot guarantee that patches are not
2155 applied in destination. If you clone remote repository, be sure
2157 applied in destination. If you clone remote repository, be sure
2156 before that it has no patches applied.
2158 before that it has no patches applied.
2157
2159
2158 Source patch repository is looked for in <src>/.hg/patches by
2160 Source patch repository is looked for in <src>/.hg/patches by
2159 default. Use -p <url> to change.
2161 default. Use -p <url> to change.
2160
2162
2161 The patch directory must be a nested Mercurial repository, as
2163 The patch directory must be a nested Mercurial repository, as
2162 would be created by :hg:`init --mq`.
2164 would be created by :hg:`init --mq`.
2163
2165
2164 Return 0 on success.
2166 Return 0 on success.
2165 '''
2167 '''
2166 def patchdir(repo):
2168 def patchdir(repo):
2167 """compute a patch repo url from a repo object"""
2169 """compute a patch repo url from a repo object"""
2168 url = repo.url()
2170 url = repo.url()
2169 if url.endswith('/'):
2171 if url.endswith('/'):
2170 url = url[:-1]
2172 url = url[:-1]
2171 return url + '/.hg/patches'
2173 return url + '/.hg/patches'
2172
2174
2173 # main repo (destination and sources)
2175 # main repo (destination and sources)
2174 if dest is None:
2176 if dest is None:
2175 dest = hg.defaultdest(source)
2177 dest = hg.defaultdest(source)
2176 sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source))
2178 sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source))
2177
2179
2178 # patches repo (source only)
2180 # patches repo (source only)
2179 if opts.get('patches'):
2181 if opts.get('patches'):
2180 patchespath = ui.expandpath(opts.get('patches'))
2182 patchespath = ui.expandpath(opts.get('patches'))
2181 else:
2183 else:
2182 patchespath = patchdir(sr)
2184 patchespath = patchdir(sr)
2183 try:
2185 try:
2184 hg.repository(ui, patchespath)
2186 hg.repository(ui, patchespath)
2185 except error.RepoError:
2187 except error.RepoError:
2186 raise util.Abort(_('versioned patch repository not found'
2188 raise util.Abort(_('versioned patch repository not found'
2187 ' (see init --mq)'))
2189 ' (see init --mq)'))
2188 qbase, destrev = None, None
2190 qbase, destrev = None, None
2189 if sr.local():
2191 if sr.local():
2190 if sr.mq.applied and sr[qbase].phase() != phases.secret:
2192 if sr.mq.applied and sr[qbase].phase() != phases.secret:
2191 qbase = sr.mq.applied[0].node
2193 qbase = sr.mq.applied[0].node
2192 if not hg.islocal(dest):
2194 if not hg.islocal(dest):
2193 heads = set(sr.heads())
2195 heads = set(sr.heads())
2194 destrev = list(heads.difference(sr.heads(qbase)))
2196 destrev = list(heads.difference(sr.heads(qbase)))
2195 destrev.append(sr.changelog.parents(qbase)[0])
2197 destrev.append(sr.changelog.parents(qbase)[0])
2196 elif sr.capable('lookup'):
2198 elif sr.capable('lookup'):
2197 try:
2199 try:
2198 qbase = sr.lookup('qbase')
2200 qbase = sr.lookup('qbase')
2199 except error.RepoError:
2201 except error.RepoError:
2200 pass
2202 pass
2201
2203
2202 ui.note(_('cloning main repository\n'))
2204 ui.note(_('cloning main repository\n'))
2203 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2205 sr, dr = hg.clone(ui, opts, sr.url(), dest,
2204 pull=opts.get('pull'),
2206 pull=opts.get('pull'),
2205 rev=destrev,
2207 rev=destrev,
2206 update=False,
2208 update=False,
2207 stream=opts.get('uncompressed'))
2209 stream=opts.get('uncompressed'))
2208
2210
2209 ui.note(_('cloning patch repository\n'))
2211 ui.note(_('cloning patch repository\n'))
2210 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2212 hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
2211 pull=opts.get('pull'), update=not opts.get('noupdate'),
2213 pull=opts.get('pull'), update=not opts.get('noupdate'),
2212 stream=opts.get('uncompressed'))
2214 stream=opts.get('uncompressed'))
2213
2215
2214 if dr.local():
2216 if dr.local():
2215 if qbase:
2217 if qbase:
2216 ui.note(_('stripping applied patches from destination '
2218 ui.note(_('stripping applied patches from destination '
2217 'repository\n'))
2219 'repository\n'))
2218 dr.mq.strip(dr, [qbase], update=False, backup=None)
2220 dr.mq.strip(dr, [qbase], update=False, backup=None)
2219 if not opts.get('noupdate'):
2221 if not opts.get('noupdate'):
2220 ui.note(_('updating destination repository\n'))
2222 ui.note(_('updating destination repository\n'))
2221 hg.update(dr, dr.changelog.tip())
2223 hg.update(dr, dr.changelog.tip())
2222
2224
2223 @command("qcommit|qci",
2225 @command("qcommit|qci",
2224 commands.table["^commit|ci"][1],
2226 commands.table["^commit|ci"][1],
2225 _('hg qcommit [OPTION]... [FILE]...'))
2227 _('hg qcommit [OPTION]... [FILE]...'))
2226 def commit(ui, repo, *pats, **opts):
2228 def commit(ui, repo, *pats, **opts):
2227 """commit changes in the queue repository (DEPRECATED)
2229 """commit changes in the queue repository (DEPRECATED)
2228
2230
2229 This command is deprecated; use :hg:`commit --mq` instead."""
2231 This command is deprecated; use :hg:`commit --mq` instead."""
2230 q = repo.mq
2232 q = repo.mq
2231 r = q.qrepo()
2233 r = q.qrepo()
2232 if not r:
2234 if not r:
2233 raise util.Abort('no queue repository')
2235 raise util.Abort('no queue repository')
2234 commands.commit(r.ui, r, *pats, **opts)
2236 commands.commit(r.ui, r, *pats, **opts)
2235
2237
2236 @command("qseries",
2238 @command("qseries",
2237 [('m', 'missing', None, _('print patches not in series')),
2239 [('m', 'missing', None, _('print patches not in series')),
2238 ] + seriesopts,
2240 ] + seriesopts,
2239 _('hg qseries [-ms]'))
2241 _('hg qseries [-ms]'))
2240 def series(ui, repo, **opts):
2242 def series(ui, repo, **opts):
2241 """print the entire series file
2243 """print the entire series file
2242
2244
2243 Returns 0 on success."""
2245 Returns 0 on success."""
2244 repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
2246 repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
2245 return 0
2247 return 0
2246
2248
2247 @command("qtop", seriesopts, _('hg qtop [-s]'))
2249 @command("qtop", seriesopts, _('hg qtop [-s]'))
2248 def top(ui, repo, **opts):
2250 def top(ui, repo, **opts):
2249 """print the name of the current patch
2251 """print the name of the current patch
2250
2252
2251 Returns 0 on success."""
2253 Returns 0 on success."""
2252 q = repo.mq
2254 q = repo.mq
2253 t = q.applied and q.seriesend(True) or 0
2255 t = q.applied and q.seriesend(True) or 0
2254 if t:
2256 if t:
2255 q.qseries(repo, start=t - 1, length=1, status='A',
2257 q.qseries(repo, start=t - 1, length=1, status='A',
2256 summary=opts.get('summary'))
2258 summary=opts.get('summary'))
2257 else:
2259 else:
2258 ui.write(_("no patches applied\n"))
2260 ui.write(_("no patches applied\n"))
2259 return 1
2261 return 1
2260
2262
2261 @command("qnext", seriesopts, _('hg qnext [-s]'))
2263 @command("qnext", seriesopts, _('hg qnext [-s]'))
2262 def next(ui, repo, **opts):
2264 def next(ui, repo, **opts):
2263 """print the name of the next pushable patch
2265 """print the name of the next pushable patch
2264
2266
2265 Returns 0 on success."""
2267 Returns 0 on success."""
2266 q = repo.mq
2268 q = repo.mq
2267 end = q.seriesend()
2269 end = q.seriesend()
2268 if end == len(q.series):
2270 if end == len(q.series):
2269 ui.write(_("all patches applied\n"))
2271 ui.write(_("all patches applied\n"))
2270 return 1
2272 return 1
2271 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2273 q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
2272
2274
2273 @command("qprev", seriesopts, _('hg qprev [-s]'))
2275 @command("qprev", seriesopts, _('hg qprev [-s]'))
2274 def prev(ui, repo, **opts):
2276 def prev(ui, repo, **opts):
2275 """print the name of the preceding applied patch
2277 """print the name of the preceding applied patch
2276
2278
2277 Returns 0 on success."""
2279 Returns 0 on success."""
2278 q = repo.mq
2280 q = repo.mq
2279 l = len(q.applied)
2281 l = len(q.applied)
2280 if l == 1:
2282 if l == 1:
2281 ui.write(_("only one patch applied\n"))
2283 ui.write(_("only one patch applied\n"))
2282 return 1
2284 return 1
2283 if not l:
2285 if not l:
2284 ui.write(_("no patches applied\n"))
2286 ui.write(_("no patches applied\n"))
2285 return 1
2287 return 1
2286 idx = q.series.index(q.applied[-2].name)
2288 idx = q.series.index(q.applied[-2].name)
2287 q.qseries(repo, start=idx, length=1, status='A',
2289 q.qseries(repo, start=idx, length=1, status='A',
2288 summary=opts.get('summary'))
2290 summary=opts.get('summary'))
2289
2291
2290 def setupheaderopts(ui, opts):
2292 def setupheaderopts(ui, opts):
2291 if not opts.get('user') and opts.get('currentuser'):
2293 if not opts.get('user') and opts.get('currentuser'):
2292 opts['user'] = ui.username()
2294 opts['user'] = ui.username()
2293 if not opts.get('date') and opts.get('currentdate'):
2295 if not opts.get('date') and opts.get('currentdate'):
2294 opts['date'] = "%d %d" % util.makedate()
2296 opts['date'] = "%d %d" % util.makedate()
2295
2297
2296 @command("^qnew",
2298 @command("^qnew",
2297 [('e', 'edit', None, _('edit commit message')),
2299 [('e', 'edit', None, _('edit commit message')),
2298 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2300 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2299 ('g', 'git', None, _('use git extended diff format')),
2301 ('g', 'git', None, _('use git extended diff format')),
2300 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2302 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2301 ('u', 'user', '',
2303 ('u', 'user', '',
2302 _('add "From: <USER>" to patch'), _('USER')),
2304 _('add "From: <USER>" to patch'), _('USER')),
2303 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2305 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2304 ('d', 'date', '',
2306 ('d', 'date', '',
2305 _('add "Date: <DATE>" to patch'), _('DATE'))
2307 _('add "Date: <DATE>" to patch'), _('DATE'))
2306 ] + commands.walkopts + commands.commitopts,
2308 ] + commands.walkopts + commands.commitopts,
2307 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'))
2309 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'))
2308 def new(ui, repo, patch, *args, **opts):
2310 def new(ui, repo, patch, *args, **opts):
2309 """create a new patch
2311 """create a new patch
2310
2312
2311 qnew creates a new patch on top of the currently-applied patch (if
2313 qnew creates a new patch on top of the currently-applied patch (if
2312 any). The patch will be initialized with any outstanding changes
2314 any). The patch will be initialized with any outstanding changes
2313 in the working directory. You may also use -I/--include,
2315 in the working directory. You may also use -I/--include,
2314 -X/--exclude, and/or a list of files after the patch name to add
2316 -X/--exclude, and/or a list of files after the patch name to add
2315 only changes to matching files to the new patch, leaving the rest
2317 only changes to matching files to the new patch, leaving the rest
2316 as uncommitted modifications.
2318 as uncommitted modifications.
2317
2319
2318 -u/--user and -d/--date can be used to set the (given) user and
2320 -u/--user and -d/--date can be used to set the (given) user and
2319 date, respectively. -U/--currentuser and -D/--currentdate set user
2321 date, respectively. -U/--currentuser and -D/--currentdate set user
2320 to current user and date to current date.
2322 to current user and date to current date.
2321
2323
2322 -e/--edit, -m/--message or -l/--logfile set the patch header as
2324 -e/--edit, -m/--message or -l/--logfile set the patch header as
2323 well as the commit message. If none is specified, the header is
2325 well as the commit message. If none is specified, the header is
2324 empty and the commit message is '[mq]: PATCH'.
2326 empty and the commit message is '[mq]: PATCH'.
2325
2327
2326 Use the -g/--git option to keep the patch in the git extended diff
2328 Use the -g/--git option to keep the patch in the git extended diff
2327 format. Read the diffs help topic for more information on why this
2329 format. Read the diffs help topic for more information on why this
2328 is important for preserving permission changes and copy/rename
2330 is important for preserving permission changes and copy/rename
2329 information.
2331 information.
2330
2332
2331 Returns 0 on successful creation of a new patch.
2333 Returns 0 on successful creation of a new patch.
2332 """
2334 """
2333 msg = cmdutil.logmessage(ui, opts)
2335 msg = cmdutil.logmessage(ui, opts)
2334 def getmsg():
2336 def getmsg():
2335 return ui.edit(msg, opts.get('user') or ui.username())
2337 return ui.edit(msg, opts.get('user') or ui.username())
2336 q = repo.mq
2338 q = repo.mq
2337 opts['msg'] = msg
2339 opts['msg'] = msg
2338 if opts.get('edit'):
2340 if opts.get('edit'):
2339 opts['msg'] = getmsg
2341 opts['msg'] = getmsg
2340 else:
2342 else:
2341 opts['msg'] = msg
2343 opts['msg'] = msg
2342 setupheaderopts(ui, opts)
2344 setupheaderopts(ui, opts)
2343 q.new(repo, patch, *args, **opts)
2345 q.new(repo, patch, *args, **opts)
2344 q.savedirty()
2346 q.savedirty()
2345 return 0
2347 return 0
2346
2348
2347 @command("^qrefresh",
2349 @command("^qrefresh",
2348 [('e', 'edit', None, _('edit commit message')),
2350 [('e', 'edit', None, _('edit commit message')),
2349 ('g', 'git', None, _('use git extended diff format')),
2351 ('g', 'git', None, _('use git extended diff format')),
2350 ('s', 'short', None,
2352 ('s', 'short', None,
2351 _('refresh only files already in the patch and specified files')),
2353 _('refresh only files already in the patch and specified files')),
2352 ('U', 'currentuser', None,
2354 ('U', 'currentuser', None,
2353 _('add/update author field in patch with current user')),
2355 _('add/update author field in patch with current user')),
2354 ('u', 'user', '',
2356 ('u', 'user', '',
2355 _('add/update author field in patch with given user'), _('USER')),
2357 _('add/update author field in patch with given user'), _('USER')),
2356 ('D', 'currentdate', None,
2358 ('D', 'currentdate', None,
2357 _('add/update date field in patch with current date')),
2359 _('add/update date field in patch with current date')),
2358 ('d', 'date', '',
2360 ('d', 'date', '',
2359 _('add/update date field in patch with given date'), _('DATE'))
2361 _('add/update date field in patch with given date'), _('DATE'))
2360 ] + commands.walkopts + commands.commitopts,
2362 ] + commands.walkopts + commands.commitopts,
2361 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'))
2363 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'))
2362 def refresh(ui, repo, *pats, **opts):
2364 def refresh(ui, repo, *pats, **opts):
2363 """update the current patch
2365 """update the current patch
2364
2366
2365 If any file patterns are provided, the refreshed patch will
2367 If any file patterns are provided, the refreshed patch will
2366 contain only the modifications that match those patterns; the
2368 contain only the modifications that match those patterns; the
2367 remaining modifications will remain in the working directory.
2369 remaining modifications will remain in the working directory.
2368
2370
2369 If -s/--short is specified, files currently included in the patch
2371 If -s/--short is specified, files currently included in the patch
2370 will be refreshed just like matched files and remain in the patch.
2372 will be refreshed just like matched files and remain in the patch.
2371
2373
2372 If -e/--edit is specified, Mercurial will start your configured editor for
2374 If -e/--edit is specified, Mercurial will start your configured editor for
2373 you to enter a message. In case qrefresh fails, you will find a backup of
2375 you to enter a message. In case qrefresh fails, you will find a backup of
2374 your message in ``.hg/last-message.txt``.
2376 your message in ``.hg/last-message.txt``.
2375
2377
2376 hg add/remove/copy/rename work as usual, though you might want to
2378 hg add/remove/copy/rename work as usual, though you might want to
2377 use git-style patches (-g/--git or [diff] git=1) to track copies
2379 use git-style patches (-g/--git or [diff] git=1) to track copies
2378 and renames. See the diffs help topic for more information on the
2380 and renames. See the diffs help topic for more information on the
2379 git diff format.
2381 git diff format.
2380
2382
2381 Returns 0 on success.
2383 Returns 0 on success.
2382 """
2384 """
2383 q = repo.mq
2385 q = repo.mq
2384 message = cmdutil.logmessage(ui, opts)
2386 message = cmdutil.logmessage(ui, opts)
2385 if opts.get('edit'):
2387 if opts.get('edit'):
2386 if not q.applied:
2388 if not q.applied:
2387 ui.write(_("no patches applied\n"))
2389 ui.write(_("no patches applied\n"))
2388 return 1
2390 return 1
2389 if message:
2391 if message:
2390 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2392 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2391 patch = q.applied[-1].name
2393 patch = q.applied[-1].name
2392 ph = patchheader(q.join(patch), q.plainmode)
2394 ph = patchheader(q.join(patch), q.plainmode)
2393 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2395 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2394 # We don't want to lose the patch message if qrefresh fails (issue2062)
2396 # We don't want to lose the patch message if qrefresh fails (issue2062)
2395 repo.savecommitmessage(message)
2397 repo.savecommitmessage(message)
2396 setupheaderopts(ui, opts)
2398 setupheaderopts(ui, opts)
2397 wlock = repo.wlock()
2399 wlock = repo.wlock()
2398 try:
2400 try:
2399 ret = q.refresh(repo, pats, msg=message, **opts)
2401 ret = q.refresh(repo, pats, msg=message, **opts)
2400 q.savedirty()
2402 q.savedirty()
2401 return ret
2403 return ret
2402 finally:
2404 finally:
2403 wlock.release()
2405 wlock.release()
2404
2406
2405 @command("^qdiff",
2407 @command("^qdiff",
2406 commands.diffopts + commands.diffopts2 + commands.walkopts,
2408 commands.diffopts + commands.diffopts2 + commands.walkopts,
2407 _('hg qdiff [OPTION]... [FILE]...'))
2409 _('hg qdiff [OPTION]... [FILE]...'))
2408 def diff(ui, repo, *pats, **opts):
2410 def diff(ui, repo, *pats, **opts):
2409 """diff of the current patch and subsequent modifications
2411 """diff of the current patch and subsequent modifications
2410
2412
2411 Shows a diff which includes the current patch as well as any
2413 Shows a diff which includes the current patch as well as any
2412 changes which have been made in the working directory since the
2414 changes which have been made in the working directory since the
2413 last refresh (thus showing what the current patch would become
2415 last refresh (thus showing what the current patch would become
2414 after a qrefresh).
2416 after a qrefresh).
2415
2417
2416 Use :hg:`diff` if you only want to see the changes made since the
2418 Use :hg:`diff` if you only want to see the changes made since the
2417 last qrefresh, or :hg:`export qtip` if you want to see changes
2419 last qrefresh, or :hg:`export qtip` if you want to see changes
2418 made by the current patch without including changes made since the
2420 made by the current patch without including changes made since the
2419 qrefresh.
2421 qrefresh.
2420
2422
2421 Returns 0 on success.
2423 Returns 0 on success.
2422 """
2424 """
2423 repo.mq.diff(repo, pats, opts)
2425 repo.mq.diff(repo, pats, opts)
2424 return 0
2426 return 0
2425
2427
2426 @command('qfold',
2428 @command('qfold',
2427 [('e', 'edit', None, _('edit patch header')),
2429 [('e', 'edit', None, _('edit patch header')),
2428 ('k', 'keep', None, _('keep folded patch files')),
2430 ('k', 'keep', None, _('keep folded patch files')),
2429 ] + commands.commitopts,
2431 ] + commands.commitopts,
2430 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2432 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'))
2431 def fold(ui, repo, *files, **opts):
2433 def fold(ui, repo, *files, **opts):
2432 """fold the named patches into the current patch
2434 """fold the named patches into the current patch
2433
2435
2434 Patches must not yet be applied. Each patch will be successively
2436 Patches must not yet be applied. Each patch will be successively
2435 applied to the current patch in the order given. If all the
2437 applied to the current patch in the order given. If all the
2436 patches apply successfully, the current patch will be refreshed
2438 patches apply successfully, the current patch will be refreshed
2437 with the new cumulative patch, and the folded patches will be
2439 with the new cumulative patch, and the folded patches will be
2438 deleted. With -k/--keep, the folded patch files will not be
2440 deleted. With -k/--keep, the folded patch files will not be
2439 removed afterwards.
2441 removed afterwards.
2440
2442
2441 The header for each folded patch will be concatenated with the
2443 The header for each folded patch will be concatenated with the
2442 current patch header, separated by a line of ``* * *``.
2444 current patch header, separated by a line of ``* * *``.
2443
2445
2444 Returns 0 on success."""
2446 Returns 0 on success."""
2445 q = repo.mq
2447 q = repo.mq
2446 if not files:
2448 if not files:
2447 raise util.Abort(_('qfold requires at least one patch name'))
2449 raise util.Abort(_('qfold requires at least one patch name'))
2448 if not q.checktoppatch(repo)[0]:
2450 if not q.checktoppatch(repo)[0]:
2449 raise util.Abort(_('no patches applied'))
2451 raise util.Abort(_('no patches applied'))
2450 q.checklocalchanges(repo)
2452 q.checklocalchanges(repo)
2451
2453
2452 message = cmdutil.logmessage(ui, opts)
2454 message = cmdutil.logmessage(ui, opts)
2453 if opts.get('edit'):
2455 if opts.get('edit'):
2454 if message:
2456 if message:
2455 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2457 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2456
2458
2457 parent = q.lookup('qtip')
2459 parent = q.lookup('qtip')
2458 patches = []
2460 patches = []
2459 messages = []
2461 messages = []
2460 for f in files:
2462 for f in files:
2461 p = q.lookup(f)
2463 p = q.lookup(f)
2462 if p in patches or p == parent:
2464 if p in patches or p == parent:
2463 ui.warn(_('Skipping already folded patch %s\n') % p)
2465 ui.warn(_('Skipping already folded patch %s\n') % p)
2464 if q.isapplied(p):
2466 if q.isapplied(p):
2465 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2467 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2466 patches.append(p)
2468 patches.append(p)
2467
2469
2468 for p in patches:
2470 for p in patches:
2469 if not message:
2471 if not message:
2470 ph = patchheader(q.join(p), q.plainmode)
2472 ph = patchheader(q.join(p), q.plainmode)
2471 if ph.message:
2473 if ph.message:
2472 messages.append(ph.message)
2474 messages.append(ph.message)
2473 pf = q.join(p)
2475 pf = q.join(p)
2474 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2476 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2475 if not patchsuccess:
2477 if not patchsuccess:
2476 raise util.Abort(_('error folding patch %s') % p)
2478 raise util.Abort(_('error folding patch %s') % p)
2477
2479
2478 if not message:
2480 if not message:
2479 ph = patchheader(q.join(parent), q.plainmode)
2481 ph = patchheader(q.join(parent), q.plainmode)
2480 message, user = ph.message, ph.user
2482 message, user = ph.message, ph.user
2481 for msg in messages:
2483 for msg in messages:
2482 message.append('* * *')
2484 message.append('* * *')
2483 message.extend(msg)
2485 message.extend(msg)
2484 message = '\n'.join(message)
2486 message = '\n'.join(message)
2485
2487
2486 if opts.get('edit'):
2488 if opts.get('edit'):
2487 message = ui.edit(message, user or ui.username())
2489 message = ui.edit(message, user or ui.username())
2488
2490
2489 diffopts = q.patchopts(q.diffopts(), *patches)
2491 diffopts = q.patchopts(q.diffopts(), *patches)
2490 wlock = repo.wlock()
2492 wlock = repo.wlock()
2491 try:
2493 try:
2492 q.refresh(repo, msg=message, git=diffopts.git)
2494 q.refresh(repo, msg=message, git=diffopts.git)
2493 q.delete(repo, patches, opts)
2495 q.delete(repo, patches, opts)
2494 q.savedirty()
2496 q.savedirty()
2495 finally:
2497 finally:
2496 wlock.release()
2498 wlock.release()
2497
2499
2498 @command("qgoto",
2500 @command("qgoto",
2499 [('f', 'force', None, _('overwrite any local changes'))],
2501 [('f', 'force', None, _('overwrite any local changes')),
2502 ('', 'no-backup', None, _('do not save backup copies of files'))],
2500 _('hg qgoto [OPTION]... PATCH'))
2503 _('hg qgoto [OPTION]... PATCH'))
2501 def goto(ui, repo, patch, **opts):
2504 def goto(ui, repo, patch, **opts):
2502 '''push or pop patches until named patch is at top of stack
2505 '''push or pop patches until named patch is at top of stack
2503
2506
2504 Returns 0 on success.'''
2507 Returns 0 on success.'''
2505 q = repo.mq
2508 q = repo.mq
2506 patch = q.lookup(patch)
2509 patch = q.lookup(patch)
2510 nobackup = opts.get('no_backup')
2507 if q.isapplied(patch):
2511 if q.isapplied(patch):
2508 ret = q.pop(repo, patch, force=opts.get('force'))
2512 ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup)
2509 else:
2513 else:
2510 ret = q.push(repo, patch, force=opts.get('force'))
2514 ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup)
2511 q.savedirty()
2515 q.savedirty()
2512 return ret
2516 return ret
2513
2517
2514 @command("qguard",
2518 @command("qguard",
2515 [('l', 'list', None, _('list all patches and guards')),
2519 [('l', 'list', None, _('list all patches and guards')),
2516 ('n', 'none', None, _('drop all guards'))],
2520 ('n', 'none', None, _('drop all guards'))],
2517 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2521 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'))
2518 def guard(ui, repo, *args, **opts):
2522 def guard(ui, repo, *args, **opts):
2519 '''set or print guards for a patch
2523 '''set or print guards for a patch
2520
2524
2521 Guards control whether a patch can be pushed. A patch with no
2525 Guards control whether a patch can be pushed. A patch with no
2522 guards is always pushed. A patch with a positive guard ("+foo") is
2526 guards is always pushed. A patch with a positive guard ("+foo") is
2523 pushed only if the :hg:`qselect` command has activated it. A patch with
2527 pushed only if the :hg:`qselect` command has activated it. A patch with
2524 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2528 a negative guard ("-foo") is never pushed if the :hg:`qselect` command
2525 has activated it.
2529 has activated it.
2526
2530
2527 With no arguments, print the currently active guards.
2531 With no arguments, print the currently active guards.
2528 With arguments, set guards for the named patch.
2532 With arguments, set guards for the named patch.
2529
2533
2530 .. note::
2534 .. note::
2531 Specifying negative guards now requires '--'.
2535 Specifying negative guards now requires '--'.
2532
2536
2533 To set guards on another patch::
2537 To set guards on another patch::
2534
2538
2535 hg qguard other.patch -- +2.6.17 -stable
2539 hg qguard other.patch -- +2.6.17 -stable
2536
2540
2537 Returns 0 on success.
2541 Returns 0 on success.
2538 '''
2542 '''
2539 def status(idx):
2543 def status(idx):
2540 guards = q.seriesguards[idx] or ['unguarded']
2544 guards = q.seriesguards[idx] or ['unguarded']
2541 if q.series[idx] in applied:
2545 if q.series[idx] in applied:
2542 state = 'applied'
2546 state = 'applied'
2543 elif q.pushable(idx)[0]:
2547 elif q.pushable(idx)[0]:
2544 state = 'unapplied'
2548 state = 'unapplied'
2545 else:
2549 else:
2546 state = 'guarded'
2550 state = 'guarded'
2547 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2551 label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
2548 ui.write('%s: ' % ui.label(q.series[idx], label))
2552 ui.write('%s: ' % ui.label(q.series[idx], label))
2549
2553
2550 for i, guard in enumerate(guards):
2554 for i, guard in enumerate(guards):
2551 if guard.startswith('+'):
2555 if guard.startswith('+'):
2552 ui.write(guard, label='qguard.positive')
2556 ui.write(guard, label='qguard.positive')
2553 elif guard.startswith('-'):
2557 elif guard.startswith('-'):
2554 ui.write(guard, label='qguard.negative')
2558 ui.write(guard, label='qguard.negative')
2555 else:
2559 else:
2556 ui.write(guard, label='qguard.unguarded')
2560 ui.write(guard, label='qguard.unguarded')
2557 if i != len(guards) - 1:
2561 if i != len(guards) - 1:
2558 ui.write(' ')
2562 ui.write(' ')
2559 ui.write('\n')
2563 ui.write('\n')
2560 q = repo.mq
2564 q = repo.mq
2561 applied = set(p.name for p in q.applied)
2565 applied = set(p.name for p in q.applied)
2562 patch = None
2566 patch = None
2563 args = list(args)
2567 args = list(args)
2564 if opts.get('list'):
2568 if opts.get('list'):
2565 if args or opts.get('none'):
2569 if args or opts.get('none'):
2566 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2570 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2567 for i in xrange(len(q.series)):
2571 for i in xrange(len(q.series)):
2568 status(i)
2572 status(i)
2569 return
2573 return
2570 if not args or args[0][0:1] in '-+':
2574 if not args or args[0][0:1] in '-+':
2571 if not q.applied:
2575 if not q.applied:
2572 raise util.Abort(_('no patches applied'))
2576 raise util.Abort(_('no patches applied'))
2573 patch = q.applied[-1].name
2577 patch = q.applied[-1].name
2574 if patch is None and args[0][0:1] not in '-+':
2578 if patch is None and args[0][0:1] not in '-+':
2575 patch = args.pop(0)
2579 patch = args.pop(0)
2576 if patch is None:
2580 if patch is None:
2577 raise util.Abort(_('no patch to work with'))
2581 raise util.Abort(_('no patch to work with'))
2578 if args or opts.get('none'):
2582 if args or opts.get('none'):
2579 idx = q.findseries(patch)
2583 idx = q.findseries(patch)
2580 if idx is None:
2584 if idx is None:
2581 raise util.Abort(_('no patch named %s') % patch)
2585 raise util.Abort(_('no patch named %s') % patch)
2582 q.setguards(idx, args)
2586 q.setguards(idx, args)
2583 q.savedirty()
2587 q.savedirty()
2584 else:
2588 else:
2585 status(q.series.index(q.lookup(patch)))
2589 status(q.series.index(q.lookup(patch)))
2586
2590
2587 @command("qheader", [], _('hg qheader [PATCH]'))
2591 @command("qheader", [], _('hg qheader [PATCH]'))
2588 def header(ui, repo, patch=None):
2592 def header(ui, repo, patch=None):
2589 """print the header of the topmost or specified patch
2593 """print the header of the topmost or specified patch
2590
2594
2591 Returns 0 on success."""
2595 Returns 0 on success."""
2592 q = repo.mq
2596 q = repo.mq
2593
2597
2594 if patch:
2598 if patch:
2595 patch = q.lookup(patch)
2599 patch = q.lookup(patch)
2596 else:
2600 else:
2597 if not q.applied:
2601 if not q.applied:
2598 ui.write(_('no patches applied\n'))
2602 ui.write(_('no patches applied\n'))
2599 return 1
2603 return 1
2600 patch = q.lookup('qtip')
2604 patch = q.lookup('qtip')
2601 ph = patchheader(q.join(patch), q.plainmode)
2605 ph = patchheader(q.join(patch), q.plainmode)
2602
2606
2603 ui.write('\n'.join(ph.message) + '\n')
2607 ui.write('\n'.join(ph.message) + '\n')
2604
2608
2605 def lastsavename(path):
2609 def lastsavename(path):
2606 (directory, base) = os.path.split(path)
2610 (directory, base) = os.path.split(path)
2607 names = os.listdir(directory)
2611 names = os.listdir(directory)
2608 namere = re.compile("%s.([0-9]+)" % base)
2612 namere = re.compile("%s.([0-9]+)" % base)
2609 maxindex = None
2613 maxindex = None
2610 maxname = None
2614 maxname = None
2611 for f in names:
2615 for f in names:
2612 m = namere.match(f)
2616 m = namere.match(f)
2613 if m:
2617 if m:
2614 index = int(m.group(1))
2618 index = int(m.group(1))
2615 if maxindex is None or index > maxindex:
2619 if maxindex is None or index > maxindex:
2616 maxindex = index
2620 maxindex = index
2617 maxname = f
2621 maxname = f
2618 if maxname:
2622 if maxname:
2619 return (os.path.join(directory, maxname), maxindex)
2623 return (os.path.join(directory, maxname), maxindex)
2620 return (None, None)
2624 return (None, None)
2621
2625
2622 def savename(path):
2626 def savename(path):
2623 (last, index) = lastsavename(path)
2627 (last, index) = lastsavename(path)
2624 if last is None:
2628 if last is None:
2625 index = 0
2629 index = 0
2626 newpath = path + ".%d" % (index + 1)
2630 newpath = path + ".%d" % (index + 1)
2627 return newpath
2631 return newpath
2628
2632
2629 @command("^qpush",
2633 @command("^qpush",
2630 [('f', 'force', None, _('apply on top of local changes')),
2634 [('f', 'force', None, _('apply on top of local changes')),
2631 ('e', 'exact', None, _('apply the target patch to its recorded parent')),
2635 ('e', 'exact', None, _('apply the target patch to its recorded parent')),
2632 ('l', 'list', None, _('list patch name in commit text')),
2636 ('l', 'list', None, _('list patch name in commit text')),
2633 ('a', 'all', None, _('apply all patches')),
2637 ('a', 'all', None, _('apply all patches')),
2634 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2638 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2635 ('n', 'name', '',
2639 ('n', 'name', '',
2636 _('merge queue name (DEPRECATED)'), _('NAME')),
2640 _('merge queue name (DEPRECATED)'), _('NAME')),
2637 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2641 ('', 'move', None,
2642 _('reorder patch series and apply only the patch')),
2643 ('', 'no-backup', None, _('do not save backup copies of files'))],
2638 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2644 _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
2639 def push(ui, repo, patch=None, **opts):
2645 def push(ui, repo, patch=None, **opts):
2640 """push the next patch onto the stack
2646 """push the next patch onto the stack
2641
2647
2642 When -f/--force is applied, all local changes in patched files
2648 When -f/--force is applied, all local changes in patched files
2643 will be lost.
2649 will be lost.
2644
2650
2645 Return 0 on success.
2651 Return 0 on success.
2646 """
2652 """
2647 q = repo.mq
2653 q = repo.mq
2648 mergeq = None
2654 mergeq = None
2649
2655
2650 if opts.get('merge'):
2656 if opts.get('merge'):
2651 if opts.get('name'):
2657 if opts.get('name'):
2652 newpath = repo.join(opts.get('name'))
2658 newpath = repo.join(opts.get('name'))
2653 else:
2659 else:
2654 newpath, i = lastsavename(q.path)
2660 newpath, i = lastsavename(q.path)
2655 if not newpath:
2661 if not newpath:
2656 ui.warn(_("no saved queues found, please use -n\n"))
2662 ui.warn(_("no saved queues found, please use -n\n"))
2657 return 1
2663 return 1
2658 mergeq = queue(ui, repo.path, newpath)
2664 mergeq = queue(ui, repo.path, newpath)
2659 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2665 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2660 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2666 ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
2661 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2667 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
2662 exact=opts.get('exact'))
2668 exact=opts.get('exact'), nobackup=opts.get('no_backup'))
2663 return ret
2669 return ret
2664
2670
2665 @command("^qpop",
2671 @command("^qpop",
2666 [('a', 'all', None, _('pop all patches')),
2672 [('a', 'all', None, _('pop all patches')),
2667 ('n', 'name', '',
2673 ('n', 'name', '',
2668 _('queue name to pop (DEPRECATED)'), _('NAME')),
2674 _('queue name to pop (DEPRECATED)'), _('NAME')),
2669 ('f', 'force', None, _('forget any local changes to patched files'))],
2675 ('f', 'force', None, _('forget any local changes to patched files')),
2676 ('', 'no-backup', None, _('do not save backup copies of files'))],
2670 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2677 _('hg qpop [-a] [-f] [PATCH | INDEX]'))
2671 def pop(ui, repo, patch=None, **opts):
2678 def pop(ui, repo, patch=None, **opts):
2672 """pop the current patch off the stack
2679 """pop the current patch off the stack
2673
2680
2674 By default, pops off the top of the patch stack. If given a patch
2681 By default, pops off the top of the patch stack. If given a patch
2675 name, keeps popping off patches until the named patch is at the
2682 name, keeps popping off patches until the named patch is at the
2676 top of the stack.
2683 top of the stack.
2677
2684
2678 Return 0 on success.
2685 Return 0 on success.
2679 """
2686 """
2680 localupdate = True
2687 localupdate = True
2681 if opts.get('name'):
2688 if opts.get('name'):
2682 q = queue(ui, repo.path, repo.join(opts.get('name')))
2689 q = queue(ui, repo.path, repo.join(opts.get('name')))
2683 ui.warn(_('using patch queue: %s\n') % q.path)
2690 ui.warn(_('using patch queue: %s\n') % q.path)
2684 localupdate = False
2691 localupdate = False
2685 else:
2692 else:
2686 q = repo.mq
2693 q = repo.mq
2687 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2694 ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
2688 all=opts.get('all'))
2695 all=opts.get('all'), nobackup=opts.get('no_backup'))
2689 q.savedirty()
2696 q.savedirty()
2690 return ret
2697 return ret
2691
2698
2692 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2699 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'))
2693 def rename(ui, repo, patch, name=None, **opts):
2700 def rename(ui, repo, patch, name=None, **opts):
2694 """rename a patch
2701 """rename a patch
2695
2702
2696 With one argument, renames the current patch to PATCH1.
2703 With one argument, renames the current patch to PATCH1.
2697 With two arguments, renames PATCH1 to PATCH2.
2704 With two arguments, renames PATCH1 to PATCH2.
2698
2705
2699 Returns 0 on success."""
2706 Returns 0 on success."""
2700 q = repo.mq
2707 q = repo.mq
2701 if not name:
2708 if not name:
2702 name = patch
2709 name = patch
2703 patch = None
2710 patch = None
2704
2711
2705 if patch:
2712 if patch:
2706 patch = q.lookup(patch)
2713 patch = q.lookup(patch)
2707 else:
2714 else:
2708 if not q.applied:
2715 if not q.applied:
2709 ui.write(_('no patches applied\n'))
2716 ui.write(_('no patches applied\n'))
2710 return
2717 return
2711 patch = q.lookup('qtip')
2718 patch = q.lookup('qtip')
2712 absdest = q.join(name)
2719 absdest = q.join(name)
2713 if os.path.isdir(absdest):
2720 if os.path.isdir(absdest):
2714 name = normname(os.path.join(name, os.path.basename(patch)))
2721 name = normname(os.path.join(name, os.path.basename(patch)))
2715 absdest = q.join(name)
2722 absdest = q.join(name)
2716 q.checkpatchname(name)
2723 q.checkpatchname(name)
2717
2724
2718 ui.note(_('renaming %s to %s\n') % (patch, name))
2725 ui.note(_('renaming %s to %s\n') % (patch, name))
2719 i = q.findseries(patch)
2726 i = q.findseries(patch)
2720 guards = q.guard_re.findall(q.fullseries[i])
2727 guards = q.guard_re.findall(q.fullseries[i])
2721 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2728 q.fullseries[i] = name + ''.join([' #' + g for g in guards])
2722 q.parseseries()
2729 q.parseseries()
2723 q.seriesdirty = True
2730 q.seriesdirty = True
2724
2731
2725 info = q.isapplied(patch)
2732 info = q.isapplied(patch)
2726 if info:
2733 if info:
2727 q.applied[info[0]] = statusentry(info[1], name)
2734 q.applied[info[0]] = statusentry(info[1], name)
2728 q.applieddirty = True
2735 q.applieddirty = True
2729
2736
2730 destdir = os.path.dirname(absdest)
2737 destdir = os.path.dirname(absdest)
2731 if not os.path.isdir(destdir):
2738 if not os.path.isdir(destdir):
2732 os.makedirs(destdir)
2739 os.makedirs(destdir)
2733 util.rename(q.join(patch), absdest)
2740 util.rename(q.join(patch), absdest)
2734 r = q.qrepo()
2741 r = q.qrepo()
2735 if r and patch in r.dirstate:
2742 if r and patch in r.dirstate:
2736 wctx = r[None]
2743 wctx = r[None]
2737 wlock = r.wlock()
2744 wlock = r.wlock()
2738 try:
2745 try:
2739 if r.dirstate[patch] == 'a':
2746 if r.dirstate[patch] == 'a':
2740 r.dirstate.drop(patch)
2747 r.dirstate.drop(patch)
2741 r.dirstate.add(name)
2748 r.dirstate.add(name)
2742 else:
2749 else:
2743 wctx.copy(patch, name)
2750 wctx.copy(patch, name)
2744 wctx.forget([patch])
2751 wctx.forget([patch])
2745 finally:
2752 finally:
2746 wlock.release()
2753 wlock.release()
2747
2754
2748 q.savedirty()
2755 q.savedirty()
2749
2756
2750 @command("qrestore",
2757 @command("qrestore",
2751 [('d', 'delete', None, _('delete save entry')),
2758 [('d', 'delete', None, _('delete save entry')),
2752 ('u', 'update', None, _('update queue working directory'))],
2759 ('u', 'update', None, _('update queue working directory'))],
2753 _('hg qrestore [-d] [-u] REV'))
2760 _('hg qrestore [-d] [-u] REV'))
2754 def restore(ui, repo, rev, **opts):
2761 def restore(ui, repo, rev, **opts):
2755 """restore the queue state saved by a revision (DEPRECATED)
2762 """restore the queue state saved by a revision (DEPRECATED)
2756
2763
2757 This command is deprecated, use :hg:`rebase` instead."""
2764 This command is deprecated, use :hg:`rebase` instead."""
2758 rev = repo.lookup(rev)
2765 rev = repo.lookup(rev)
2759 q = repo.mq
2766 q = repo.mq
2760 q.restore(repo, rev, delete=opts.get('delete'),
2767 q.restore(repo, rev, delete=opts.get('delete'),
2761 qupdate=opts.get('update'))
2768 qupdate=opts.get('update'))
2762 q.savedirty()
2769 q.savedirty()
2763 return 0
2770 return 0
2764
2771
2765 @command("qsave",
2772 @command("qsave",
2766 [('c', 'copy', None, _('copy patch directory')),
2773 [('c', 'copy', None, _('copy patch directory')),
2767 ('n', 'name', '',
2774 ('n', 'name', '',
2768 _('copy directory name'), _('NAME')),
2775 _('copy directory name'), _('NAME')),
2769 ('e', 'empty', None, _('clear queue status file')),
2776 ('e', 'empty', None, _('clear queue status file')),
2770 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2777 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2771 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
2778 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'))
2772 def save(ui, repo, **opts):
2779 def save(ui, repo, **opts):
2773 """save current queue state (DEPRECATED)
2780 """save current queue state (DEPRECATED)
2774
2781
2775 This command is deprecated, use :hg:`rebase` instead."""
2782 This command is deprecated, use :hg:`rebase` instead."""
2776 q = repo.mq
2783 q = repo.mq
2777 message = cmdutil.logmessage(ui, opts)
2784 message = cmdutil.logmessage(ui, opts)
2778 ret = q.save(repo, msg=message)
2785 ret = q.save(repo, msg=message)
2779 if ret:
2786 if ret:
2780 return ret
2787 return ret
2781 q.savedirty() # save to .hg/patches before copying
2788 q.savedirty() # save to .hg/patches before copying
2782 if opts.get('copy'):
2789 if opts.get('copy'):
2783 path = q.path
2790 path = q.path
2784 if opts.get('name'):
2791 if opts.get('name'):
2785 newpath = os.path.join(q.basepath, opts.get('name'))
2792 newpath = os.path.join(q.basepath, opts.get('name'))
2786 if os.path.exists(newpath):
2793 if os.path.exists(newpath):
2787 if not os.path.isdir(newpath):
2794 if not os.path.isdir(newpath):
2788 raise util.Abort(_('destination %s exists and is not '
2795 raise util.Abort(_('destination %s exists and is not '
2789 'a directory') % newpath)
2796 'a directory') % newpath)
2790 if not opts.get('force'):
2797 if not opts.get('force'):
2791 raise util.Abort(_('destination %s exists, '
2798 raise util.Abort(_('destination %s exists, '
2792 'use -f to force') % newpath)
2799 'use -f to force') % newpath)
2793 else:
2800 else:
2794 newpath = savename(path)
2801 newpath = savename(path)
2795 ui.warn(_("copy %s to %s\n") % (path, newpath))
2802 ui.warn(_("copy %s to %s\n") % (path, newpath))
2796 util.copyfiles(path, newpath)
2803 util.copyfiles(path, newpath)
2797 if opts.get('empty'):
2804 if opts.get('empty'):
2798 del q.applied[:]
2805 del q.applied[:]
2799 q.applieddirty = True
2806 q.applieddirty = True
2800 q.savedirty()
2807 q.savedirty()
2801 return 0
2808 return 0
2802
2809
2803 @command("strip",
2810 @command("strip",
2804 [
2811 [
2805 ('r', 'rev', [], _('strip specified revision (optional, '
2812 ('r', 'rev', [], _('strip specified revision (optional, '
2806 'can specify revisions without this '
2813 'can specify revisions without this '
2807 'option)'), _('REV')),
2814 'option)'), _('REV')),
2808 ('f', 'force', None, _('force removal of changesets, discard '
2815 ('f', 'force', None, _('force removal of changesets, discard '
2809 'uncommitted changes (no backup)')),
2816 'uncommitted changes (no backup)')),
2810 ('b', 'backup', None, _('bundle only changesets with local revision'
2817 ('b', 'backup', None, _('bundle only changesets with local revision'
2811 ' number greater than REV which are not'
2818 ' number greater than REV which are not'
2812 ' descendants of REV (DEPRECATED)')),
2819 ' descendants of REV (DEPRECATED)')),
2813 ('', 'no-backup', None, _('no backups')),
2820 ('', 'no-backup', None, _('no backups')),
2814 ('', 'nobackup', None, _('no backups (DEPRECATED)')),
2821 ('', 'nobackup', None, _('no backups (DEPRECATED)')),
2815 ('n', '', None, _('ignored (DEPRECATED)')),
2822 ('n', '', None, _('ignored (DEPRECATED)')),
2816 ('k', 'keep', None, _("do not modify working copy during strip"))],
2823 ('k', 'keep', None, _("do not modify working copy during strip"))],
2817 _('hg strip [-k] [-f] [-n] REV...'))
2824 _('hg strip [-k] [-f] [-n] REV...'))
2818 def strip(ui, repo, *revs, **opts):
2825 def strip(ui, repo, *revs, **opts):
2819 """strip changesets and all their descendants from the repository
2826 """strip changesets and all their descendants from the repository
2820
2827
2821 The strip command removes the specified changesets and all their
2828 The strip command removes the specified changesets and all their
2822 descendants. If the working directory has uncommitted changes, the
2829 descendants. If the working directory has uncommitted changes, the
2823 operation is aborted unless the --force flag is supplied, in which
2830 operation is aborted unless the --force flag is supplied, in which
2824 case changes will be discarded.
2831 case changes will be discarded.
2825
2832
2826 If a parent of the working directory is stripped, then the working
2833 If a parent of the working directory is stripped, then the working
2827 directory will automatically be updated to the most recent
2834 directory will automatically be updated to the most recent
2828 available ancestor of the stripped parent after the operation
2835 available ancestor of the stripped parent after the operation
2829 completes.
2836 completes.
2830
2837
2831 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2838 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2832 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2839 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2833 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2840 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2834 where BUNDLE is the bundle file created by the strip. Note that
2841 where BUNDLE is the bundle file created by the strip. Note that
2835 the local revision numbers will in general be different after the
2842 the local revision numbers will in general be different after the
2836 restore.
2843 restore.
2837
2844
2838 Use the --no-backup option to discard the backup bundle once the
2845 Use the --no-backup option to discard the backup bundle once the
2839 operation completes.
2846 operation completes.
2840
2847
2841 Return 0 on success.
2848 Return 0 on success.
2842 """
2849 """
2843 backup = 'all'
2850 backup = 'all'
2844 if opts.get('backup'):
2851 if opts.get('backup'):
2845 backup = 'strip'
2852 backup = 'strip'
2846 elif opts.get('no_backup') or opts.get('nobackup'):
2853 elif opts.get('no_backup') or opts.get('nobackup'):
2847 backup = 'none'
2854 backup = 'none'
2848
2855
2849 cl = repo.changelog
2856 cl = repo.changelog
2850 revs = list(revs) + opts.get('rev')
2857 revs = list(revs) + opts.get('rev')
2851 revs = set(scmutil.revrange(repo, revs))
2858 revs = set(scmutil.revrange(repo, revs))
2852 if not revs:
2859 if not revs:
2853 raise util.Abort(_('empty revision set'))
2860 raise util.Abort(_('empty revision set'))
2854
2861
2855 descendants = set(cl.descendants(*revs))
2862 descendants = set(cl.descendants(*revs))
2856 strippedrevs = revs.union(descendants)
2863 strippedrevs = revs.union(descendants)
2857 roots = revs.difference(descendants)
2864 roots = revs.difference(descendants)
2858
2865
2859 update = False
2866 update = False
2860 # if one of the wdir parent is stripped we'll need
2867 # if one of the wdir parent is stripped we'll need
2861 # to update away to an earlier revision
2868 # to update away to an earlier revision
2862 for p in repo.dirstate.parents():
2869 for p in repo.dirstate.parents():
2863 if p != nullid and cl.rev(p) in strippedrevs:
2870 if p != nullid and cl.rev(p) in strippedrevs:
2864 update = True
2871 update = True
2865 break
2872 break
2866
2873
2867 rootnodes = set(cl.node(r) for r in roots)
2874 rootnodes = set(cl.node(r) for r in roots)
2868
2875
2869 q = repo.mq
2876 q = repo.mq
2870 if q.applied:
2877 if q.applied:
2871 # refresh queue state if we're about to strip
2878 # refresh queue state if we're about to strip
2872 # applied patches
2879 # applied patches
2873 if cl.rev(repo.lookup('qtip')) in strippedrevs:
2880 if cl.rev(repo.lookup('qtip')) in strippedrevs:
2874 q.applieddirty = True
2881 q.applieddirty = True
2875 start = 0
2882 start = 0
2876 end = len(q.applied)
2883 end = len(q.applied)
2877 for i, statusentry in enumerate(q.applied):
2884 for i, statusentry in enumerate(q.applied):
2878 if statusentry.node in rootnodes:
2885 if statusentry.node in rootnodes:
2879 # if one of the stripped roots is an applied
2886 # if one of the stripped roots is an applied
2880 # patch, only part of the queue is stripped
2887 # patch, only part of the queue is stripped
2881 start = i
2888 start = i
2882 break
2889 break
2883 del q.applied[start:end]
2890 del q.applied[start:end]
2884 q.savedirty()
2891 q.savedirty()
2885
2892
2886 revs = list(rootnodes)
2893 revs = list(rootnodes)
2887 if update and opts.get('keep'):
2894 if update and opts.get('keep'):
2888 wlock = repo.wlock()
2895 wlock = repo.wlock()
2889 try:
2896 try:
2890 urev = repo.mq.qparents(repo, revs[0])
2897 urev = repo.mq.qparents(repo, revs[0])
2891 repo.dirstate.rebuild(urev, repo[urev].manifest())
2898 repo.dirstate.rebuild(urev, repo[urev].manifest())
2892 repo.dirstate.write()
2899 repo.dirstate.write()
2893 update = False
2900 update = False
2894 finally:
2901 finally:
2895 wlock.release()
2902 wlock.release()
2896
2903
2897 repo.mq.strip(repo, revs, backup=backup, update=update,
2904 repo.mq.strip(repo, revs, backup=backup, update=update,
2898 force=opts.get('force'))
2905 force=opts.get('force'))
2899 return 0
2906 return 0
2900
2907
2901 @command("qselect",
2908 @command("qselect",
2902 [('n', 'none', None, _('disable all guards')),
2909 [('n', 'none', None, _('disable all guards')),
2903 ('s', 'series', None, _('list all guards in series file')),
2910 ('s', 'series', None, _('list all guards in series file')),
2904 ('', 'pop', None, _('pop to before first guarded applied patch')),
2911 ('', 'pop', None, _('pop to before first guarded applied patch')),
2905 ('', 'reapply', None, _('pop, then reapply patches'))],
2912 ('', 'reapply', None, _('pop, then reapply patches'))],
2906 _('hg qselect [OPTION]... [GUARD]...'))
2913 _('hg qselect [OPTION]... [GUARD]...'))
2907 def select(ui, repo, *args, **opts):
2914 def select(ui, repo, *args, **opts):
2908 '''set or print guarded patches to push
2915 '''set or print guarded patches to push
2909
2916
2910 Use the :hg:`qguard` command to set or print guards on patch, then use
2917 Use the :hg:`qguard` command to set or print guards on patch, then use
2911 qselect to tell mq which guards to use. A patch will be pushed if
2918 qselect to tell mq which guards to use. A patch will be pushed if
2912 it has no guards or any positive guards match the currently
2919 it has no guards or any positive guards match the currently
2913 selected guard, but will not be pushed if any negative guards
2920 selected guard, but will not be pushed if any negative guards
2914 match the current guard. For example::
2921 match the current guard. For example::
2915
2922
2916 qguard foo.patch -- -stable (negative guard)
2923 qguard foo.patch -- -stable (negative guard)
2917 qguard bar.patch +stable (positive guard)
2924 qguard bar.patch +stable (positive guard)
2918 qselect stable
2925 qselect stable
2919
2926
2920 This activates the "stable" guard. mq will skip foo.patch (because
2927 This activates the "stable" guard. mq will skip foo.patch (because
2921 it has a negative match) but push bar.patch (because it has a
2928 it has a negative match) but push bar.patch (because it has a
2922 positive match).
2929 positive match).
2923
2930
2924 With no arguments, prints the currently active guards.
2931 With no arguments, prints the currently active guards.
2925 With one argument, sets the active guard.
2932 With one argument, sets the active guard.
2926
2933
2927 Use -n/--none to deactivate guards (no other arguments needed).
2934 Use -n/--none to deactivate guards (no other arguments needed).
2928 When no guards are active, patches with positive guards are
2935 When no guards are active, patches with positive guards are
2929 skipped and patches with negative guards are pushed.
2936 skipped and patches with negative guards are pushed.
2930
2937
2931 qselect can change the guards on applied patches. It does not pop
2938 qselect can change the guards on applied patches. It does not pop
2932 guarded patches by default. Use --pop to pop back to the last
2939 guarded patches by default. Use --pop to pop back to the last
2933 applied patch that is not guarded. Use --reapply (which implies
2940 applied patch that is not guarded. Use --reapply (which implies
2934 --pop) to push back to the current patch afterwards, but skip
2941 --pop) to push back to the current patch afterwards, but skip
2935 guarded patches.
2942 guarded patches.
2936
2943
2937 Use -s/--series to print a list of all guards in the series file
2944 Use -s/--series to print a list of all guards in the series file
2938 (no other arguments needed). Use -v for more information.
2945 (no other arguments needed). Use -v for more information.
2939
2946
2940 Returns 0 on success.'''
2947 Returns 0 on success.'''
2941
2948
2942 q = repo.mq
2949 q = repo.mq
2943 guards = q.active()
2950 guards = q.active()
2944 if args or opts.get('none'):
2951 if args or opts.get('none'):
2945 old_unapplied = q.unapplied(repo)
2952 old_unapplied = q.unapplied(repo)
2946 old_guarded = [i for i in xrange(len(q.applied)) if
2953 old_guarded = [i for i in xrange(len(q.applied)) if
2947 not q.pushable(i)[0]]
2954 not q.pushable(i)[0]]
2948 q.setactive(args)
2955 q.setactive(args)
2949 q.savedirty()
2956 q.savedirty()
2950 if not args:
2957 if not args:
2951 ui.status(_('guards deactivated\n'))
2958 ui.status(_('guards deactivated\n'))
2952 if not opts.get('pop') and not opts.get('reapply'):
2959 if not opts.get('pop') and not opts.get('reapply'):
2953 unapplied = q.unapplied(repo)
2960 unapplied = q.unapplied(repo)
2954 guarded = [i for i in xrange(len(q.applied))
2961 guarded = [i for i in xrange(len(q.applied))
2955 if not q.pushable(i)[0]]
2962 if not q.pushable(i)[0]]
2956 if len(unapplied) != len(old_unapplied):
2963 if len(unapplied) != len(old_unapplied):
2957 ui.status(_('number of unguarded, unapplied patches has '
2964 ui.status(_('number of unguarded, unapplied patches has '
2958 'changed from %d to %d\n') %
2965 'changed from %d to %d\n') %
2959 (len(old_unapplied), len(unapplied)))
2966 (len(old_unapplied), len(unapplied)))
2960 if len(guarded) != len(old_guarded):
2967 if len(guarded) != len(old_guarded):
2961 ui.status(_('number of guarded, applied patches has changed '
2968 ui.status(_('number of guarded, applied patches has changed '
2962 'from %d to %d\n') %
2969 'from %d to %d\n') %
2963 (len(old_guarded), len(guarded)))
2970 (len(old_guarded), len(guarded)))
2964 elif opts.get('series'):
2971 elif opts.get('series'):
2965 guards = {}
2972 guards = {}
2966 noguards = 0
2973 noguards = 0
2967 for gs in q.seriesguards:
2974 for gs in q.seriesguards:
2968 if not gs:
2975 if not gs:
2969 noguards += 1
2976 noguards += 1
2970 for g in gs:
2977 for g in gs:
2971 guards.setdefault(g, 0)
2978 guards.setdefault(g, 0)
2972 guards[g] += 1
2979 guards[g] += 1
2973 if ui.verbose:
2980 if ui.verbose:
2974 guards['NONE'] = noguards
2981 guards['NONE'] = noguards
2975 guards = guards.items()
2982 guards = guards.items()
2976 guards.sort(key=lambda x: x[0][1:])
2983 guards.sort(key=lambda x: x[0][1:])
2977 if guards:
2984 if guards:
2978 ui.note(_('guards in series file:\n'))
2985 ui.note(_('guards in series file:\n'))
2979 for guard, count in guards:
2986 for guard, count in guards:
2980 ui.note('%2d ' % count)
2987 ui.note('%2d ' % count)
2981 ui.write(guard, '\n')
2988 ui.write(guard, '\n')
2982 else:
2989 else:
2983 ui.note(_('no guards in series file\n'))
2990 ui.note(_('no guards in series file\n'))
2984 else:
2991 else:
2985 if guards:
2992 if guards:
2986 ui.note(_('active guards:\n'))
2993 ui.note(_('active guards:\n'))
2987 for g in guards:
2994 for g in guards:
2988 ui.write(g, '\n')
2995 ui.write(g, '\n')
2989 else:
2996 else:
2990 ui.write(_('no active guards\n'))
2997 ui.write(_('no active guards\n'))
2991 reapply = opts.get('reapply') and q.applied and q.appliedname(-1)
2998 reapply = opts.get('reapply') and q.applied and q.appliedname(-1)
2992 popped = False
2999 popped = False
2993 if opts.get('pop') or opts.get('reapply'):
3000 if opts.get('pop') or opts.get('reapply'):
2994 for i in xrange(len(q.applied)):
3001 for i in xrange(len(q.applied)):
2995 pushable, reason = q.pushable(i)
3002 pushable, reason = q.pushable(i)
2996 if not pushable:
3003 if not pushable:
2997 ui.status(_('popping guarded patches\n'))
3004 ui.status(_('popping guarded patches\n'))
2998 popped = True
3005 popped = True
2999 if i == 0:
3006 if i == 0:
3000 q.pop(repo, all=True)
3007 q.pop(repo, all=True)
3001 else:
3008 else:
3002 q.pop(repo, str(i - 1))
3009 q.pop(repo, str(i - 1))
3003 break
3010 break
3004 if popped:
3011 if popped:
3005 try:
3012 try:
3006 if reapply:
3013 if reapply:
3007 ui.status(_('reapplying unguarded patches\n'))
3014 ui.status(_('reapplying unguarded patches\n'))
3008 q.push(repo, reapply)
3015 q.push(repo, reapply)
3009 finally:
3016 finally:
3010 q.savedirty()
3017 q.savedirty()
3011
3018
3012 @command("qfinish",
3019 @command("qfinish",
3013 [('a', 'applied', None, _('finish all applied changesets'))],
3020 [('a', 'applied', None, _('finish all applied changesets'))],
3014 _('hg qfinish [-a] [REV]...'))
3021 _('hg qfinish [-a] [REV]...'))
3015 def finish(ui, repo, *revrange, **opts):
3022 def finish(ui, repo, *revrange, **opts):
3016 """move applied patches into repository history
3023 """move applied patches into repository history
3017
3024
3018 Finishes the specified revisions (corresponding to applied
3025 Finishes the specified revisions (corresponding to applied
3019 patches) by moving them out of mq control into regular repository
3026 patches) by moving them out of mq control into regular repository
3020 history.
3027 history.
3021
3028
3022 Accepts a revision range or the -a/--applied option. If --applied
3029 Accepts a revision range or the -a/--applied option. If --applied
3023 is specified, all applied mq revisions are removed from mq
3030 is specified, all applied mq revisions are removed from mq
3024 control. Otherwise, the given revisions must be at the base of the
3031 control. Otherwise, the given revisions must be at the base of the
3025 stack of applied patches.
3032 stack of applied patches.
3026
3033
3027 This can be especially useful if your changes have been applied to
3034 This can be especially useful if your changes have been applied to
3028 an upstream repository, or if you are about to push your changes
3035 an upstream repository, or if you are about to push your changes
3029 to upstream.
3036 to upstream.
3030
3037
3031 Returns 0 on success.
3038 Returns 0 on success.
3032 """
3039 """
3033 if not opts.get('applied') and not revrange:
3040 if not opts.get('applied') and not revrange:
3034 raise util.Abort(_('no revisions specified'))
3041 raise util.Abort(_('no revisions specified'))
3035 elif opts.get('applied'):
3042 elif opts.get('applied'):
3036 revrange = ('qbase::qtip',) + revrange
3043 revrange = ('qbase::qtip',) + revrange
3037
3044
3038 q = repo.mq
3045 q = repo.mq
3039 if not q.applied:
3046 if not q.applied:
3040 ui.status(_('no patches applied\n'))
3047 ui.status(_('no patches applied\n'))
3041 return 0
3048 return 0
3042
3049
3043 revs = scmutil.revrange(repo, revrange)
3050 revs = scmutil.revrange(repo, revrange)
3044 if repo['.'].rev() in revs and repo[None].files():
3051 if repo['.'].rev() in revs and repo[None].files():
3045 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3052 ui.warn(_('warning: uncommitted changes in the working directory\n'))
3046 # queue.finish may changes phases but leave the responsability to lock the
3053 # queue.finish may changes phases but leave the responsability to lock the
3047 # repo to the caller to avoid deadlock with wlock. This command code is
3054 # repo to the caller to avoid deadlock with wlock. This command code is
3048 # responsability for this locking.
3055 # responsability for this locking.
3049 lock = repo.lock()
3056 lock = repo.lock()
3050 try:
3057 try:
3051 q.finish(repo, revs)
3058 q.finish(repo, revs)
3052 q.savedirty()
3059 q.savedirty()
3053 finally:
3060 finally:
3054 lock.release()
3061 lock.release()
3055 return 0
3062 return 0
3056
3063
3057 @command("qqueue",
3064 @command("qqueue",
3058 [('l', 'list', False, _('list all available queues')),
3065 [('l', 'list', False, _('list all available queues')),
3059 ('', 'active', False, _('print name of active queue')),
3066 ('', 'active', False, _('print name of active queue')),
3060 ('c', 'create', False, _('create new queue')),
3067 ('c', 'create', False, _('create new queue')),
3061 ('', 'rename', False, _('rename active queue')),
3068 ('', 'rename', False, _('rename active queue')),
3062 ('', 'delete', False, _('delete reference to queue')),
3069 ('', 'delete', False, _('delete reference to queue')),
3063 ('', 'purge', False, _('delete queue, and remove patch dir')),
3070 ('', 'purge', False, _('delete queue, and remove patch dir')),
3064 ],
3071 ],
3065 _('[OPTION] [QUEUE]'))
3072 _('[OPTION] [QUEUE]'))
3066 def qqueue(ui, repo, name=None, **opts):
3073 def qqueue(ui, repo, name=None, **opts):
3067 '''manage multiple patch queues
3074 '''manage multiple patch queues
3068
3075
3069 Supports switching between different patch queues, as well as creating
3076 Supports switching between different patch queues, as well as creating
3070 new patch queues and deleting existing ones.
3077 new patch queues and deleting existing ones.
3071
3078
3072 Omitting a queue name or specifying -l/--list will show you the registered
3079 Omitting a queue name or specifying -l/--list will show you the registered
3073 queues - by default the "normal" patches queue is registered. The currently
3080 queues - by default the "normal" patches queue is registered. The currently
3074 active queue will be marked with "(active)". Specifying --active will print
3081 active queue will be marked with "(active)". Specifying --active will print
3075 only the name of the active queue.
3082 only the name of the active queue.
3076
3083
3077 To create a new queue, use -c/--create. The queue is automatically made
3084 To create a new queue, use -c/--create. The queue is automatically made
3078 active, except in the case where there are applied patches from the
3085 active, except in the case where there are applied patches from the
3079 currently active queue in the repository. Then the queue will only be
3086 currently active queue in the repository. Then the queue will only be
3080 created and switching will fail.
3087 created and switching will fail.
3081
3088
3082 To delete an existing queue, use --delete. You cannot delete the currently
3089 To delete an existing queue, use --delete. You cannot delete the currently
3083 active queue.
3090 active queue.
3084
3091
3085 Returns 0 on success.
3092 Returns 0 on success.
3086 '''
3093 '''
3087 q = repo.mq
3094 q = repo.mq
3088 _defaultqueue = 'patches'
3095 _defaultqueue = 'patches'
3089 _allqueues = 'patches.queues'
3096 _allqueues = 'patches.queues'
3090 _activequeue = 'patches.queue'
3097 _activequeue = 'patches.queue'
3091
3098
3092 def _getcurrent():
3099 def _getcurrent():
3093 cur = os.path.basename(q.path)
3100 cur = os.path.basename(q.path)
3094 if cur.startswith('patches-'):
3101 if cur.startswith('patches-'):
3095 cur = cur[8:]
3102 cur = cur[8:]
3096 return cur
3103 return cur
3097
3104
3098 def _noqueues():
3105 def _noqueues():
3099 try:
3106 try:
3100 fh = repo.opener(_allqueues, 'r')
3107 fh = repo.opener(_allqueues, 'r')
3101 fh.close()
3108 fh.close()
3102 except IOError:
3109 except IOError:
3103 return True
3110 return True
3104
3111
3105 return False
3112 return False
3106
3113
3107 def _getqueues():
3114 def _getqueues():
3108 current = _getcurrent()
3115 current = _getcurrent()
3109
3116
3110 try:
3117 try:
3111 fh = repo.opener(_allqueues, 'r')
3118 fh = repo.opener(_allqueues, 'r')
3112 queues = [queue.strip() for queue in fh if queue.strip()]
3119 queues = [queue.strip() for queue in fh if queue.strip()]
3113 fh.close()
3120 fh.close()
3114 if current not in queues:
3121 if current not in queues:
3115 queues.append(current)
3122 queues.append(current)
3116 except IOError:
3123 except IOError:
3117 queues = [_defaultqueue]
3124 queues = [_defaultqueue]
3118
3125
3119 return sorted(queues)
3126 return sorted(queues)
3120
3127
3121 def _setactive(name):
3128 def _setactive(name):
3122 if q.applied:
3129 if q.applied:
3123 raise util.Abort(_('patches applied - cannot set new queue active'))
3130 raise util.Abort(_('patches applied - cannot set new queue active'))
3124 _setactivenocheck(name)
3131 _setactivenocheck(name)
3125
3132
3126 def _setactivenocheck(name):
3133 def _setactivenocheck(name):
3127 fh = repo.opener(_activequeue, 'w')
3134 fh = repo.opener(_activequeue, 'w')
3128 if name != 'patches':
3135 if name != 'patches':
3129 fh.write(name)
3136 fh.write(name)
3130 fh.close()
3137 fh.close()
3131
3138
3132 def _addqueue(name):
3139 def _addqueue(name):
3133 fh = repo.opener(_allqueues, 'a')
3140 fh = repo.opener(_allqueues, 'a')
3134 fh.write('%s\n' % (name,))
3141 fh.write('%s\n' % (name,))
3135 fh.close()
3142 fh.close()
3136
3143
3137 def _queuedir(name):
3144 def _queuedir(name):
3138 if name == 'patches':
3145 if name == 'patches':
3139 return repo.join('patches')
3146 return repo.join('patches')
3140 else:
3147 else:
3141 return repo.join('patches-' + name)
3148 return repo.join('patches-' + name)
3142
3149
3143 def _validname(name):
3150 def _validname(name):
3144 for n in name:
3151 for n in name:
3145 if n in ':\\/.':
3152 if n in ':\\/.':
3146 return False
3153 return False
3147 return True
3154 return True
3148
3155
3149 def _delete(name):
3156 def _delete(name):
3150 if name not in existing:
3157 if name not in existing:
3151 raise util.Abort(_('cannot delete queue that does not exist'))
3158 raise util.Abort(_('cannot delete queue that does not exist'))
3152
3159
3153 current = _getcurrent()
3160 current = _getcurrent()
3154
3161
3155 if name == current:
3162 if name == current:
3156 raise util.Abort(_('cannot delete currently active queue'))
3163 raise util.Abort(_('cannot delete currently active queue'))
3157
3164
3158 fh = repo.opener('patches.queues.new', 'w')
3165 fh = repo.opener('patches.queues.new', 'w')
3159 for queue in existing:
3166 for queue in existing:
3160 if queue == name:
3167 if queue == name:
3161 continue
3168 continue
3162 fh.write('%s\n' % (queue,))
3169 fh.write('%s\n' % (queue,))
3163 fh.close()
3170 fh.close()
3164 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3171 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3165
3172
3166 if not name or opts.get('list') or opts.get('active'):
3173 if not name or opts.get('list') or opts.get('active'):
3167 current = _getcurrent()
3174 current = _getcurrent()
3168 if opts.get('active'):
3175 if opts.get('active'):
3169 ui.write('%s\n' % (current,))
3176 ui.write('%s\n' % (current,))
3170 return
3177 return
3171 for queue in _getqueues():
3178 for queue in _getqueues():
3172 ui.write('%s' % (queue,))
3179 ui.write('%s' % (queue,))
3173 if queue == current and not ui.quiet:
3180 if queue == current and not ui.quiet:
3174 ui.write(_(' (active)\n'))
3181 ui.write(_(' (active)\n'))
3175 else:
3182 else:
3176 ui.write('\n')
3183 ui.write('\n')
3177 return
3184 return
3178
3185
3179 if not _validname(name):
3186 if not _validname(name):
3180 raise util.Abort(
3187 raise util.Abort(
3181 _('invalid queue name, may not contain the characters ":\\/."'))
3188 _('invalid queue name, may not contain the characters ":\\/."'))
3182
3189
3183 existing = _getqueues()
3190 existing = _getqueues()
3184
3191
3185 if opts.get('create'):
3192 if opts.get('create'):
3186 if name in existing:
3193 if name in existing:
3187 raise util.Abort(_('queue "%s" already exists') % name)
3194 raise util.Abort(_('queue "%s" already exists') % name)
3188 if _noqueues():
3195 if _noqueues():
3189 _addqueue(_defaultqueue)
3196 _addqueue(_defaultqueue)
3190 _addqueue(name)
3197 _addqueue(name)
3191 _setactive(name)
3198 _setactive(name)
3192 elif opts.get('rename'):
3199 elif opts.get('rename'):
3193 current = _getcurrent()
3200 current = _getcurrent()
3194 if name == current:
3201 if name == current:
3195 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3202 raise util.Abort(_('can\'t rename "%s" to its current name') % name)
3196 if name in existing:
3203 if name in existing:
3197 raise util.Abort(_('queue "%s" already exists') % name)
3204 raise util.Abort(_('queue "%s" already exists') % name)
3198
3205
3199 olddir = _queuedir(current)
3206 olddir = _queuedir(current)
3200 newdir = _queuedir(name)
3207 newdir = _queuedir(name)
3201
3208
3202 if os.path.exists(newdir):
3209 if os.path.exists(newdir):
3203 raise util.Abort(_('non-queue directory "%s" already exists') %
3210 raise util.Abort(_('non-queue directory "%s" already exists') %
3204 newdir)
3211 newdir)
3205
3212
3206 fh = repo.opener('patches.queues.new', 'w')
3213 fh = repo.opener('patches.queues.new', 'w')
3207 for queue in existing:
3214 for queue in existing:
3208 if queue == current:
3215 if queue == current:
3209 fh.write('%s\n' % (name,))
3216 fh.write('%s\n' % (name,))
3210 if os.path.exists(olddir):
3217 if os.path.exists(olddir):
3211 util.rename(olddir, newdir)
3218 util.rename(olddir, newdir)
3212 else:
3219 else:
3213 fh.write('%s\n' % (queue,))
3220 fh.write('%s\n' % (queue,))
3214 fh.close()
3221 fh.close()
3215 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3222 util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
3216 _setactivenocheck(name)
3223 _setactivenocheck(name)
3217 elif opts.get('delete'):
3224 elif opts.get('delete'):
3218 _delete(name)
3225 _delete(name)
3219 elif opts.get('purge'):
3226 elif opts.get('purge'):
3220 if name in existing:
3227 if name in existing:
3221 _delete(name)
3228 _delete(name)
3222 qdir = _queuedir(name)
3229 qdir = _queuedir(name)
3223 if os.path.exists(qdir):
3230 if os.path.exists(qdir):
3224 shutil.rmtree(qdir)
3231 shutil.rmtree(qdir)
3225 else:
3232 else:
3226 if name not in existing:
3233 if name not in existing:
3227 raise util.Abort(_('use --create to create a new queue'))
3234 raise util.Abort(_('use --create to create a new queue'))
3228 _setactive(name)
3235 _setactive(name)
3229
3236
3230 def mqphasedefaults(repo, roots):
3237 def mqphasedefaults(repo, roots):
3231 """callback used to set mq changeset as secret when no phase data exists"""
3238 """callback used to set mq changeset as secret when no phase data exists"""
3232 if repo.mq.applied:
3239 if repo.mq.applied:
3233 if repo.ui.configbool('mq', 'secret', False):
3240 if repo.ui.configbool('mq', 'secret', False):
3234 mqphase = phases.secret
3241 mqphase = phases.secret
3235 else:
3242 else:
3236 mqphase = phases.draft
3243 mqphase = phases.draft
3237 qbase = repo[repo.mq.applied[0].node]
3244 qbase = repo[repo.mq.applied[0].node]
3238 roots[mqphase].add(qbase.node())
3245 roots[mqphase].add(qbase.node())
3239 return roots
3246 return roots
3240
3247
3241 def reposetup(ui, repo):
3248 def reposetup(ui, repo):
3242 class mqrepo(repo.__class__):
3249 class mqrepo(repo.__class__):
3243 @util.propertycache
3250 @util.propertycache
3244 def mq(self):
3251 def mq(self):
3245 return queue(self.ui, self.path)
3252 return queue(self.ui, self.path)
3246
3253
3247 def abortifwdirpatched(self, errmsg, force=False):
3254 def abortifwdirpatched(self, errmsg, force=False):
3248 if self.mq.applied and not force:
3255 if self.mq.applied and not force:
3249 parents = self.dirstate.parents()
3256 parents = self.dirstate.parents()
3250 patches = [s.node for s in self.mq.applied]
3257 patches = [s.node for s in self.mq.applied]
3251 if parents[0] in patches or parents[1] in patches:
3258 if parents[0] in patches or parents[1] in patches:
3252 raise util.Abort(errmsg)
3259 raise util.Abort(errmsg)
3253
3260
3254 def commit(self, text="", user=None, date=None, match=None,
3261 def commit(self, text="", user=None, date=None, match=None,
3255 force=False, editor=False, extra={}):
3262 force=False, editor=False, extra={}):
3256 self.abortifwdirpatched(
3263 self.abortifwdirpatched(
3257 _('cannot commit over an applied mq patch'),
3264 _('cannot commit over an applied mq patch'),
3258 force)
3265 force)
3259
3266
3260 return super(mqrepo, self).commit(text, user, date, match, force,
3267 return super(mqrepo, self).commit(text, user, date, match, force,
3261 editor, extra)
3268 editor, extra)
3262
3269
3263 def checkpush(self, force, revs):
3270 def checkpush(self, force, revs):
3264 if self.mq.applied and not force:
3271 if self.mq.applied and not force:
3265 outapplied = [e.node for e in self.mq.applied]
3272 outapplied = [e.node for e in self.mq.applied]
3266 if revs:
3273 if revs:
3267 # Assume applied patches have no non-patch descendants and
3274 # Assume applied patches have no non-patch descendants and
3268 # are not on remote already. Filtering any changeset not
3275 # are not on remote already. Filtering any changeset not
3269 # pushed.
3276 # pushed.
3270 heads = set(revs)
3277 heads = set(revs)
3271 for node in reversed(outapplied):
3278 for node in reversed(outapplied):
3272 if node in heads:
3279 if node in heads:
3273 break
3280 break
3274 else:
3281 else:
3275 outapplied.pop()
3282 outapplied.pop()
3276 # looking for pushed and shared changeset
3283 # looking for pushed and shared changeset
3277 for node in outapplied:
3284 for node in outapplied:
3278 if repo[node].phase() < phases.secret:
3285 if repo[node].phase() < phases.secret:
3279 raise util.Abort(_('source has mq patches applied'))
3286 raise util.Abort(_('source has mq patches applied'))
3280 # no non-secret patches pushed
3287 # no non-secret patches pushed
3281 super(mqrepo, self).checkpush(force, revs)
3288 super(mqrepo, self).checkpush(force, revs)
3282
3289
3283 def _findtags(self):
3290 def _findtags(self):
3284 '''augment tags from base class with patch tags'''
3291 '''augment tags from base class with patch tags'''
3285 result = super(mqrepo, self)._findtags()
3292 result = super(mqrepo, self)._findtags()
3286
3293
3287 q = self.mq
3294 q = self.mq
3288 if not q.applied:
3295 if not q.applied:
3289 return result
3296 return result
3290
3297
3291 mqtags = [(patch.node, patch.name) for patch in q.applied]
3298 mqtags = [(patch.node, patch.name) for patch in q.applied]
3292
3299
3293 try:
3300 try:
3294 self.changelog.rev(mqtags[-1][0])
3301 self.changelog.rev(mqtags[-1][0])
3295 except error.LookupError:
3302 except error.LookupError:
3296 self.ui.warn(_('mq status file refers to unknown node %s\n')
3303 self.ui.warn(_('mq status file refers to unknown node %s\n')
3297 % short(mqtags[-1][0]))
3304 % short(mqtags[-1][0]))
3298 return result
3305 return result
3299
3306
3300 mqtags.append((mqtags[-1][0], 'qtip'))
3307 mqtags.append((mqtags[-1][0], 'qtip'))
3301 mqtags.append((mqtags[0][0], 'qbase'))
3308 mqtags.append((mqtags[0][0], 'qbase'))
3302 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3309 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
3303 tags = result[0]
3310 tags = result[0]
3304 for patch in mqtags:
3311 for patch in mqtags:
3305 if patch[1] in tags:
3312 if patch[1] in tags:
3306 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
3313 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
3307 % patch[1])
3314 % patch[1])
3308 else:
3315 else:
3309 tags[patch[1]] = patch[0]
3316 tags[patch[1]] = patch[0]
3310
3317
3311 return result
3318 return result
3312
3319
3313 def _branchtags(self, partial, lrev):
3320 def _branchtags(self, partial, lrev):
3314 q = self.mq
3321 q = self.mq
3315 cl = self.changelog
3322 cl = self.changelog
3316 qbase = None
3323 qbase = None
3317 if not q.applied:
3324 if not q.applied:
3318 if getattr(self, '_committingpatch', False):
3325 if getattr(self, '_committingpatch', False):
3319 # Committing a new patch, must be tip
3326 # Committing a new patch, must be tip
3320 qbase = len(cl) - 1
3327 qbase = len(cl) - 1
3321 else:
3328 else:
3322 qbasenode = q.applied[0].node
3329 qbasenode = q.applied[0].node
3323 try:
3330 try:
3324 qbase = cl.rev(qbasenode)
3331 qbase = cl.rev(qbasenode)
3325 except error.LookupError:
3332 except error.LookupError:
3326 self.ui.warn(_('mq status file refers to unknown node %s\n')
3333 self.ui.warn(_('mq status file refers to unknown node %s\n')
3327 % short(qbasenode))
3334 % short(qbasenode))
3328 if qbase is None:
3335 if qbase is None:
3329 return super(mqrepo, self)._branchtags(partial, lrev)
3336 return super(mqrepo, self)._branchtags(partial, lrev)
3330
3337
3331 start = lrev + 1
3338 start = lrev + 1
3332 if start < qbase:
3339 if start < qbase:
3333 # update the cache (excluding the patches) and save it
3340 # update the cache (excluding the patches) and save it
3334 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
3341 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
3335 self._updatebranchcache(partial, ctxgen)
3342 self._updatebranchcache(partial, ctxgen)
3336 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
3343 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
3337 start = qbase
3344 start = qbase
3338 # if start = qbase, the cache is as updated as it should be.
3345 # if start = qbase, the cache is as updated as it should be.
3339 # if start > qbase, the cache includes (part of) the patches.
3346 # if start > qbase, the cache includes (part of) the patches.
3340 # we might as well use it, but we won't save it.
3347 # we might as well use it, but we won't save it.
3341
3348
3342 # update the cache up to the tip
3349 # update the cache up to the tip
3343 ctxgen = (self[r] for r in xrange(start, len(cl)))
3350 ctxgen = (self[r] for r in xrange(start, len(cl)))
3344 self._updatebranchcache(partial, ctxgen)
3351 self._updatebranchcache(partial, ctxgen)
3345
3352
3346 return partial
3353 return partial
3347
3354
3348 if repo.local():
3355 if repo.local():
3349 repo.__class__ = mqrepo
3356 repo.__class__ = mqrepo
3350
3357
3351 repo._phasedefaults.append(mqphasedefaults)
3358 repo._phasedefaults.append(mqphasedefaults)
3352
3359
3353 def mqimport(orig, ui, repo, *args, **kwargs):
3360 def mqimport(orig, ui, repo, *args, **kwargs):
3354 if (util.safehasattr(repo, 'abortifwdirpatched')
3361 if (util.safehasattr(repo, 'abortifwdirpatched')
3355 and not kwargs.get('no_commit', False)):
3362 and not kwargs.get('no_commit', False)):
3356 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3363 repo.abortifwdirpatched(_('cannot import over an applied patch'),
3357 kwargs.get('force'))
3364 kwargs.get('force'))
3358 return orig(ui, repo, *args, **kwargs)
3365 return orig(ui, repo, *args, **kwargs)
3359
3366
3360 def mqinit(orig, ui, *args, **kwargs):
3367 def mqinit(orig, ui, *args, **kwargs):
3361 mq = kwargs.pop('mq', None)
3368 mq = kwargs.pop('mq', None)
3362
3369
3363 if not mq:
3370 if not mq:
3364 return orig(ui, *args, **kwargs)
3371 return orig(ui, *args, **kwargs)
3365
3372
3366 if args:
3373 if args:
3367 repopath = args[0]
3374 repopath = args[0]
3368 if not hg.islocal(repopath):
3375 if not hg.islocal(repopath):
3369 raise util.Abort(_('only a local queue repository '
3376 raise util.Abort(_('only a local queue repository '
3370 'may be initialized'))
3377 'may be initialized'))
3371 else:
3378 else:
3372 repopath = cmdutil.findrepo(os.getcwd())
3379 repopath = cmdutil.findrepo(os.getcwd())
3373 if not repopath:
3380 if not repopath:
3374 raise util.Abort(_('there is no Mercurial repository here '
3381 raise util.Abort(_('there is no Mercurial repository here '
3375 '(.hg not found)'))
3382 '(.hg not found)'))
3376 repo = hg.repository(ui, repopath)
3383 repo = hg.repository(ui, repopath)
3377 return qinit(ui, repo, True)
3384 return qinit(ui, repo, True)
3378
3385
3379 def mqcommand(orig, ui, repo, *args, **kwargs):
3386 def mqcommand(orig, ui, repo, *args, **kwargs):
3380 """Add --mq option to operate on patch repository instead of main"""
3387 """Add --mq option to operate on patch repository instead of main"""
3381
3388
3382 # some commands do not like getting unknown options
3389 # some commands do not like getting unknown options
3383 mq = kwargs.pop('mq', None)
3390 mq = kwargs.pop('mq', None)
3384
3391
3385 if not mq:
3392 if not mq:
3386 return orig(ui, repo, *args, **kwargs)
3393 return orig(ui, repo, *args, **kwargs)
3387
3394
3388 q = repo.mq
3395 q = repo.mq
3389 r = q.qrepo()
3396 r = q.qrepo()
3390 if not r:
3397 if not r:
3391 raise util.Abort(_('no queue repository'))
3398 raise util.Abort(_('no queue repository'))
3392 return orig(r.ui, r, *args, **kwargs)
3399 return orig(r.ui, r, *args, **kwargs)
3393
3400
3394 def summary(orig, ui, repo, *args, **kwargs):
3401 def summary(orig, ui, repo, *args, **kwargs):
3395 r = orig(ui, repo, *args, **kwargs)
3402 r = orig(ui, repo, *args, **kwargs)
3396 q = repo.mq
3403 q = repo.mq
3397 m = []
3404 m = []
3398 a, u = len(q.applied), len(q.unapplied(repo))
3405 a, u = len(q.applied), len(q.unapplied(repo))
3399 if a:
3406 if a:
3400 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3407 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
3401 if u:
3408 if u:
3402 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3409 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
3403 if m:
3410 if m:
3404 ui.write("mq: %s\n" % ', '.join(m))
3411 ui.write("mq: %s\n" % ', '.join(m))
3405 else:
3412 else:
3406 ui.note(_("mq: (empty queue)\n"))
3413 ui.note(_("mq: (empty queue)\n"))
3407 return r
3414 return r
3408
3415
3409 def revsetmq(repo, subset, x):
3416 def revsetmq(repo, subset, x):
3410 """``mq()``
3417 """``mq()``
3411 Changesets managed by MQ.
3418 Changesets managed by MQ.
3412 """
3419 """
3413 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3420 revset.getargs(x, 0, 0, _("mq takes no arguments"))
3414 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3421 applied = set([repo[r.node].rev() for r in repo.mq.applied])
3415 return [r for r in subset if r in applied]
3422 return [r for r in subset if r in applied]
3416
3423
3417 def extsetup(ui):
3424 def extsetup(ui):
3418 revset.symbols['mq'] = revsetmq
3425 revset.symbols['mq'] = revsetmq
3419
3426
3420 # tell hggettext to extract docstrings from these functions:
3427 # tell hggettext to extract docstrings from these functions:
3421 i18nfunctions = [revsetmq]
3428 i18nfunctions = [revsetmq]
3422
3429
3423 def uisetup(ui):
3430 def uisetup(ui):
3424 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3431 mqopt = [('', 'mq', None, _("operate on patch repository"))]
3425
3432
3426 extensions.wrapcommand(commands.table, 'import', mqimport)
3433 extensions.wrapcommand(commands.table, 'import', mqimport)
3427 extensions.wrapcommand(commands.table, 'summary', summary)
3434 extensions.wrapcommand(commands.table, 'summary', summary)
3428
3435
3429 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3436 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
3430 entry[1].extend(mqopt)
3437 entry[1].extend(mqopt)
3431
3438
3432 nowrap = set(commands.norepo.split(" "))
3439 nowrap = set(commands.norepo.split(" "))
3433
3440
3434 def dotable(cmdtable):
3441 def dotable(cmdtable):
3435 for cmd in cmdtable.keys():
3442 for cmd in cmdtable.keys():
3436 cmd = cmdutil.parsealiases(cmd)[0]
3443 cmd = cmdutil.parsealiases(cmd)[0]
3437 if cmd in nowrap:
3444 if cmd in nowrap:
3438 continue
3445 continue
3439 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3446 entry = extensions.wrapcommand(cmdtable, cmd, mqcommand)
3440 entry[1].extend(mqopt)
3447 entry[1].extend(mqopt)
3441
3448
3442 dotable(commands.table)
3449 dotable(commands.table)
3443
3450
3444 for extname, extmodule in extensions.extensions():
3451 for extname, extmodule in extensions.extensions():
3445 if extmodule.__file__ != __file__:
3452 if extmodule.__file__ != __file__:
3446 dotable(getattr(extmodule, 'cmdtable', {}))
3453 dotable(getattr(extmodule, 'cmdtable', {}))
3447
3454
3448
3455
3449 colortable = {'qguard.negative': 'red',
3456 colortable = {'qguard.negative': 'red',
3450 'qguard.positive': 'yellow',
3457 'qguard.positive': 'yellow',
3451 'qguard.unguarded': 'green',
3458 'qguard.unguarded': 'green',
3452 'qseries.applied': 'blue bold underline',
3459 'qseries.applied': 'blue bold underline',
3453 'qseries.guarded': 'black bold',
3460 'qseries.guarded': 'black bold',
3454 'qseries.missing': 'red bold',
3461 'qseries.missing': 'red bold',
3455 'qseries.unapplied': 'black bold'}
3462 'qseries.unapplied': 'black bold'}
@@ -1,633 +1,630 b''
1 $ check_code="$TESTDIR"/../contrib/check-code.py
1 $ check_code="$TESTDIR"/../contrib/check-code.py
2 $ cd "$TESTDIR"/..
2 $ cd "$TESTDIR"/..
3 $ if hg identify -q > /dev/null; then :
3 $ if hg identify -q > /dev/null; then :
4 > else
4 > else
5 > echo "skipped: not a Mercurial working dir" >&2
5 > echo "skipped: not a Mercurial working dir" >&2
6 > exit 80
6 > exit 80
7 > fi
7 > fi
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
9
9
10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
11 contrib/check-code.py:0:
11 contrib/check-code.py:0:
12 > # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
12 > # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
13 warning: line over 80 characters
13 warning: line over 80 characters
14 contrib/perf.py:0:
14 contrib/perf.py:0:
15 > except:
15 > except:
16 warning: naked except clause
16 warning: naked except clause
17 contrib/perf.py:0:
17 contrib/perf.py:0:
18 > #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, False))))
18 > #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, False))))
19 warning: line over 80 characters
19 warning: line over 80 characters
20 contrib/perf.py:0:
20 contrib/perf.py:0:
21 > except:
21 > except:
22 warning: naked except clause
22 warning: naked except clause
23 contrib/setup3k.py:0:
23 contrib/setup3k.py:0:
24 > except:
24 > except:
25 warning: naked except clause
25 warning: naked except clause
26 contrib/setup3k.py:0:
26 contrib/setup3k.py:0:
27 > except:
27 > except:
28 warning: naked except clause
28 warning: naked except clause
29 contrib/setup3k.py:0:
29 contrib/setup3k.py:0:
30 > except:
30 > except:
31 warning: naked except clause
31 warning: naked except clause
32 warning: naked except clause
32 warning: naked except clause
33 warning: naked except clause
33 warning: naked except clause
34 contrib/shrink-revlog.py:0:
34 contrib/shrink-revlog.py:0:
35 > except:
35 > except:
36 warning: naked except clause
36 warning: naked except clause
37 doc/gendoc.py:0:
37 doc/gendoc.py:0:
38 > "together with Mercurial. Help for other extensions is available "
38 > "together with Mercurial. Help for other extensions is available "
39 warning: line over 80 characters
39 warning: line over 80 characters
40 hgext/bugzilla.py:0:
40 hgext/bugzilla.py:0:
41 > raise util.Abort(_('cannot find bugzilla user id for %s or %s') %
41 > raise util.Abort(_('cannot find bugzilla user id for %s or %s') %
42 warning: line over 80 characters
42 warning: line over 80 characters
43 hgext/bugzilla.py:0:
43 hgext/bugzilla.py:0:
44 > bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla')
44 > bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla')
45 warning: line over 80 characters
45 warning: line over 80 characters
46 hgext/convert/__init__.py:0:
46 hgext/convert/__init__.py:0:
47 > ('', 'ancestors', '', _('show current changeset in ancestor branches')),
47 > ('', 'ancestors', '', _('show current changeset in ancestor branches')),
48 warning: line over 80 characters
48 warning: line over 80 characters
49 hgext/convert/bzr.py:0:
49 hgext/convert/bzr.py:0:
50 > except:
50 > except:
51 warning: naked except clause
51 warning: naked except clause
52 hgext/convert/common.py:0:
52 hgext/convert/common.py:0:
53 > except:
53 > except:
54 warning: naked except clause
54 warning: naked except clause
55 hgext/convert/common.py:0:
55 hgext/convert/common.py:0:
56 > except:
56 > except:
57 warning: naked except clause
57 warning: naked except clause
58 warning: naked except clause
58 warning: naked except clause
59 hgext/convert/convcmd.py:0:
59 hgext/convert/convcmd.py:0:
60 > except:
60 > except:
61 warning: naked except clause
61 warning: naked except clause
62 hgext/convert/cvs.py:0:
62 hgext/convert/cvs.py:0:
63 > # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
63 > # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
64 warning: line over 80 characters
64 warning: line over 80 characters
65 hgext/convert/cvsps.py:0:
65 hgext/convert/cvsps.py:0:
66 > assert len(branches) == 1, 'unknown branch: %s' % e.mergepoint
66 > assert len(branches) == 1, 'unknown branch: %s' % e.mergepoint
67 warning: line over 80 characters
67 warning: line over 80 characters
68 hgext/convert/cvsps.py:0:
68 hgext/convert/cvsps.py:0:
69 > ui.write('Ancestors: %s\n' % (','.join(r)))
69 > ui.write('Ancestors: %s\n' % (','.join(r)))
70 warning: unwrapped ui message
70 warning: unwrapped ui message
71 hgext/convert/cvsps.py:0:
71 hgext/convert/cvsps.py:0:
72 > ui.write('Parent: %d\n' % cs.parents[0].id)
72 > ui.write('Parent: %d\n' % cs.parents[0].id)
73 warning: unwrapped ui message
73 warning: unwrapped ui message
74 hgext/convert/cvsps.py:0:
74 hgext/convert/cvsps.py:0:
75 > ui.write('Parents: %s\n' %
75 > ui.write('Parents: %s\n' %
76 warning: unwrapped ui message
76 warning: unwrapped ui message
77 hgext/convert/cvsps.py:0:
77 hgext/convert/cvsps.py:0:
78 > except:
78 > except:
79 warning: naked except clause
79 warning: naked except clause
80 hgext/convert/cvsps.py:0:
80 hgext/convert/cvsps.py:0:
81 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
81 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
82 warning: unwrapped ui message
82 warning: unwrapped ui message
83 hgext/convert/cvsps.py:0:
83 hgext/convert/cvsps.py:0:
84 > ui.write('Author: %s\n' % cs.author)
84 > ui.write('Author: %s\n' % cs.author)
85 warning: unwrapped ui message
85 warning: unwrapped ui message
86 hgext/convert/cvsps.py:0:
86 hgext/convert/cvsps.py:0:
87 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
87 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
88 warning: unwrapped ui message
88 warning: unwrapped ui message
89 hgext/convert/cvsps.py:0:
89 hgext/convert/cvsps.py:0:
90 > ui.write('Date: %s\n' % util.datestr(cs.date,
90 > ui.write('Date: %s\n' % util.datestr(cs.date,
91 warning: unwrapped ui message
91 warning: unwrapped ui message
92 hgext/convert/cvsps.py:0:
92 hgext/convert/cvsps.py:0:
93 > ui.write('Log:\n')
93 > ui.write('Log:\n')
94 warning: unwrapped ui message
94 warning: unwrapped ui message
95 hgext/convert/cvsps.py:0:
95 hgext/convert/cvsps.py:0:
96 > ui.write('Members: \n')
96 > ui.write('Members: \n')
97 warning: unwrapped ui message
97 warning: unwrapped ui message
98 hgext/convert/cvsps.py:0:
98 hgext/convert/cvsps.py:0:
99 > ui.write('PatchSet %d \n' % cs.id)
99 > ui.write('PatchSet %d \n' % cs.id)
100 warning: unwrapped ui message
100 warning: unwrapped ui message
101 hgext/convert/cvsps.py:0:
101 hgext/convert/cvsps.py:0:
102 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
102 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
103 warning: unwrapped ui message
103 warning: unwrapped ui message
104 hgext/convert/git.py:0:
104 hgext/convert/git.py:0:
105 > except:
105 > except:
106 warning: naked except clause
106 warning: naked except clause
107 hgext/convert/git.py:0:
107 hgext/convert/git.py:0:
108 > fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
108 > fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
109 warning: line over 80 characters
109 warning: line over 80 characters
110 hgext/convert/hg.py:0:
110 hgext/convert/hg.py:0:
111 > # detect missing revlogs and abort on errors or populate self.ignored
111 > # detect missing revlogs and abort on errors or populate self.ignored
112 warning: line over 80 characters
112 warning: line over 80 characters
113 hgext/convert/hg.py:0:
113 hgext/convert/hg.py:0:
114 > except:
114 > except:
115 warning: naked except clause
115 warning: naked except clause
116 warning: naked except clause
116 warning: naked except clause
117 hgext/convert/hg.py:0:
117 hgext/convert/hg.py:0:
118 > except:
118 > except:
119 warning: naked except clause
119 warning: naked except clause
120 hgext/convert/monotone.py:0:
120 hgext/convert/monotone.py:0:
121 > except:
121 > except:
122 warning: naked except clause
122 warning: naked except clause
123 hgext/convert/monotone.py:0:
123 hgext/convert/monotone.py:0:
124 > except:
124 > except:
125 warning: naked except clause
125 warning: naked except clause
126 hgext/convert/subversion.py:0:
126 hgext/convert/subversion.py:0:
127 > raise util.Abort(_('svn: branch has no revision %s') % to_revnum)
127 > raise util.Abort(_('svn: branch has no revision %s') % to_revnum)
128 warning: line over 80 characters
128 warning: line over 80 characters
129 hgext/convert/subversion.py:0:
129 hgext/convert/subversion.py:0:
130 > except:
130 > except:
131 warning: naked except clause
131 warning: naked except clause
132 hgext/convert/subversion.py:0:
132 hgext/convert/subversion.py:0:
133 > args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
133 > args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
134 warning: line over 80 characters
134 warning: line over 80 characters
135 hgext/convert/subversion.py:0:
135 hgext/convert/subversion.py:0:
136 > self.trunkname = self.ui.config('convert', 'svn.trunk', 'trunk').strip('/')
136 > self.trunkname = self.ui.config('convert', 'svn.trunk', 'trunk').strip('/')
137 warning: line over 80 characters
137 warning: line over 80 characters
138 hgext/convert/subversion.py:0:
138 hgext/convert/subversion.py:0:
139 > except:
139 > except:
140 warning: naked except clause
140 warning: naked except clause
141 hgext/convert/subversion.py:0:
141 hgext/convert/subversion.py:0:
142 > def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True,
142 > def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True,
143 warning: line over 80 characters
143 warning: line over 80 characters
144 hgext/eol.py:0:
144 hgext/eol.py:0:
145 > if ui.configbool('eol', 'fix-trailing-newline', False) and s and s[-1] != '\n':
145 > if ui.configbool('eol', 'fix-trailing-newline', False) and s and s[-1] != '\n':
146 warning: line over 80 characters
146 warning: line over 80 characters
147 warning: line over 80 characters
147 warning: line over 80 characters
148 hgext/gpg.py:0:
148 hgext/gpg.py:0:
149 > except:
149 > except:
150 warning: naked except clause
150 warning: naked except clause
151 hgext/hgcia.py:0:
151 hgext/hgcia.py:0:
152 > except:
152 > except:
153 warning: naked except clause
153 warning: naked except clause
154 hgext/hgk.py:0:
154 hgext/hgk.py:0:
155 > ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
155 > ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
156 warning: line over 80 characters
156 warning: line over 80 characters
157 hgext/hgk.py:0:
157 hgext/hgk.py:0:
158 > ui.write("parent %s\n" % p)
158 > ui.write("parent %s\n" % p)
159 warning: unwrapped ui message
159 warning: unwrapped ui message
160 hgext/hgk.py:0:
160 hgext/hgk.py:0:
161 > ui.write('k=%s\nv=%s\n' % (name, value))
161 > ui.write('k=%s\nv=%s\n' % (name, value))
162 warning: unwrapped ui message
162 warning: unwrapped ui message
163 hgext/hgk.py:0:
163 hgext/hgk.py:0:
164 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
164 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
165 warning: unwrapped ui message
165 warning: unwrapped ui message
166 hgext/hgk.py:0:
166 hgext/hgk.py:0:
167 > ui.write("branch %s\n\n" % ctx.branch())
167 > ui.write("branch %s\n\n" % ctx.branch())
168 warning: unwrapped ui message
168 warning: unwrapped ui message
169 hgext/hgk.py:0:
169 hgext/hgk.py:0:
170 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
170 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
171 warning: unwrapped ui message
171 warning: unwrapped ui message
172 hgext/hgk.py:0:
172 hgext/hgk.py:0:
173 > ui.write("revision %d\n" % ctx.rev())
173 > ui.write("revision %d\n" % ctx.rev())
174 warning: unwrapped ui message
174 warning: unwrapped ui message
175 hgext/hgk.py:0:
175 hgext/hgk.py:0:
176 > ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
176 > ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
177 warning: line over 80 characters
177 warning: line over 80 characters
178 warning: unwrapped ui message
178 warning: unwrapped ui message
179 hgext/highlight/__init__.py:0:
179 hgext/highlight/__init__.py:0:
180 > extensions.wrapfunction(webcommands, '_filerevision', filerevision_highlight)
180 > extensions.wrapfunction(webcommands, '_filerevision', filerevision_highlight)
181 warning: line over 80 characters
181 warning: line over 80 characters
182 hgext/highlight/__init__.py:0:
182 hgext/highlight/__init__.py:0:
183 > return ['/* pygments_style = %s */\n\n' % pg_style, fmter.get_style_defs('')]
183 > return ['/* pygments_style = %s */\n\n' % pg_style, fmter.get_style_defs('')]
184 warning: line over 80 characters
184 warning: line over 80 characters
185 hgext/inotify/__init__.py:0:
185 hgext/inotify/__init__.py:0:
186 > if self._inotifyon and not ignored and not subrepos and not self._dirty:
186 > if self._inotifyon and not ignored and not subrepos and not self._dirty:
187 warning: line over 80 characters
187 warning: line over 80 characters
188 hgext/inotify/server.py:0:
188 hgext/inotify/server.py:0:
189 > except:
189 > except:
190 warning: naked except clause
190 warning: naked except clause
191 hgext/inotify/server.py:0:
191 hgext/inotify/server.py:0:
192 > except:
192 > except:
193 warning: naked except clause
193 warning: naked except clause
194 hgext/keyword.py:0:
194 hgext/keyword.py:0:
195 > ui.note("hg ci -m '%s'\n" % msg)
195 > ui.note("hg ci -m '%s'\n" % msg)
196 warning: unwrapped ui message
196 warning: unwrapped ui message
197 hgext/mq.py:0:
197 hgext/mq.py:0:
198 > raise util.Abort(_("cannot push --exact with applied patches"))
198 > raise util.Abort(_("cannot push --exact with applied patches"))
199 warning: line over 80 characters
199 warning: line over 80 characters
200 hgext/mq.py:0:
200 hgext/mq.py:0:
201 > raise util.Abort(_("cannot use --exact and --move together"))
201 > raise util.Abort(_("cannot use --exact and --move together"))
202 warning: line over 80 characters
202 warning: line over 80 characters
203 hgext/mq.py:0:
203 hgext/mq.py:0:
204 > self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
204 > self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
205 warning: line over 80 characters
205 warning: line over 80 characters
206 hgext/mq.py:0:
206 hgext/mq.py:0:
207 > except:
207 > except:
208 warning: naked except clause
208 warning: naked except clause
209 warning: naked except clause
209 warning: naked except clause
210 hgext/mq.py:0:
210 hgext/mq.py:0:
211 > except:
211 > except:
212 warning: naked except clause
212 warning: naked except clause
213 warning: naked except clause
213 warning: naked except clause
214 warning: naked except clause
214 warning: naked except clause
215 warning: naked except clause
215 warning: naked except clause
216 hgext/mq.py:0:
216 hgext/mq.py:0:
217 > raise util.Abort(_('cannot mix -l/--list with options or arguments'))
217 > raise util.Abort(_('cannot mix -l/--list with options or arguments'))
218 warning: line over 80 characters
218 warning: line over 80 characters
219 hgext/mq.py:0:
219 hgext/mq.py:0:
220 > raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
220 > raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
221 warning: line over 80 characters
221 warning: line over 80 characters
222 hgext/mq.py:0:
222 hgext/mq.py:0:
223 > ('', 'move', None, _('reorder patch series and apply only the patch'))],
224 warning: line over 80 characters
225 hgext/mq.py:0:
226 > ('U', 'noupdate', None, _('do not update the new working directories')),
223 > ('U', 'noupdate', None, _('do not update the new working directories')),
227 warning: line over 80 characters
224 warning: line over 80 characters
228 hgext/mq.py:0:
225 hgext/mq.py:0:
229 > ('e', 'exact', None, _('apply the target patch to its recorded parent')),
226 > ('e', 'exact', None, _('apply the target patch to its recorded parent')),
230 warning: line over 80 characters
227 warning: line over 80 characters
231 hgext/mq.py:0:
228 hgext/mq.py:0:
232 > except:
229 > except:
233 warning: naked except clause
230 warning: naked except clause
234 hgext/mq.py:0:
231 hgext/mq.py:0:
235 > ui.write("mq: %s\n" % ', '.join(m))
232 > ui.write("mq: %s\n" % ', '.join(m))
236 warning: unwrapped ui message
233 warning: unwrapped ui message
237 hgext/mq.py:0:
234 hgext/mq.py:0:
238 > repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
235 > repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
239 warning: line over 80 characters
236 warning: line over 80 characters
240 hgext/notify.py:0:
237 hgext/notify.py:0:
241 > ui.note(_('notify: suppressing notification for merge %d:%s\n') %
238 > ui.note(_('notify: suppressing notification for merge %d:%s\n') %
242 warning: line over 80 characters
239 warning: line over 80 characters
243 hgext/patchbomb.py:0:
240 hgext/patchbomb.py:0:
244 > binnode, seqno=idx, total=total)
241 > binnode, seqno=idx, total=total)
245 warning: line over 80 characters
242 warning: line over 80 characters
246 hgext/patchbomb.py:0:
243 hgext/patchbomb.py:0:
247 > except:
244 > except:
248 warning: naked except clause
245 warning: naked except clause
249 hgext/patchbomb.py:0:
246 hgext/patchbomb.py:0:
250 > ui.write('Subject: %s\n' % subj)
247 > ui.write('Subject: %s\n' % subj)
251 warning: unwrapped ui message
248 warning: unwrapped ui message
252 hgext/patchbomb.py:0:
249 hgext/patchbomb.py:0:
253 > p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test'))
250 > p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test'))
254 warning: line over 80 characters
251 warning: line over 80 characters
255 hgext/patchbomb.py:0:
252 hgext/patchbomb.py:0:
256 > ui.write('From: %s\n' % sender)
253 > ui.write('From: %s\n' % sender)
257 warning: unwrapped ui message
254 warning: unwrapped ui message
258 hgext/record.py:0:
255 hgext/record.py:0:
259 > ignoreblanklines=opts.get('ignore_blank_lines'))
256 > ignoreblanklines=opts.get('ignore_blank_lines'))
260 warning: line over 80 characters
257 warning: line over 80 characters
261 hgext/record.py:0:
258 hgext/record.py:0:
262 > ignorewsamount=opts.get('ignore_space_change'),
259 > ignorewsamount=opts.get('ignore_space_change'),
263 warning: line over 80 characters
260 warning: line over 80 characters
264 hgext/zeroconf/__init__.py:0:
261 hgext/zeroconf/__init__.py:0:
265 > publish(name, desc, path, util.getport(u.config("web", "port", 8000)))
262 > publish(name, desc, path, util.getport(u.config("web", "port", 8000)))
266 warning: line over 80 characters
263 warning: line over 80 characters
267 hgext/zeroconf/__init__.py:0:
264 hgext/zeroconf/__init__.py:0:
268 > except:
265 > except:
269 warning: naked except clause
266 warning: naked except clause
270 warning: naked except clause
267 warning: naked except clause
271 mercurial/bundlerepo.py:0:
268 mercurial/bundlerepo.py:0:
272 > is a bundlerepo for the obtained bundle when the original "other" is remote.
269 > is a bundlerepo for the obtained bundle when the original "other" is remote.
273 warning: line over 80 characters
270 warning: line over 80 characters
274 mercurial/bundlerepo.py:0:
271 mercurial/bundlerepo.py:0:
275 > "local" is a local repo from which to obtain the actual incoming changesets; it
272 > "local" is a local repo from which to obtain the actual incoming changesets; it
276 warning: line over 80 characters
273 warning: line over 80 characters
277 mercurial/bundlerepo.py:0:
274 mercurial/bundlerepo.py:0:
278 > tmp = discovery.findcommonincoming(repo, other, heads=onlyheads, force=force)
275 > tmp = discovery.findcommonincoming(repo, other, heads=onlyheads, force=force)
279 warning: line over 80 characters
276 warning: line over 80 characters
280 mercurial/commands.py:0:
277 mercurial/commands.py:0:
281 > " size " + basehdr + " link p1 p2 nodeid\n")
278 > " size " + basehdr + " link p1 p2 nodeid\n")
282 warning: line over 80 characters
279 warning: line over 80 characters
283 mercurial/commands.py:0:
280 mercurial/commands.py:0:
284 > raise util.Abort('cannot use localheads with old style discovery')
281 > raise util.Abort('cannot use localheads with old style discovery')
285 warning: line over 80 characters
282 warning: line over 80 characters
286 mercurial/commands.py:0:
283 mercurial/commands.py:0:
287 > ui.note('branch %s\n' % data)
284 > ui.note('branch %s\n' % data)
288 warning: unwrapped ui message
285 warning: unwrapped ui message
289 mercurial/commands.py:0:
286 mercurial/commands.py:0:
290 > ui.note('node %s\n' % str(data))
287 > ui.note('node %s\n' % str(data))
291 warning: unwrapped ui message
288 warning: unwrapped ui message
292 mercurial/commands.py:0:
289 mercurial/commands.py:0:
293 > ui.note('tag %s\n' % name)
290 > ui.note('tag %s\n' % name)
294 warning: unwrapped ui message
291 warning: unwrapped ui message
295 mercurial/commands.py:0:
292 mercurial/commands.py:0:
296 > ui.write("unpruned common: %s\n" % " ".join([short(n)
293 > ui.write("unpruned common: %s\n" % " ".join([short(n)
297 warning: unwrapped ui message
294 warning: unwrapped ui message
298 mercurial/commands.py:0:
295 mercurial/commands.py:0:
299 > yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
296 > yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
300 warning: line over 80 characters
297 warning: line over 80 characters
301 mercurial/commands.py:0:
298 mercurial/commands.py:0:
302 > yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
299 > yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
303 warning: line over 80 characters
300 warning: line over 80 characters
304 mercurial/commands.py:0:
301 mercurial/commands.py:0:
305 > except:
302 > except:
306 warning: naked except clause
303 warning: naked except clause
307 mercurial/commands.py:0:
304 mercurial/commands.py:0:
308 > ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
305 > ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
309 warning: line over 80 characters
306 warning: line over 80 characters
310 mercurial/commands.py:0:
307 mercurial/commands.py:0:
311 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
308 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
312 warning: unwrapped ui message
309 warning: unwrapped ui message
313 mercurial/commands.py:0:
310 mercurial/commands.py:0:
314 > ui.write("local is subset\n")
311 > ui.write("local is subset\n")
315 warning: unwrapped ui message
312 warning: unwrapped ui message
316 mercurial/commands.py:0:
313 mercurial/commands.py:0:
317 > ui.write("remote is subset\n")
314 > ui.write("remote is subset\n")
318 warning: unwrapped ui message
315 warning: unwrapped ui message
319 mercurial/commands.py:0:
316 mercurial/commands.py:0:
320 > ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
317 > ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
321 warning: line over 80 characters
318 warning: line over 80 characters
322 mercurial/commands.py:0:
319 mercurial/commands.py:0:
323 > ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
320 > ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
324 warning: line over 80 characters
321 warning: line over 80 characters
325 mercurial/commands.py:0:
322 mercurial/commands.py:0:
326 > ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
323 > ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
327 warning: line over 80 characters
324 warning: line over 80 characters
328 mercurial/commands.py:0:
325 mercurial/commands.py:0:
329 > ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
326 > ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
330 warning: line over 80 characters
327 warning: line over 80 characters
331 warning: unwrapped ui message
328 warning: unwrapped ui message
332 mercurial/commands.py:0:
329 mercurial/commands.py:0:
333 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
330 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
334 warning: unwrapped ui message
331 warning: unwrapped ui message
335 mercurial/commands.py:0:
332 mercurial/commands.py:0:
336 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
333 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
337 warning: unwrapped ui message
334 warning: unwrapped ui message
338 mercurial/commands.py:0:
335 mercurial/commands.py:0:
339 > except:
336 > except:
340 warning: naked except clause
337 warning: naked except clause
341 mercurial/commands.py:0:
338 mercurial/commands.py:0:
342 > revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
339 > revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
343 warning: line over 80 characters
340 warning: line over 80 characters
344 mercurial/commands.py:0:
341 mercurial/commands.py:0:
345 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
342 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
346 warning: unwrapped ui message
343 warning: unwrapped ui message
347 mercurial/commands.py:0:
344 mercurial/commands.py:0:
348 > ui.write("match: %s\n" % m(d[0]))
345 > ui.write("match: %s\n" % m(d[0]))
349 warning: unwrapped ui message
346 warning: unwrapped ui message
350 mercurial/commands.py:0:
347 mercurial/commands.py:0:
351 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
348 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
352 warning: unwrapped ui message
349 warning: unwrapped ui message
353 mercurial/commands.py:0:
350 mercurial/commands.py:0:
354 > ui.write('path %s\n' % k)
351 > ui.write('path %s\n' % k)
355 warning: unwrapped ui message
352 warning: unwrapped ui message
356 mercurial/commands.py:0:
353 mercurial/commands.py:0:
357 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
354 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
358 warning: unwrapped ui message
355 warning: unwrapped ui message
359 mercurial/commands.py:0:
356 mercurial/commands.py:0:
360 > Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
357 > Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
361 warning: line over 80 characters
358 warning: line over 80 characters
362 mercurial/commands.py:0:
359 mercurial/commands.py:0:
363 > remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
360 > remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
364 warning: line over 80 characters
361 warning: line over 80 characters
365 mercurial/commands.py:0:
362 mercurial/commands.py:0:
366 > ui.write("digraph G {\n")
363 > ui.write("digraph G {\n")
367 warning: unwrapped ui message
364 warning: unwrapped ui message
368 mercurial/commands.py:0:
365 mercurial/commands.py:0:
369 > ui.write("internal: %s %s\n" % d)
366 > ui.write("internal: %s %s\n" % d)
370 warning: unwrapped ui message
367 warning: unwrapped ui message
371 mercurial/commands.py:0:
368 mercurial/commands.py:0:
372 > ui.write("standard: %s\n" % util.datestr(d))
369 > ui.write("standard: %s\n" % util.datestr(d))
373 warning: unwrapped ui message
370 warning: unwrapped ui message
374 mercurial/commands.py:0:
371 mercurial/commands.py:0:
375 > ui.write('avg chain length : ' + fmt % avgchainlen)
372 > ui.write('avg chain length : ' + fmt % avgchainlen)
376 warning: unwrapped ui message
373 warning: unwrapped ui message
377 mercurial/commands.py:0:
374 mercurial/commands.py:0:
378 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
375 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
379 warning: unwrapped ui message
376 warning: unwrapped ui message
380 mercurial/commands.py:0:
377 mercurial/commands.py:0:
381 > ui.write('compression ratio : ' + fmt % compratio)
378 > ui.write('compression ratio : ' + fmt % compratio)
382 warning: unwrapped ui message
379 warning: unwrapped ui message
383 mercurial/commands.py:0:
380 mercurial/commands.py:0:
384 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
381 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
385 warning: unwrapped ui message
382 warning: unwrapped ui message
386 mercurial/commands.py:0:
383 mercurial/commands.py:0:
387 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
384 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
388 warning: unwrapped ui message
385 warning: unwrapped ui message
389 mercurial/commands.py:0:
386 mercurial/commands.py:0:
390 > ui.write('flags : %s\n' % ', '.join(flags))
387 > ui.write('flags : %s\n' % ', '.join(flags))
391 warning: unwrapped ui message
388 warning: unwrapped ui message
392 mercurial/commands.py:0:
389 mercurial/commands.py:0:
393 > ui.write('format : %d\n' % format)
390 > ui.write('format : %d\n' % format)
394 warning: unwrapped ui message
391 warning: unwrapped ui message
395 mercurial/commands.py:0:
392 mercurial/commands.py:0:
396 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
393 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
397 warning: unwrapped ui message
394 warning: unwrapped ui message
398 mercurial/commands.py:0:
395 mercurial/commands.py:0:
399 > ui.write('revision size : ' + fmt2 % totalsize)
396 > ui.write('revision size : ' + fmt2 % totalsize)
400 warning: unwrapped ui message
397 warning: unwrapped ui message
401 mercurial/commands.py:0:
398 mercurial/commands.py:0:
402 > ui.write('revisions : ' + fmt2 % numrevs)
399 > ui.write('revisions : ' + fmt2 % numrevs)
403 warning: unwrapped ui message
400 warning: unwrapped ui message
404 warning: unwrapped ui message
401 warning: unwrapped ui message
405 mercurial/commands.py:0:
402 mercurial/commands.py:0:
406 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
403 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
407 warning: unwrapped ui message
404 warning: unwrapped ui message
408 mercurial/commandserver.py:0:
405 mercurial/commandserver.py:0:
409 > # the ui here is really the repo ui so take its baseui so we don't end up
406 > # the ui here is really the repo ui so take its baseui so we don't end up
410 warning: line over 80 characters
407 warning: line over 80 characters
411 mercurial/context.py:0:
408 mercurial/context.py:0:
412 > return self._manifestdelta[path], self._manifestdelta.flags(path)
409 > return self._manifestdelta[path], self._manifestdelta.flags(path)
413 warning: line over 80 characters
410 warning: line over 80 characters
414 mercurial/dagparser.py:0:
411 mercurial/dagparser.py:0:
415 > raise util.Abort(_("invalid character in dag description: %s...") % s)
412 > raise util.Abort(_("invalid character in dag description: %s...") % s)
416 warning: line over 80 characters
413 warning: line over 80 characters
417 mercurial/dagparser.py:0:
414 mercurial/dagparser.py:0:
418 > >>> dagtext([('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))])
415 > >>> dagtext([('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))])
419 warning: line over 80 characters
416 warning: line over 80 characters
420 mercurial/dirstate.py:0:
417 mercurial/dirstate.py:0:
421 > if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
418 > if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
422 warning: line over 80 characters
419 warning: line over 80 characters
423 mercurial/discovery.py:0:
420 mercurial/discovery.py:0:
424 > If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
421 > If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
425 warning: line over 80 characters
422 warning: line over 80 characters
426 mercurial/discovery.py:0:
423 mercurial/discovery.py:0:
427 > def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
424 > def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
428 warning: line over 80 characters
425 warning: line over 80 characters
429 mercurial/dispatch.py:0:
426 mercurial/dispatch.py:0:
430 > " (.hg not found)") % os.getcwd())
427 > " (.hg not found)") % os.getcwd())
431 warning: line over 80 characters
428 warning: line over 80 characters
432 mercurial/dispatch.py:0:
429 mercurial/dispatch.py:0:
433 > except:
430 > except:
434 warning: naked except clause
431 warning: naked except clause
435 mercurial/dispatch.py:0:
432 mercurial/dispatch.py:0:
436 > return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
433 > return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
437 warning: line over 80 characters
434 warning: line over 80 characters
438 mercurial/dispatch.py:0:
435 mercurial/dispatch.py:0:
439 > def __init__(self, args, ui=None, repo=None, fin=None, fout=None, ferr=None):
436 > def __init__(self, args, ui=None, repo=None, fin=None, fout=None, ferr=None):
440 warning: line over 80 characters
437 warning: line over 80 characters
441 mercurial/dispatch.py:0:
438 mercurial/dispatch.py:0:
442 > except:
439 > except:
443 warning: naked except clause
440 warning: naked except clause
444 mercurial/hg.py:0:
441 mercurial/hg.py:0:
445 > except:
442 > except:
446 warning: naked except clause
443 warning: naked except clause
447 mercurial/hgweb/hgweb_mod.py:0:
444 mercurial/hgweb/hgweb_mod.py:0:
448 > self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
445 > self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
449 warning: line over 80 characters
446 warning: line over 80 characters
450 mercurial/keepalive.py:0:
447 mercurial/keepalive.py:0:
451 > except:
448 > except:
452 warning: naked except clause
449 warning: naked except clause
453 mercurial/keepalive.py:0:
450 mercurial/keepalive.py:0:
454 > except:
451 > except:
455 warning: naked except clause
452 warning: naked except clause
456 mercurial/localrepo.py:0:
453 mercurial/localrepo.py:0:
457 > # we return an integer indicating remote head count change
454 > # we return an integer indicating remote head count change
458 warning: line over 80 characters
455 warning: line over 80 characters
459 mercurial/localrepo.py:0:
456 mercurial/localrepo.py:0:
460 > raise util.Abort(_("empty or missing revlog for %s") % fname)
457 > raise util.Abort(_("empty or missing revlog for %s") % fname)
461 warning: line over 80 characters
458 warning: line over 80 characters
462 warning: line over 80 characters
459 warning: line over 80 characters
463 mercurial/localrepo.py:0:
460 mercurial/localrepo.py:0:
464 > if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
461 > if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
465 warning: line over 80 characters
462 warning: line over 80 characters
466 mercurial/localrepo.py:0:
463 mercurial/localrepo.py:0:
467 > self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
464 > self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
468 warning: line over 80 characters
465 warning: line over 80 characters
469 mercurial/localrepo.py:0:
466 mercurial/localrepo.py:0:
470 > # new requirements = old non-format requirements + new format-related
467 > # new requirements = old non-format requirements + new format-related
471 warning: line over 80 characters
468 warning: line over 80 characters
472 mercurial/localrepo.py:0:
469 mercurial/localrepo.py:0:
473 > except:
470 > except:
474 warning: naked except clause
471 warning: naked except clause
475 mercurial/localrepo.py:0:
472 mercurial/localrepo.py:0:
476 > """return status of files between two nodes or node and working directory
473 > """return status of files between two nodes or node and working directory
477 warning: line over 80 characters
474 warning: line over 80 characters
478 mercurial/localrepo.py:0:
475 mercurial/localrepo.py:0:
479 > '''Returns a tagscache object that contains various tags related caches.'''
476 > '''Returns a tagscache object that contains various tags related caches.'''
480 warning: line over 80 characters
477 warning: line over 80 characters
481 mercurial/manifest.py:0:
478 mercurial/manifest.py:0:
482 > return "".join(struct.pack(">lll", start, end, len(content)) + content
479 > return "".join(struct.pack(">lll", start, end, len(content)) + content
483 warning: line over 80 characters
480 warning: line over 80 characters
484 mercurial/merge.py:0:
481 mercurial/merge.py:0:
485 > subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx), overwrite)
482 > subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx), overwrite)
486 warning: line over 80 characters
483 warning: line over 80 characters
487 mercurial/patch.py:0:
484 mercurial/patch.py:0:
488 > modified, added, removed, copy, getfilectx, opts, losedata, prefix)
485 > modified, added, removed, copy, getfilectx, opts, losedata, prefix)
489 warning: line over 80 characters
486 warning: line over 80 characters
490 mercurial/patch.py:0:
487 mercurial/patch.py:0:
491 > diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
488 > diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
492 warning: line over 80 characters
489 warning: line over 80 characters
493 mercurial/patch.py:0:
490 mercurial/patch.py:0:
494 > output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
491 > output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
495 warning: line over 80 characters
492 warning: line over 80 characters
496 mercurial/patch.py:0:
493 mercurial/patch.py:0:
497 > except:
494 > except:
498 warning: naked except clause
495 warning: naked except clause
499 mercurial/pure/mpatch.py:0:
496 mercurial/pure/mpatch.py:0:
500 > frags.extend(reversed(new)) # what was left at the end
497 > frags.extend(reversed(new)) # what was left at the end
501 warning: line over 80 characters
498 warning: line over 80 characters
502 mercurial/repair.py:0:
499 mercurial/repair.py:0:
503 > except:
500 > except:
504 warning: naked except clause
501 warning: naked except clause
505 mercurial/repair.py:0:
502 mercurial/repair.py:0:
506 > except:
503 > except:
507 warning: naked except clause
504 warning: naked except clause
508 mercurial/revset.py:0:
505 mercurial/revset.py:0:
509 > elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
506 > elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
510 warning: line over 80 characters
507 warning: line over 80 characters
511 mercurial/revset.py:0:
508 mercurial/revset.py:0:
512 > Changesets that are the Nth ancestor (first parents only) of a changeset in set.
509 > Changesets that are the Nth ancestor (first parents only) of a changeset in set.
513 warning: line over 80 characters
510 warning: line over 80 characters
514 mercurial/scmutil.py:0:
511 mercurial/scmutil.py:0:
515 > raise util.Abort(_("path '%s' is inside nested repo %r") %
512 > raise util.Abort(_("path '%s' is inside nested repo %r") %
516 warning: line over 80 characters
513 warning: line over 80 characters
517 mercurial/scmutil.py:0:
514 mercurial/scmutil.py:0:
518 > "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
515 > "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
519 warning: line over 80 characters
516 warning: line over 80 characters
520 mercurial/scmutil.py:0:
517 mercurial/scmutil.py:0:
521 > elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
518 > elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
522 warning: line over 80 characters
519 warning: line over 80 characters
523 mercurial/setdiscovery.py:0:
520 mercurial/setdiscovery.py:0:
524 > # treat remote heads (and maybe own heads) as a first implicit sample response
521 > # treat remote heads (and maybe own heads) as a first implicit sample response
525 warning: line over 80 characters
522 warning: line over 80 characters
526 mercurial/setdiscovery.py:0:
523 mercurial/setdiscovery.py:0:
527 > undecided = dag.nodeset() # own nodes where I don't know if remote knows them
524 > undecided = dag.nodeset() # own nodes where I don't know if remote knows them
528 warning: line over 80 characters
525 warning: line over 80 characters
529 mercurial/similar.py:0:
526 mercurial/similar.py:0:
530 > repo.ui.progress(_('searching for similar files'), i, total=len(removed))
527 > repo.ui.progress(_('searching for similar files'), i, total=len(removed))
531 warning: line over 80 characters
528 warning: line over 80 characters
532 mercurial/simplemerge.py:0:
529 mercurial/simplemerge.py:0:
533 > for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
530 > for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
534 warning: line over 80 characters
531 warning: line over 80 characters
535 mercurial/sshrepo.py:0:
532 mercurial/sshrepo.py:0:
536 > self._abort(error.RepoError(_("no suitable response from remote hg")))
533 > self._abort(error.RepoError(_("no suitable response from remote hg")))
537 warning: line over 80 characters
534 warning: line over 80 characters
538 mercurial/sshrepo.py:0:
535 mercurial/sshrepo.py:0:
539 > except:
536 > except:
540 warning: naked except clause
537 warning: naked except clause
541 mercurial/subrepo.py:0:
538 mercurial/subrepo.py:0:
542 > other, self._repo = hg.clone(self._repo._subparent.ui, {}, other,
539 > other, self._repo = hg.clone(self._repo._subparent.ui, {}, other,
543 warning: line over 80 characters
540 warning: line over 80 characters
544 mercurial/subrepo.py:0:
541 mercurial/subrepo.py:0:
545 > msg = (_(' subrepository sources for %s differ (in checked out version)\n'
542 > msg = (_(' subrepository sources for %s differ (in checked out version)\n'
546 warning: line over 80 characters
543 warning: line over 80 characters
547 mercurial/transaction.py:0:
544 mercurial/transaction.py:0:
548 > except:
545 > except:
549 warning: naked except clause
546 warning: naked except clause
550 mercurial/ui.py:0:
547 mercurial/ui.py:0:
551 > traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
548 > traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
552 warning: line over 80 characters
549 warning: line over 80 characters
553 mercurial/url.py:0:
550 mercurial/url.py:0:
554 > conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
551 > conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
555 warning: line over 80 characters
552 warning: line over 80 characters
556 mercurial/util.py:0:
553 mercurial/util.py:0:
557 > except:
554 > except:
558 warning: naked except clause
555 warning: naked except clause
559 mercurial/util.py:0:
556 mercurial/util.py:0:
560 > except:
557 > except:
561 warning: naked except clause
558 warning: naked except clause
562 mercurial/verify.py:0:
559 mercurial/verify.py:0:
563 > except:
560 > except:
564 warning: naked except clause
561 warning: naked except clause
565 mercurial/verify.py:0:
562 mercurial/verify.py:0:
566 > except:
563 > except:
567 warning: naked except clause
564 warning: naked except clause
568 mercurial/wireproto.py:0:
565 mercurial/wireproto.py:0:
569 > # Assuming the future to be filled with the result from the batched request
566 > # Assuming the future to be filled with the result from the batched request
570 warning: line over 80 characters
567 warning: line over 80 characters
571 mercurial/wireproto.py:0:
568 mercurial/wireproto.py:0:
572 > '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
569 > '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
573 warning: line over 80 characters
570 warning: line over 80 characters
574 mercurial/wireproto.py:0:
571 mercurial/wireproto.py:0:
575 > All methods invoked on instances of this class are simply queued and return a
572 > All methods invoked on instances of this class are simply queued and return a
576 warning: line over 80 characters
573 warning: line over 80 characters
577 mercurial/wireproto.py:0:
574 mercurial/wireproto.py:0:
578 > The decorator returns a function which wraps this coroutine as a plain method,
575 > The decorator returns a function which wraps this coroutine as a plain method,
579 warning: line over 80 characters
576 warning: line over 80 characters
580 setup.py:0:
577 setup.py:0:
581 > raise SystemExit("Python headers are required to build Mercurial")
578 > raise SystemExit("Python headers are required to build Mercurial")
582 warning: line over 80 characters
579 warning: line over 80 characters
583 setup.py:0:
580 setup.py:0:
584 > except:
581 > except:
585 warning: naked except clause
582 warning: naked except clause
586 setup.py:0:
583 setup.py:0:
587 > # build_py), it will not find osutil & friends, thinking that those modules are
584 > # build_py), it will not find osutil & friends, thinking that those modules are
588 warning: line over 80 characters
585 warning: line over 80 characters
589 setup.py:0:
586 setup.py:0:
590 > except:
587 > except:
591 warning: naked except clause
588 warning: naked except clause
592 warning: naked except clause
589 warning: naked except clause
593 setup.py:0:
590 setup.py:0:
594 > isironpython = platform.python_implementation().lower().find("ironpython") != -1
591 > isironpython = platform.python_implementation().lower().find("ironpython") != -1
595 warning: line over 80 characters
592 warning: line over 80 characters
596 setup.py:0:
593 setup.py:0:
597 > except:
594 > except:
598 warning: naked except clause
595 warning: naked except clause
599 warning: naked except clause
596 warning: naked except clause
600 warning: naked except clause
597 warning: naked except clause
601 tests/autodiff.py:0:
598 tests/autodiff.py:0:
602 > ui.write('data lost for: %s\n' % fn)
599 > ui.write('data lost for: %s\n' % fn)
603 warning: unwrapped ui message
600 warning: unwrapped ui message
604 tests/run-tests.py:0:
601 tests/run-tests.py:0:
605 > except:
602 > except:
606 warning: naked except clause
603 warning: naked except clause
607 tests/test-commandserver.py:0:
604 tests/test-commandserver.py:0:
608 > 'hooks.pre-identify=python:test-commandserver.hook', 'id'],
605 > 'hooks.pre-identify=python:test-commandserver.hook', 'id'],
609 warning: line over 80 characters
606 warning: line over 80 characters
610 tests/test-commandserver.py:0:
607 tests/test-commandserver.py:0:
611 > # the cached repo local hgrc contains ui.foo=bar, so showconfig should show it
608 > # the cached repo local hgrc contains ui.foo=bar, so showconfig should show it
612 warning: line over 80 characters
609 warning: line over 80 characters
613 tests/test-commandserver.py:0:
610 tests/test-commandserver.py:0:
614 > print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', data))
611 > print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', data))
615 warning: line over 80 characters
612 warning: line over 80 characters
616 tests/test-filecache.py:0:
613 tests/test-filecache.py:0:
617 > except:
614 > except:
618 warning: naked except clause
615 warning: naked except clause
619 tests/test-filecache.py:0:
616 tests/test-filecache.py:0:
620 > if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], 'cacheable']):
617 > if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], 'cacheable']):
621 warning: line over 80 characters
618 warning: line over 80 characters
622 tests/test-ui-color.py:0:
619 tests/test-ui-color.py:0:
623 > testui.warn('warning\n')
620 > testui.warn('warning\n')
624 warning: unwrapped ui message
621 warning: unwrapped ui message
625 tests/test-ui-color.py:0:
622 tests/test-ui-color.py:0:
626 > testui.write('buffered\n')
623 > testui.write('buffered\n')
627 warning: unwrapped ui message
624 warning: unwrapped ui message
628 tests/test-walkrepo.py:0:
625 tests/test-walkrepo.py:0:
629 > print "Found %d repositories when I should have found 2" % (len(reposet),)
626 > print "Found %d repositories when I should have found 2" % (len(reposet),)
630 warning: line over 80 characters
627 warning: line over 80 characters
631 tests/test-walkrepo.py:0:
628 tests/test-walkrepo.py:0:
632 > print "Found %d repositories when I should have found 3" % (len(reposet),)
629 > print "Found %d repositories when I should have found 3" % (len(reposet),)
633 warning: line over 80 characters
630 warning: line over 80 characters
@@ -1,239 +1,283 b''
1 Test that qpush cleans things up if it doesn't complete
1 Test that qpush cleans things up if it doesn't complete
2
2
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
4 $ echo "mq=" >> $HGRCPATH
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ echo foo > foo
7 $ echo foo > foo
8 $ hg ci -Am 'add foo'
8 $ hg ci -Am 'add foo'
9 adding foo
9 adding foo
10 $ touch untracked-file
10 $ touch untracked-file
11 $ echo 'syntax: glob' > .hgignore
11 $ echo 'syntax: glob' > .hgignore
12 $ echo '.hgignore' >> .hgignore
12 $ echo '.hgignore' >> .hgignore
13 $ hg qinit
13 $ hg qinit
14
14
15 test qpush on empty series
15 test qpush on empty series
16
16
17 $ hg qpush
17 $ hg qpush
18 no patches in series
18 no patches in series
19 $ hg qnew patch1
19 $ hg qnew patch1
20 $ echo >> foo
20 $ echo >> foo
21 $ hg qrefresh -m 'patch 1'
21 $ hg qrefresh -m 'patch 1'
22 $ hg qnew patch2
22 $ hg qnew patch2
23 $ echo bar > bar
23 $ echo bar > bar
24 $ hg add bar
24 $ hg add bar
25 $ hg qrefresh -m 'patch 2'
25 $ hg qrefresh -m 'patch 2'
26 $ hg qnew --config 'mq.plain=true' bad-patch
26 $ hg qnew --config 'mq.plain=true' bad-patch
27 $ echo >> foo
27 $ echo >> foo
28 $ hg qrefresh
28 $ hg qrefresh
29 $ hg qpop -a
29 $ hg qpop -a
30 popping bad-patch
30 popping bad-patch
31 popping patch2
31 popping patch2
32 popping patch1
32 popping patch1
33 patch queue now empty
33 patch queue now empty
34 $ python -c 'print "\xe9"' > message
34 $ python -c 'print "\xe9"' > message
35 $ cat .hg/patches/bad-patch >> message
35 $ cat .hg/patches/bad-patch >> message
36 $ mv message .hg/patches/bad-patch
36 $ mv message .hg/patches/bad-patch
37 $ hg qpush -a && echo 'qpush succeded?!'
37 $ hg qpush -a && echo 'qpush succeded?!'
38 applying patch1
38 applying patch1
39 applying patch2
39 applying patch2
40 applying bad-patch
40 applying bad-patch
41 transaction abort!
41 transaction abort!
42 rollback completed
42 rollback completed
43 cleaning up working directory...done
43 cleaning up working directory...done
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
44 abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
45 [255]
45 [255]
46 $ hg parents
46 $ hg parents
47 changeset: 0:bbd179dfa0a7
47 changeset: 0:bbd179dfa0a7
48 tag: tip
48 tag: tip
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:00 1970 +0000
50 date: Thu Jan 01 00:00:00 1970 +0000
51 summary: add foo
51 summary: add foo
52
52
53
53
54 test corrupt status file
54 test corrupt status file
55 $ hg qpush
55 $ hg qpush
56 applying patch1
56 applying patch1
57 now at: patch1
57 now at: patch1
58 $ cp .hg/patches/status .hg/patches/status.orig
58 $ cp .hg/patches/status .hg/patches/status.orig
59 $ hg qpop
59 $ hg qpop
60 popping patch1
60 popping patch1
61 patch queue now empty
61 patch queue now empty
62 $ cp .hg/patches/status.orig .hg/patches/status
62 $ cp .hg/patches/status.orig .hg/patches/status
63 $ hg qpush
63 $ hg qpush
64 mq status file refers to unknown node * (glob)
64 mq status file refers to unknown node * (glob)
65 abort: working directory revision is not qtip
65 abort: working directory revision is not qtip
66 [255]
66 [255]
67 $ rm .hg/patches/status .hg/patches/status.orig
67 $ rm .hg/patches/status .hg/patches/status.orig
68
68
69
69
70 bar should be gone; other unknown/ignored files should still be around
70 bar should be gone; other unknown/ignored files should still be around
71
71
72 $ hg status -A
72 $ hg status -A
73 ? untracked-file
73 ? untracked-file
74 I .hgignore
74 I .hgignore
75 C foo
75 C foo
76
76
77 preparing qpush of a missing patch
77 preparing qpush of a missing patch
78
78
79 $ hg qpop -a
79 $ hg qpop -a
80 no patches applied
80 no patches applied
81 $ hg qpush
81 $ hg qpush
82 applying patch1
82 applying patch1
83 now at: patch1
83 now at: patch1
84 $ rm .hg/patches/patch2
84 $ rm .hg/patches/patch2
85
85
86 now we expect the push to fail, but it should NOT complain about patch1
86 now we expect the push to fail, but it should NOT complain about patch1
87
87
88 $ hg qpush
88 $ hg qpush
89 applying patch2
89 applying patch2
90 unable to read patch2
90 unable to read patch2
91 now at: patch1
91 now at: patch1
92 [1]
92 [1]
93
93
94 preparing qpush of missing patch with no patch applied
94 preparing qpush of missing patch with no patch applied
95
95
96 $ hg qpop -a
96 $ hg qpop -a
97 popping patch1
97 popping patch1
98 patch queue now empty
98 patch queue now empty
99 $ rm .hg/patches/patch1
99 $ rm .hg/patches/patch1
100
100
101 qpush should fail the same way as below
101 qpush should fail the same way as below
102
102
103 $ hg qpush
103 $ hg qpush
104 applying patch1
104 applying patch1
105 unable to read patch1
105 unable to read patch1
106 [1]
106 [1]
107
107
108 Test qpush to a patch below the currently applied patch.
108 Test qpush to a patch below the currently applied patch.
109
109
110 $ hg qq -c guardedseriesorder
110 $ hg qq -c guardedseriesorder
111 $ hg qnew a
111 $ hg qnew a
112 $ hg qguard +block
112 $ hg qguard +block
113 $ hg qnew b
113 $ hg qnew b
114 $ hg qnew c
114 $ hg qnew c
115
115
116 $ hg qpop -a
116 $ hg qpop -a
117 popping c
117 popping c
118 popping b
118 popping b
119 popping a
119 popping a
120 patch queue now empty
120 patch queue now empty
121
121
122 try to push and pop while a is guarded
122 try to push and pop while a is guarded
123
123
124 $ hg qpush a
124 $ hg qpush a
125 cannot push 'a' - guarded by '+block'
125 cannot push 'a' - guarded by '+block'
126 [1]
126 [1]
127 $ hg qpush -a
127 $ hg qpush -a
128 applying b
128 applying b
129 patch b is empty
129 patch b is empty
130 applying c
130 applying c
131 patch c is empty
131 patch c is empty
132 now at: c
132 now at: c
133
133
134 now try it when a is unguarded, and we're at the top of the queue
134 now try it when a is unguarded, and we're at the top of the queue
135 $ hg qsel block
135 $ hg qsel block
136 number of guarded, applied patches has changed from 1 to 0
136 number of guarded, applied patches has changed from 1 to 0
137 $ hg qpush b
137 $ hg qpush b
138 abort: cannot push to a previous patch: b
138 abort: cannot push to a previous patch: b
139 [255]
139 [255]
140 $ hg qpush a
140 $ hg qpush a
141 abort: cannot push to a previous patch: a
141 abort: cannot push to a previous patch: a
142 [255]
142 [255]
143
143
144 and now we try it one more time with a unguarded, while we're not at the top of the queue
144 and now we try it one more time with a unguarded, while we're not at the top of the queue
145
145
146 $ hg qpop b
146 $ hg qpop b
147 popping c
147 popping c
148 now at: b
148 now at: b
149 $ hg qpush a
149 $ hg qpush a
150 abort: cannot push to a previous patch: a
150 abort: cannot push to a previous patch: a
151 [255]
151 [255]
152
152
153 test qpop --force and backup files
153 test qpop --force and backup files
154
154
155 $ hg qpop -a
155 $ hg qpop -a
156 popping b
156 popping b
157 patch queue now empty
157 patch queue now empty
158 $ hg qq --create force
158 $ hg qq --create force
159 $ echo a > a
159 $ echo a > a
160 $ echo b > b
160 $ echo b > b
161 $ echo c > c
161 $ echo c > c
162 $ hg ci -Am add a b c
162 $ hg ci -Am add a b c
163 $ echo a >> a
163 $ echo a >> a
164 $ hg rm b
164 $ hg rm b
165 $ hg rm c
165 $ hg rm c
166 $ hg qnew p1
166 $ hg qnew p1
167 $ echo a >> a
167 $ echo a >> a
168 $ echo bb > b
168 $ echo bb > b
169 $ hg add b
169 $ hg add b
170 $ echo cc > c
170 $ echo cc > c
171 $ hg add c
171 $ hg add c
172 $ hg qpop --force --verbose
172 $ hg qpop --force --verbose
173 saving current version of a as a.orig
173 saving current version of a as a.orig
174 saving current version of b as b.orig
174 saving current version of b as b.orig
175 saving current version of c as c.orig
175 saving current version of c as c.orig
176 popping p1
176 popping p1
177 patch queue now empty
177 patch queue now empty
178 $ hg st
178 $ hg st
179 ? a.orig
179 ? a.orig
180 ? b.orig
180 ? b.orig
181 ? c.orig
181 ? c.orig
182 ? untracked-file
182 ? untracked-file
183 $ cat a.orig
183 $ cat a.orig
184 a
184 a
185 a
185 a
186 a
186 a
187 $ cat b.orig
187 $ cat b.orig
188 bb
188 bb
189 $ cat c.orig
189 $ cat c.orig
190 cc
190 cc
191
191
192 test qpop --force --no-backup
193
194 $ hg qpush
195 applying p1
196 now at: p1
197 $ rm a.orig
198 $ echo a >> a
199 $ hg qpop --force --no-backup --verbose
200 popping p1
201 patch queue now empty
202 $ test -f a.orig && echo 'error: backup with --no-backup'
203 [1]
204
192 test qpush --force and backup files
205 test qpush --force and backup files
193
206
194 $ echo a >> a
207 $ echo a >> a
195 $ hg qnew p2
208 $ hg qnew p2
196 $ echo b >> b
209 $ echo b >> b
197 $ echo d > d
210 $ echo d > d
198 $ echo e > e
211 $ echo e > e
199 $ hg add d e
212 $ hg add d e
200 $ hg rm c
213 $ hg rm c
201 $ hg qnew p3
214 $ hg qnew p3
202 $ hg qpop -a
215 $ hg qpop -a
203 popping p3
216 popping p3
204 popping p2
217 popping p2
205 patch queue now empty
218 patch queue now empty
206 $ echo a >> a
219 $ echo a >> a
207 $ echo b1 >> b
220 $ echo b1 >> b
208 $ echo d1 > d
221 $ echo d1 > d
209 $ hg add d
222 $ hg add d
210 $ echo e1 > e
223 $ echo e1 > e
211 $ hg qpush -a --force --verbose
224 $ hg qpush -a --force --verbose
212 applying p2
225 applying p2
213 saving current version of a as a.orig
226 saving current version of a as a.orig
214 patching file a
227 patching file a
215 a
228 a
216 applying p3
229 applying p3
217 saving current version of b as b.orig
230 saving current version of b as b.orig
218 saving current version of d as d.orig
231 saving current version of d as d.orig
219 patching file b
232 patching file b
220 patching file c
233 patching file c
221 patching file d
234 patching file d
222 file d already exists
235 file d already exists
223 1 out of 1 hunks FAILED -- saving rejects to file d.rej
236 1 out of 1 hunks FAILED -- saving rejects to file d.rej
224 patching file e
237 patching file e
225 file e already exists
238 file e already exists
226 1 out of 1 hunks FAILED -- saving rejects to file e.rej
239 1 out of 1 hunks FAILED -- saving rejects to file e.rej
227 patch failed to apply
240 patch failed to apply
228 b
241 b
229 patch failed, rejects left in working dir
242 patch failed, rejects left in working dir
230 errors during apply, please fix and refresh p3
243 errors during apply, please fix and refresh p3
231 [2]
244 [2]
232 $ cat a.orig
245 $ cat a.orig
233 a
246 a
234 a
247 a
235 $ cat b.orig
248 $ cat b.orig
236 b
249 b
237 b1
250 b1
238 $ cat d.orig
251 $ cat d.orig
239 d1
252 d1
253
254 test qpush --force --no-backup
255
256 $ hg revert -qa
257 $ hg qpop -a
258 popping p3
259 popping p2
260 patch queue now empty
261 $ echo a >> a
262 $ rm a.orig
263 $ hg qpush --force --no-backup --verbose
264 applying p2
265 patching file a
266 a
267 now at: p2
268 $ test -f a.orig && echo 'error: backup with --no-backup'
269 [1]
270
271 test qgoto --force --no-backup
272
273 $ hg qpop
274 popping p2
275 patch queue now empty
276 $ echo a >> a
277 $ hg qgoto --force --no-backup p2 --verbose
278 applying p2
279 patching file a
280 a
281 now at: p2
282 $ test -f a.orig && echo 'error: backup with --no-backup'
283 [1]
General Comments 0
You need to be logged in to leave comments. Login now