##// END OF EJS Templates
merge with mpm.
Vadim Gelfer -
r2920:ef8ee447 merge default
parent child Browse files
Show More
@@ -0,0 +1,68 b''
1 # mail.py - mail sending bits for mercurial
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from i18n import gettext as _
9 from demandload import *
10 demandload(globals(), "os re smtplib templater util")
11
12 def _smtp(ui):
13 '''send mail using smtp.'''
14
15 local_hostname = ui.config('smtp', 'local_hostname')
16 s = smtplib.SMTP(local_hostname=local_hostname)
17 mailhost = ui.config('smtp', 'host')
18 if not mailhost:
19 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
20 mailport = int(ui.config('smtp', 'port', 25))
21 self.note(_('sending mail: smtp host %s, port %s\n') %
22 (mailhost, mailport))
23 s.connect(host=mailhost, port=mailport)
24 if ui.configbool('smtp', 'tls'):
25 ui.note(_('(using tls)\n'))
26 s.ehlo()
27 s.starttls()
28 s.ehlo()
29 username = ui.config('smtp', 'username')
30 password = ui.config('smtp', 'password')
31 if username and password:
32 ui.note(_('(authenticating to mail server as %s)\n') %
33 (username))
34 s.login(username, password)
35 return s
36
37 class _sendmail(object):
38 '''send mail using sendmail.'''
39
40 def __init__(self, ui, program):
41 self.ui = ui
42 self.program = program
43
44 def sendmail(self, sender, recipients, msg):
45 cmdline = '%s -f %s %s' % (
46 self.program, templater.email(sender),
47 ' '.join(map(templater.email, recipients)))
48 self.ui.note(_('sending mail: %s\n') % cmdline)
49 fp = os.popen(cmdline, 'w')
50 fp.write(msg)
51 ret = fp.close()
52 if ret:
53 raise util.Abort('%s %s' % (
54 os.path.basename(self.program.split(None, 1)[0]),
55 util.explain_exit(ret)[0]))
56
57 def connect(ui):
58 '''make a mail connection. object returned has one method, sendmail.
59 call as sendmail(sender, list-of-recipients, msg).'''
60
61 method = ui.config('email', 'method', 'smtp')
62 if method == 'smtp':
63 return smtp(ui)
64
65 return sendmail(ui, method)
66
67 def sendmail(ui, sender, recipients, msg):
68 return connect(ui).sendmail(sender, recipients, msg)
@@ -77,7 +77,7 b' class queue:'
77 77
78 78 def diffopts(self):
79 79 if self._diffopts is None:
80 self._diffopts = self.ui.diffopts()
80 self._diffopts = patch.diffopts(self.ui)
81 81 return self._diffopts
82 82
83 83 def join(self, *p):
@@ -400,15 +400,39 b' class queue:'
400 400 '''Apply patchfile to the working directory.
401 401 patchfile: file name of patch'''
402 402 try:
403 (files, fuzz) = patch.patch(patchfile, self.ui, strip=1,
404 cwd=repo.root)
405 except Exception, inst:
406 self.ui.note(str(inst) + '\n')
407 if not self.ui.verbose:
408 self.ui.warn("patch failed, unable to continue (try -v)\n")
409 return (False, [], False)
403 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
404 f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
405 (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
406 except:
407 self.ui.warn("patch failed, unable to continue (try -v)\n")
408 return (None, [], False)
409 files = []
410 fuzz = False
411 for l in f:
412 l = l.rstrip('\r\n');
413 if self.ui.verbose:
414 self.ui.warn(l + "\n")
415 if l[:14] == 'patching file ':
416 pf = os.path.normpath(util.parse_patch_output(l))
417 if pf not in files:
418 files.append(pf)
419 printed_file = False
420 file_str = l
421 elif l.find('with fuzz') >= 0:
422 if not printed_file:
423 self.ui.warn(file_str + '\n')
424 printed_file = True
425 self.ui.warn(l + '\n')
426 fuzz = True
427 elif l.find('saving rejects to file') >= 0:
428 self.ui.warn(l + '\n')
429 elif l.find('FAILED') >= 0:
430 if not printed_file:
431 self.ui.warn(file_str + '\n')
432 printed_file = True
433 self.ui.warn(l + '\n')
410 434
411 return (True, files.keys(), fuzz)
435 return (not f.close(), files, fuzz)
412 436
413 437 def apply(self, repo, series, list=False, update_status=True,
414 438 strict=False, patchdir=None, merge=None, wlock=None):
@@ -482,28 +506,21 b' class queue:'
482 506 tr.close()
483 507 return (err, n)
484 508
485 def delete(self, repo, patches, keep=False):
486 realpatches = []
487 for patch in patches:
488 patch = self.lookup(patch, strict=True)
489 info = self.isapplied(patch)
490 if info:
491 raise util.Abort(_("cannot delete applied patch %s") % patch)
492 if patch not in self.series:
493 raise util.Abort(_("patch %s not in series file") % patch)
494 realpatches.append(patch)
495
496 if not keep:
509 def delete(self, repo, patch, force=False):
510 patch = self.lookup(patch, strict=True)
511 info = self.isapplied(patch)
512 if info:
513 raise util.Abort(_("cannot delete applied patch %s") % patch)
514 if patch not in self.series:
515 raise util.Abort(_("patch %s not in series file") % patch)
516 if force:
497 517 r = self.qrepo()
498 518 if r:
499 r.remove(realpatches, True)
519 r.remove([patch], True)
500 520 else:
501 521 os.unlink(self.join(patch))
502
503 indices = [self.find_series(p) for p in realpatches]
504 indices.sort()
505 for i in indices[-1::-1]:
506 del self.full_series[i]
522 i = self.find_series(patch)
523 del self.full_series[i]
507 524 self.parse_series()
508 525 self.series_dirty = 1
509 526
@@ -1283,13 +1300,13 b' class queue:'
1283 1300 if qrepo:
1284 1301 qrepo.add(added)
1285 1302
1286 def delete(ui, repo, patch, *patches, **opts):
1287 """remove patches from queue
1303 def delete(ui, repo, patch, **opts):
1304 """remove a patch from the series file
1288 1305
1289 The patches must not be applied.
1290 With -k, the patch files are preserved in the patch directory."""
1306 The patch must not be applied.
1307 With -f, deletes the patch file as well as the series entry."""
1291 1308 q = repo.mq
1292 q.delete(repo, (patch,) + patches, keep=opts.get('keep'))
1309 q.delete(repo, patch, force=opts.get('force'))
1293 1310 q.save_dirty()
1294 1311 return 0
1295 1312
@@ -1447,7 +1464,7 b' def fold(ui, repo, *files, **opts):'
1447 1464 applied to the current patch in the order given. If all the
1448 1465 patches apply successfully, the current patch will be refreshed
1449 1466 with the new cumulative patch, and the folded patches will
1450 be deleted. With -k/--keep, the folded patch files will not
1467 be deleted. With -f/--force, the folded patch files will
1451 1468 be removed afterwards.
1452 1469
1453 1470 The header for each folded patch will be concatenated with
@@ -1497,7 +1514,7 b' def fold(ui, repo, *files, **opts):'
1497 1514 q.refresh(repo, msg=message)
1498 1515
1499 1516 for patch in patches:
1500 q.delete(repo, patch, keep=opts['keep'])
1517 q.delete(repo, patch, force=opts['force'])
1501 1518
1502 1519 q.save_dirty()
1503 1520
@@ -1886,14 +1903,14 b' cmdtable = {'
1886 1903 commands.table["^commit|ci"][1],
1887 1904 'hg qcommit [OPTION]... [FILE]...'),
1888 1905 "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
1889 "qdelete|qremove|qrm":
1906 "qdelete":
1890 1907 (delete,
1891 [('k', 'keep', None, _('keep patch file'))],
1892 'hg qdelete [-k] PATCH'),
1908 [('f', 'force', None, _('delete patch file'))],
1909 'hg qdelete [-f] PATCH'),
1893 1910 'qfold':
1894 1911 (fold,
1895 1912 [('e', 'edit', None, _('edit patch header')),
1896 ('k', 'keep', None, _('keep folded patch files')),
1913 ('f', 'force', None, _('delete folded patch files')),
1897 1914 ('m', 'message', '', _('set patch header to <text>')),
1898 1915 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1899 1916 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
@@ -67,8 +67,8 b''
67 67 from mercurial.demandload import *
68 68 from mercurial.i18n import gettext as _
69 69 from mercurial.node import *
70 demandload(globals(), 'email.Parser mercurial:commands,patch,templater,util')
71 demandload(globals(), 'fnmatch socket time')
70 demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
71 demandload(globals(), 'email.Parser fnmatch socket time')
72 72
73 73 # template for single changeset can include email headers.
74 74 single_template = '''
@@ -229,8 +229,8 b' class notifier(object):'
229 229 else:
230 230 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
231 231 (len(self.subs), count))
232 mail = self.ui.sendmail()
233 mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
232 mail.sendmail(self.ui, templater.email(msg['From']),
233 self.subs, msgtext)
234 234
235 235 def diff(self, node, ref):
236 236 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
@@ -241,7 +241,7 b' def patchbomb(ui, repo, *revs, **opts):'
241 241 ui.write('\n')
242 242
243 243 if not opts['test'] and not opts['mbox']:
244 mail = ui.sendmail()
244 mailer = mail.connect(ui)
245 245 parent = None
246 246
247 247 # Calculate UTC offset
@@ -290,7 +290,7 b' def patchbomb(ui, repo, *revs, **opts):'
290 290 ui.status('Sending ', m['Subject'], ' ...\n')
291 291 # Exim does not remove the Bcc field
292 292 del m['Bcc']
293 mail.sendmail(sender, to + bcc + cc, m.as_string(0))
293 mailer.sendmail(sender, to + bcc + cc, m.as_string(0))
294 294
295 295 cmdtable = {
296 296 'email':
@@ -183,59 +183,49 b' def walkchangerevs(ui, repo, pats, opts)'
183 183 fncache[rev] = matches
184 184 wanted[rev] = 1
185 185
186 class followfilter:
187 def __init__(self, onlyfirst=False):
188 self.startrev = -1
189 self.roots = []
190 self.onlyfirst = onlyfirst
191
192 def match(self, rev):
193 def realparents(rev):
194 if self.onlyfirst:
195 return repo.changelog.parentrevs(rev)[0:1]
186 def iterate():
187 class followfilter:
188 def __init__(self, onlyfirst=False):
189 self.startrev = -1
190 self.roots = []
191 self.onlyfirst = onlyfirst
192
193 def match(self, rev):
194 def realparents(rev):
195 if self.onlyfirst:
196 return repo.changelog.parentrevs(rev)[0:1]
197 else:
198 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
199
200 if self.startrev == -1:
201 self.startrev = rev
202 return True
203
204 if rev > self.startrev:
205 # forward: all descendants
206 if not self.roots:
207 self.roots.append(self.startrev)
208 for parent in realparents(rev):
209 if parent in self.roots:
210 self.roots.append(rev)
211 return True
196 212 else:
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
198
199 if self.startrev == -1:
200 self.startrev = rev
201 return True
202
203 if rev > self.startrev:
204 # forward: all descendants
205 if not self.roots:
206 self.roots.append(self.startrev)
207 for parent in realparents(rev):
208 if parent in self.roots:
209 self.roots.append(rev)
213 # backwards: all parents
214 if not self.roots:
215 self.roots.extend(realparents(self.startrev))
216 if rev in self.roots:
217 self.roots.remove(rev)
218 self.roots.extend(realparents(rev))
210 219 return True
211 else:
212 # backwards: all parents
213 if not self.roots:
214 self.roots.extend(realparents(self.startrev))
215 if rev in self.roots:
216 self.roots.remove(rev)
217 self.roots.extend(realparents(rev))
218 return True
219
220 return False
221
222 # it might be worthwhile to do this in the iterator if the rev range
223 # is descending and the prune args are all within that range
224 for rev in opts.get('prune', ()):
225 rev = repo.changelog.rev(repo.lookup(rev))
226 ff = followfilter()
227 stop = min(revs[0], revs[-1])
228 for x in range(rev, stop-1, -1):
229 if ff.match(x) and wanted.has_key(x):
230 del wanted[x]
231
232 def iterate():
220
221 return False
222
233 223 if follow and not files:
234 224 ff = followfilter(onlyfirst=opts.get('follow_first'))
235 225 def want(rev):
236 if ff.match(rev) and rev in wanted:
237 return True
238 return False
226 if rev not in wanted:
227 return False
228 return ff.match(rev)
239 229 else:
240 230 def want(rev):
241 231 return rev in wanted
@@ -1347,7 +1337,7 b' def diff(ui, repo, *pats, **opts):'
1347 1337 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1348 1338
1349 1339 patch.diff(repo, node1, node2, fns, match=matchfn,
1350 opts=ui.diffopts(opts))
1340 opts=patch.diffopts(ui, opts))
1351 1341
1352 1342 def export(ui, repo, *changesets, **opts):
1353 1343 """dump the header and diffs for one or more changesets
@@ -1384,7 +1374,8 b' def export(ui, repo, *changesets, **opts'
1384 1374 else:
1385 1375 ui.note(_('exporting patch:\n'))
1386 1376 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1387 switch_parent=opts['switch_parent'], opts=ui.diffopts(opts))
1377 switch_parent=opts['switch_parent'],
1378 opts=patch.diffopts(ui, opts))
1388 1379
1389 1380 def forget(ui, repo, *pats, **opts):
1390 1381 """don't add the specified files on the next commit (DEPRECATED)
@@ -1681,7 +1672,7 b' def import_(ui, repo, patch1, *patches, '
1681 1672 message = None
1682 1673 ui.debug(_('message:\n%s\n') % message)
1683 1674
1684 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1675 files = patch.patch(strip, tmpname, ui, cwd=repo.root)
1685 1676 removes = []
1686 1677 if len(files) > 0:
1687 1678 cfiles = files.keys()
@@ -1969,29 +1960,9 b' def merge(ui, repo, node=None, force=Non'
1969 1960 requested revision. Files that changed between either parent are
1970 1961 marked as changed for the next commit and a commit must be
1971 1962 performed before any further updates are allowed.
1972
1973 If no revision is specified, the working directory's parent is a
1974 head revision, and the repository contains exactly one other head,
1975 the other head is merged with by default. Otherwise, an explicit
1976 revision to merge with must be provided.
1977 1963 """
1978 1964
1979 if node:
1980 node = _lookup(repo, node, branch)
1981 else:
1982 heads = repo.heads()
1983 if len(heads) > 2:
1984 raise util.Abort(_('repo has %d heads - '
1985 'please merge with an explicit rev') %
1986 len(heads))
1987 if len(heads) == 1:
1988 raise util.Abort(_('there is nothing to merge - '
1989 'use "hg update" instead'))
1990 parent = repo.dirstate.parents()[0]
1991 if parent not in heads:
1992 raise util.Abort(_('working dir not at a head rev - '
1993 'use "hg update" or merge with an explicit rev'))
1994 node = parent == heads[0] and heads[-1] or heads[0]
1965 node = _lookup(repo, node, branch)
1995 1966 return hg.merge(repo, node, force=force)
1996 1967
1997 1968 def outgoing(ui, repo, dest=None, **opts):
@@ -2897,7 +2868,6 b' table = {'
2897 2868 ('a', 'text', None, _('treat all files as text')),
2898 2869 ('p', 'show-function', None,
2899 2870 _('show which function each change is in')),
2900 ('g', 'git', None, _('use git extended diff format')),
2901 2871 ('w', 'ignore-all-space', None,
2902 2872 _('ignore white space when comparing lines')),
2903 2873 ('b', 'ignore-space-change', None,
@@ -2997,7 +2967,6 b' table = {'
2997 2967 ('', 'style', '', _('display using template map file')),
2998 2968 ('m', 'only-merges', None, _('show only merges')),
2999 2969 ('p', 'patch', None, _('show patch')),
3000 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3001 2970 ('', 'template', '', _('display with template')),
3002 2971 ('I', 'include', [], _('include names matching the given patterns')),
3003 2972 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
@@ -65,26 +65,25 b' class filelog(revlog):'
65 65 return (m["copy"], bin(m["copyrev"]))
66 66 return False
67 67
68 def size(self, rev):
69 """return the size of a given revision"""
70
71 # for revisions with renames, we have to go the slow way
72 node = self.node(rev)
73 if self.renamed(node):
74 return len(self.read(node))
75
76 return revlog.size(self, rev)
77
68 78 def cmp(self, node, text):
69 79 """compare text with a given file revision"""
70 80
71 81 # for renames, we have to go the slow way
72 82 if self.renamed(node):
73 83 t2 = self.read(node)
74 return t2 == text
75
76 p1, p2 = self.parents(node)
77 h = hash(text, p1, p2)
78
79 return h != node
84 return t2 != text
80 85
81 def makenode(self, node, text):
82 """calculate a file nodeid for text, descended or possibly
83 unchanged from node"""
84
85 if self.cmp(node, text):
86 return hash(text, node, nullid)
87 return node
86 return revlog.cmp(self, node, text)
88 87
89 88 def annotate(self, node):
90 89
@@ -11,7 +11,7 b' import os.path'
11 11 import mimetypes
12 12 from mercurial.demandload import demandload
13 13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone")
14 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
15 15 demandload(globals(), "mercurial:templater")
16 16 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
17 17 from mercurial.node import *
@@ -134,7 +134,7 b' class hgweb(object):'
134 134 modified, added, removed = map(lambda x: filterfiles(files, x),
135 135 (modified, added, removed))
136 136
137 diffopts = self.repo.ui.diffopts()
137 diffopts = patch.diffopts(ui)
138 138 for f in modified:
139 139 to = r.file(f).read(mmap1[f])
140 140 tn = r.file(f).read(mmap2[f])
@@ -10,6 +10,11 b' from i18n import gettext as _'
10 10 from demandload import *
11 11 demandload(globals(), "util os tempfile")
12 12
13 def fmerge(f, local, other, ancestor):
14 """merge executable flags"""
15 a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
16 return ((a^b) | (a^c)) ^ a
17
13 18 def merge3(repo, fn, my, other, p1, p2):
14 19 """perform a 3-way merge in the working directory"""
15 20
@@ -90,9 +95,7 b' def update(repo, node, branchmerge=False'
90 95 if not force:
91 96 for f in unknown:
92 97 if f in m2:
93 t1 = repo.wread(f)
94 t2 = repo.file(f).read(m2[f])
95 if cmp(t1, t2) != 0:
98 if repo.file(f).cmp(m2[f], repo.wread(f)):
96 99 raise util.Abort(_("'%s' already exists in the working"
97 100 " dir and differs from remote") % f)
98 101
@@ -100,13 +103,14 b' def update(repo, node, branchmerge=False'
100 103 # we care about merging
101 104 repo.ui.note(_("resolving manifests\n"))
102 105 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
103 (overwrite, branchmerge, partial and True or False, linear_path))
106 (overwrite, branchmerge, bool(partial), linear_path))
104 107 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
105 108 (short(man), short(m1n), short(m2n)))
106 109
107 110 merge = {}
108 111 get = {}
109 112 remove = []
113 forget = []
110 114
111 115 # construct a working dir manifest
112 116 mw = m1.copy()
@@ -114,6 +118,11 b' def update(repo, node, branchmerge=False'
114 118
115 119 for f in added + modified + unknown:
116 120 mw[f] = ""
121 # is the wfile new and matches m2?
122 if (f not in m1 and f in m2 and
123 not repo.file(f).cmp(m2[f], repo.wread(f))):
124 mw[f] = m2[f]
125
117 126 mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
118 127
119 128 for f in deleted + removed:
@@ -125,8 +134,8 b' def update(repo, node, branchmerge=False'
125 134 # the file, then we need to remove it from the dirstate, to
126 135 # prevent the dirstate from listing the file when it is no
127 136 # longer in the manifest.
128 if not partial and linear_path and f not in m2:
129 repo.dirstate.forget((f,))
137 if linear_path and f not in m2:
138 forget.append(f)
130 139
131 140 # Compare manifests
132 141 for f, n in mw.iteritems():
@@ -135,25 +144,13 b' def update(repo, node, branchmerge=False'
135 144 if f in m2:
136 145 s = 0
137 146
138 # is the wfile new since m1, and match m2?
139 if f not in m1:
140 t1 = repo.wread(f)
141 t2 = repo.file(f).read(m2[f])
142 if cmp(t1, t2) == 0:
143 n = m2[f]
144 del t1, t2
145
146 147 # are files different?
147 148 if n != m2[f]:
148 149 a = ma.get(f, nullid)
149 150 # are both different from the ancestor?
150 151 if n != a and m2[f] != a:
151 152 repo.ui.debug(_(" %s versions differ, resolve\n") % f)
152 # merge executable bits
153 # "if we changed or they changed, change in merge"
154 a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
155 mode = ((a^b) | (a^c)) ^ a
156 merge[f] = (mode, m1.get(f, nullid), m2[f])
153 merge[f] = (fmerge(f, mw, m2, ma), m1.get(f, nullid), m2[f])
157 154 s = 1
158 155 # are we clobbering?
159 156 # is remote's version newer?
@@ -172,9 +169,7 b' def update(repo, node, branchmerge=False'
172 169 repo.ui.debug(_(" updating permissions for %s\n") % f)
173 170 util.set_exec(repo.wjoin(f), m2.execf(f))
174 171 else:
175 a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
176 mode = ((a^b) | (a^c)) ^ a
177 if mode != b:
172 if fmerge(f, mw, m2, ma) != mw.execf(f):
178 173 repo.ui.debug(_(" updating permissions for %s\n")
179 174 % f)
180 175 util.set_exec(repo.wjoin(f), mode)
@@ -230,6 +225,8 b' def update(repo, node, branchmerge=False'
230 225
231 226 del mw, m1, m2, ma
232 227
228 ### apply phase
229
233 230 if overwrite:
234 231 for f in merge:
235 232 get[f] = merge[f][:2]
@@ -257,11 +254,6 b' def update(repo, node, branchmerge=False'
257 254 t = repo.file(f).read(node)
258 255 repo.wwrite(f, t)
259 256 util.set_exec(repo.wjoin(f), flag)
260 if not partial:
261 if branchmerge:
262 repo.dirstate.update([f], 'n', st_mtime=-1)
263 else:
264 repo.dirstate.update([f], 'n')
265 257
266 258 # merge the tricky bits
267 259 unresolved = []
@@ -274,19 +266,6 b' def update(repo, node, branchmerge=False'
274 266 if ret:
275 267 unresolved.append(f)
276 268 util.set_exec(repo.wjoin(f), flag)
277 if not partial:
278 if branchmerge:
279 # We've done a branch merge, mark this file as merged
280 # so that we properly record the merger later
281 repo.dirstate.update([f], 'm')
282 else:
283 # We've update-merged a locally modified file, so
284 # we set the dirstate to emulate a normal checkout
285 # of that file some time in the past. Thus our
286 # merge will appear as a normal local file
287 # modification.
288 f_len = len(repo.file(f).read(other))
289 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
290 269
291 270 remove.sort()
292 271 for f in remove:
@@ -298,14 +277,40 b' def update(repo, node, branchmerge=False'
298 277 if inst.errno != errno.ENOENT:
299 278 repo.ui.warn(_("update failed to remove %s: %s!\n") %
300 279 (f, inst.strerror))
280
281 # update dirstate
301 282 if not partial:
283 repo.dirstate.setparents(p1, p2)
284 repo.dirstate.forget(forget)
302 285 if branchmerge:
303 286 repo.dirstate.update(remove, 'r')
304 287 else:
305 288 repo.dirstate.forget(remove)
306 289
307 if not partial:
308 repo.dirstate.setparents(p1, p2)
290 files = get.keys()
291 files.sort()
292 for f in files:
293 if branchmerge:
294 repo.dirstate.update([f], 'n', st_mtime=-1)
295 else:
296 repo.dirstate.update([f], 'n')
297
298 files = merge.keys()
299 files.sort()
300 for f in files:
301 if branchmerge:
302 # We've done a branch merge, mark this file as merged
303 # so that we properly record the merger later
304 repo.dirstate.update([f], 'm')
305 else:
306 # We've update-merged a locally modified file, so
307 # we set the dirstate to emulate a normal checkout
308 # of that file some time in the past. Thus our
309 # merge will appear as a normal local file
310 # modification.
311 fl = repo.file(f)
312 f_len = fl.size(fl.rev(other))
313 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
309 314
310 315 if show_stats:
311 316 stats = ((len(get), _("updated")),
@@ -215,14 +215,13 b' def dogitpatch(patchname, gitpatches):'
215 215 tmpfp.close()
216 216 return patchname
217 217
218 def patch(patchname, ui, strip=1, cwd=None):
218 def patch(strip, patchname, ui, cwd=None):
219 219 """apply the patch <patchname> to the working directory.
220 220 a list of patched files is returned"""
221 221
222 222 (dopatch, gitpatches) = readgitpatch(patchname)
223 223
224 224 files = {}
225 fuzz = False
226 225 if dopatch:
227 226 if dopatch == 'filter':
228 227 patchname = dogitpatch(patchname, gitpatches)
@@ -238,25 +237,10 b' def patch(patchname, ui, strip=1, cwd=No'
238 237
239 238 for line in fp:
240 239 line = line.rstrip()
241 ui.note(line + '\n')
240 ui.status("%s\n" % line)
242 241 if line.startswith('patching file '):
243 242 pf = util.parse_patch_output(line)
244 printed_file = False
245 243 files.setdefault(pf, (None, None))
246 elif line.find('with fuzz') >= 0:
247 fuzz = True
248 if not printed_file:
249 ui.warn(pf + '\n')
250 printed_file = True
251 ui.warn(line + '\n')
252 elif line.find('saving rejects to file') >= 0:
253 ui.warn(line + '\n')
254 elif line.find('FAILED') >= 0:
255 if not printed_file:
256 ui.warn(pf + '\n')
257 printed_file = True
258 ui.warn(line + '\n')
259
260 244 code = fp.close()
261 245 if code:
262 246 raise util.Abort(_("patch command failed: %s") %
@@ -265,7 +249,19 b' def patch(patchname, ui, strip=1, cwd=No'
265 249 for gp in gitpatches:
266 250 files[gp.path] = (gp.op, gp)
267 251
268 return (files, fuzz)
252 return files
253
254 def diffopts(ui, opts={}):
255 return mdiff.diffopts(
256 text=opts.get('text'),
257 showfunc=(opts.get('show_function') or
258 ui.configbool('diff', 'showfunc', None)),
259 ignorews=(opts.get('ignore_all_space') or
260 ui.configbool('diff', 'ignorews', None)),
261 ignorewsamount=(opts.get('ignore_space_change') or
262 ui.configbool('diff', 'ignorewsamount', None)),
263 ignoreblanklines=(opts.get('ignore_blank_lines') or
264 ui.configbool('diff', 'ignoreblanklines', None)))
269 265
270 266 def diff(repo, node1=None, node2=None, files=None, match=util.always,
271 267 fp=None, changes=None, opts=None):
@@ -314,9 +310,6 b' def diff(repo, node1=None, node2=None, f'
314 310 return _date2
315 311 def read(f):
316 312 return repo.file(f).read(mmap2[f])
317 def renamed(f):
318 src = repo.file(f).renamed(mmap2[f])
319 return src and src[0] or None
320 313 else:
321 314 tz = util.makedate()[1]
322 315 _date2 = util.datestr()
@@ -328,8 +321,6 b' def diff(repo, node1=None, node2=None, f'
328 321 return _date2
329 322 def read(f):
330 323 return repo.wread(f)
331 def renamed(f):
332 return repo.dirstate.copies.get(f)
333 324
334 325 if repo.ui.quiet:
335 326 r = None
@@ -337,65 +328,16 b' def diff(repo, node1=None, node2=None, f'
337 328 hexfunc = repo.ui.verbose and hex or short
338 329 r = [hexfunc(node) for node in [node1, node2] if node]
339 330
340 if opts.git:
341 copied = {}
342 for f in added:
343 src = renamed(f)
344 if src:
345 copied[f] = src
346 srcs = [x[1] for x in copied.items()]
347
348 331 all = modified + added + removed
349 332 all.sort()
350 333 for f in all:
351 334 to = None
352 335 tn = None
353 dodiff = True
354 336 if f in mmap:
355 337 to = repo.file(f).read(mmap[f])
356 338 if f not in removed:
357 339 tn = read(f)
358 if opts.git:
359 def gitmode(x):
360 return x and '100755' or '100644'
361 def addmodehdr(header, omode, nmode):
362 if omode != nmode:
363 header.append('old mode %s\n' % omode)
364 header.append('new mode %s\n' % nmode)
365
366 a, b = f, f
367 header = []
368 if f in added:
369 if node2:
370 mode = gitmode(mmap2.execf(f))
371 else:
372 mode = gitmode(util.is_exec(repo.wjoin(f), None))
373 if f in copied:
374 a = copied[f]
375 omode = gitmode(mmap.execf(a))
376 addmodehdr(header, omode, mode)
377 op = a in removed and 'rename' or 'copy'
378 header.append('%s from %s\n' % (op, a))
379 header.append('%s to %s\n' % (op, f))
380 to = repo.file(a).read(mmap[a])
381 else:
382 header.append('new file mode %s\n' % mode)
383 elif f in removed:
384 if f in srcs:
385 dodiff = False
386 else:
387 mode = gitmode(mmap.execf(f))
388 header.append('deleted file mode %s\n' % mode)
389 else:
390 omode = gitmode(mmap.execf(f))
391 nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
392 addmodehdr(header, omode, nmode)
393 r = None
394 if dodiff:
395 header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
396 fp.write(''.join(header))
397 if dodiff:
398 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts))
340 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts))
399 341
400 342 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
401 343 opts=None):
@@ -766,6 +766,19 b' class revlog(object):'
766 766
767 767 raise RevlogError(_("No match found"))
768 768
769 def cmp(self, node, text):
770 """compare text with a given file revision"""
771 p1, p2 = self.parents(node)
772 return hash(text, p1, p2) != node
773
774 def makenode(self, node, text):
775 """calculate a file nodeid for text, descended or possibly
776 unchanged from node"""
777
778 if self.cmp(node, text):
779 return hash(text, node, nullid)
780 return node
781
769 782 def diff(self, a, b):
770 783 """return a delta between two revisions"""
771 784 return mdiff.textdiff(a, b)
@@ -7,7 +7,7 b''
7 7
8 8 from i18n import gettext as _
9 9 from demandload import *
10 demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
10 demandload(globals(), "errno getpass os re socket sys tempfile")
11 11 demandload(globals(), "ConfigParser mdiff templater traceback util")
12 12
13 13 class ui(object):
@@ -169,20 +169,6 b' class ui(object):'
169 169 result[key.lower()] = value
170 170 return result
171 171
172 def diffopts(self, opts={}):
173 return mdiff.diffopts(
174 text=opts.get('text'),
175 showfunc=(opts.get('show_function') or
176 self.configbool('diff', 'showfunc', None)),
177 git=(opts.get('git') or
178 self.configbool('diff', 'git', None)),
179 ignorews=(opts.get('ignore_all_space') or
180 self.configbool('diff', 'ignorews', None)),
181 ignorewsamount=(opts.get('ignore_space_change') or
182 self.configbool('diff', 'ignorewsamount', None)),
183 ignoreblanklines=(opts.get('ignore_blank_lines') or
184 self.configbool('diff', 'ignoreblanklines', None)))
185
186 172 def username(self):
187 173 """Return default username to be used in commits.
188 174
@@ -295,62 +281,6 b' class ui(object):'
295 281
296 282 return t
297 283
298 def sendmail(self):
299 '''send mail message. object returned has one method, sendmail.
300 call as sendmail(sender, list-of-recipients, msg).'''
301
302 def smtp():
303 '''send mail using smtp.'''
304
305 local_hostname = self.config('smtp', 'local_hostname')
306 s = smtplib.SMTP(local_hostname=local_hostname)
307 mailhost = self.config('smtp', 'host')
308 if not mailhost:
309 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
310 mailport = int(self.config('smtp', 'port', 25))
311 self.note(_('sending mail: smtp host %s, port %s\n') %
312 (mailhost, mailport))
313 s.connect(host=mailhost, port=mailport)
314 if self.configbool('smtp', 'tls'):
315 self.note(_('(using tls)\n'))
316 s.ehlo()
317 s.starttls()
318 s.ehlo()
319 username = self.config('smtp', 'username')
320 password = self.config('smtp', 'password')
321 if username and password:
322 self.note(_('(authenticating to mail server as %s)\n') %
323 (username))
324 s.login(username, password)
325 return s
326
327 class sendmail(object):
328 '''send mail using sendmail.'''
329
330 def __init__(self, ui, program):
331 self.ui = ui
332 self.program = program
333
334 def sendmail(self, sender, recipients, msg):
335 cmdline = '%s -f %s %s' % (
336 self.program, templater.email(sender),
337 ' '.join(map(templater.email, recipients)))
338 self.ui.note(_('sending mail: %s\n') % cmdline)
339 fp = os.popen(cmdline, 'w')
340 fp.write(msg)
341 ret = fp.close()
342 if ret:
343 raise util.Abort('%s %s' % (
344 os.path.basename(self.program.split(None, 1)[0]),
345 util.explain_exit(ret)[0]))
346
347 method = self.config('email', 'method', 'smtp')
348 if method == 'smtp':
349 mail = smtp()
350 else:
351 mail = sendmail(self, method)
352 return mail
353
354 284 def print_exc(self):
355 285 '''print exception traceback if traceback printing enabled.
356 286 only to call in exception handler. returns true if traceback
General Comments 0
You need to be logged in to leave comments. Login now