changeset 2921:addb58e3b41c

redo merge with mpm. previous merge at ef8ee4477019 was bad.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Wed, 16 Aug 2006 10:52:19 -0700
parents b70740aefa4d (current diff) 8743188f4d2e (diff)
children 773c5b82d052
files hgext/mq.py mercurial/commands.py mercurial/hgweb/hgweb_mod.py mercurial/patch.py mercurial/ui.py
diffstat 11 files changed, 167 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/mq.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/hgext/mq.py	Wed Aug 16 10:52:19 2006 -0700
@@ -77,7 +77,7 @@
 
     def diffopts(self):
         if self._diffopts is None:
-            self._diffopts = self.ui.diffopts()
+            self._diffopts = patch.diffopts(self.ui)
         return self._diffopts
 
     def join(self, *p):
--- a/hgext/notify.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/hgext/notify.py	Wed Aug 16 10:52:19 2006 -0700
@@ -67,8 +67,8 @@
 from mercurial.demandload import *
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'email.Parser mercurial:commands,patch,templater,util')
-demandload(globals(), 'fnmatch socket time')
+demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
+demandload(globals(), 'email.Parser fnmatch socket time')
 
 # template for single changeset can include email headers.
 single_template = '''
@@ -229,8 +229,8 @@
         else:
             self.ui.status(_('notify: sending %d subscribers %d changes\n') %
                              (len(self.subs), count))
-            mail = self.ui.sendmail()
-            mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
+            mail.sendmail(self.ui, templater.email(msg['From']),
+                          self.subs, msgtext)
 
     def diff(self, node, ref):
         maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
--- a/hgext/patchbomb.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/hgext/patchbomb.py	Wed Aug 16 10:52:19 2006 -0700
@@ -241,7 +241,7 @@
     ui.write('\n')
 
     if not opts['test'] and not opts['mbox']:
-        mail = ui.sendmail()
+        mailer = mail.connect(ui)
     parent = None
 
     # Calculate UTC offset
@@ -290,7 +290,7 @@
             ui.status('Sending ', m['Subject'], ' ...\n')
             # Exim does not remove the Bcc field
             del m['Bcc']
-            mail.sendmail(sender, to + bcc + cc, m.as_string(0))
+            mailer.sendmail(sender, to + bcc + cc, m.as_string(0))
 
 cmdtable = {
     'email':
--- a/mercurial/commands.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/commands.py	Wed Aug 16 10:52:19 2006 -0700
@@ -1347,7 +1347,7 @@
     fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
 
     patch.diff(repo, node1, node2, fns, match=matchfn,
-               opts=ui.diffopts(opts))
+               opts=patch.diffopts(ui, opts))
 
 def export(ui, repo, *changesets, **opts):
     """dump the header and diffs for one or more changesets
@@ -1384,7 +1384,8 @@
     else:
         ui.note(_('exporting patch:\n'))
     patch.export(repo, map(repo.lookup, revs), template=opts['output'],
-                 switch_parent=opts['switch_parent'], opts=ui.diffopts(opts))
+                 switch_parent=opts['switch_parent'],
+                 opts=patch.diffopts(ui, opts))
 
 def forget(ui, repo, *pats, **opts):
     """don't add the specified files on the next commit (DEPRECATED)
--- a/mercurial/filelog.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/filelog.py	Wed Aug 16 10:52:19 2006 -0700
@@ -65,26 +65,25 @@
             return (m["copy"], bin(m["copyrev"]))
         return False
 
+    def size(self, rev):
+        """return the size of a given revision"""
+
+        # for revisions with renames, we have to go the slow way
+        node = self.node(rev)
+        if self.renamed(node):
+            return len(self.read(node))
+
+        return revlog.size(self, rev)
+
     def cmp(self, node, text):
         """compare text with a given file revision"""
 
         # for renames, we have to go the slow way
         if self.renamed(node):
             t2 = self.read(node)
-            return t2 == text
-
-        p1, p2 = self.parents(node)
-        h = hash(text, p1, p2)
-
-        return h != node
+            return t2 != text
 
-    def makenode(self, node, text):
-        """calculate a file nodeid for text, descended or possibly
-        unchanged from node"""
-
-        if self.cmp(node, text):
-            return hash(text, node, nullid)
-        return node
+        return revlog.cmp(self, node, text)
 
     def annotate(self, node):
 
--- a/mercurial/hgweb/hgweb_mod.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/hgweb/hgweb_mod.py	Wed Aug 16 10:52:19 2006 -0700
@@ -11,7 +11,7 @@
 import mimetypes
 from mercurial.demandload import demandload
 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
-demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone")
+demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
 demandload(globals(), "mercurial:templater")
 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
 from mercurial.node import *
@@ -134,7 +134,7 @@
             modified, added, removed = map(lambda x: filterfiles(files, x),
                                            (modified, added, removed))
 
-        diffopts = self.repo.ui.diffopts()
+        diffopts = patch.diffopts(ui)
         for f in modified:
             to = r.file(f).read(mmap1[f])
             tn = r.file(f).read(mmap2[f])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/mail.py	Wed Aug 16 10:52:19 2006 -0700
@@ -0,0 +1,68 @@
+# mail.py - mail sending bits for mercurial
+#
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from i18n import gettext as _
+from demandload import *
+demandload(globals(), "os re smtplib templater util")
+
+def _smtp(ui):
+    '''send mail using smtp.'''
+
+    local_hostname = ui.config('smtp', 'local_hostname')
+    s = smtplib.SMTP(local_hostname=local_hostname)
+    mailhost = ui.config('smtp', 'host')
+    if not mailhost:
+        raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
+    mailport = int(ui.config('smtp', 'port', 25))
+    self.note(_('sending mail: smtp host %s, port %s\n') %
+              (mailhost, mailport))
+    s.connect(host=mailhost, port=mailport)
+    if ui.configbool('smtp', 'tls'):
+        ui.note(_('(using tls)\n'))
+        s.ehlo()
+        s.starttls()
+        s.ehlo()
+    username = ui.config('smtp', 'username')
+    password = ui.config('smtp', 'password')
+    if username and password:
+        ui.note(_('(authenticating to mail server as %s)\n') %
+                  (username))
+        s.login(username, password)
+    return s
+
+class _sendmail(object):
+    '''send mail using sendmail.'''
+
+    def __init__(self, ui, program):
+        self.ui = ui
+        self.program = program
+
+    def sendmail(self, sender, recipients, msg):
+        cmdline = '%s -f %s %s' % (
+            self.program, templater.email(sender),
+            ' '.join(map(templater.email, recipients)))
+        self.ui.note(_('sending mail: %s\n') % cmdline)
+        fp = os.popen(cmdline, 'w')
+        fp.write(msg)
+        ret = fp.close()
+        if ret:
+            raise util.Abort('%s %s' % (
+                os.path.basename(self.program.split(None, 1)[0]),
+                util.explain_exit(ret)[0]))
+
+def connect(ui):
+    '''make a mail connection. object returned has one method, sendmail.
+    call as sendmail(sender, list-of-recipients, msg).'''
+
+    method = ui.config('email', 'method', 'smtp')
+    if method == 'smtp':
+        return smtp(ui)
+
+    return sendmail(ui, method)
+
+def sendmail(ui, sender, recipients, msg):
+    return connect(ui).sendmail(sender, recipients, msg)
--- a/mercurial/merge.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/merge.py	Wed Aug 16 10:52:19 2006 -0700
@@ -10,6 +10,11 @@
 from demandload import *
 demandload(globals(), "util os tempfile")
 
+def fmerge(f, local, other, ancestor):
+    """merge executable flags"""
+    a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
+    return ((a^b) | (a^c)) ^ a
+
 def merge3(repo, fn, my, other, p1, p2):
     """perform a 3-way merge in the working directory"""
 
@@ -90,9 +95,7 @@
     if not force:
         for f in unknown:
             if f in m2:
-                t1 = repo.wread(f)
-                t2 = repo.file(f).read(m2[f])
-                if cmp(t1, t2) != 0:
+                if repo.file(f).cmp(m2[f], repo.wread(f)):
                     raise util.Abort(_("'%s' already exists in the working"
                                        " dir and differs from remote") % f)
 
@@ -100,13 +103,14 @@
     # we care about merging
     repo.ui.note(_("resolving manifests\n"))
     repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
-                  (overwrite, branchmerge, partial and True or False, linear_path))
+                  (overwrite, branchmerge, bool(partial), linear_path))
     repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
                   (short(man), short(m1n), short(m2n)))
 
     merge = {}
     get = {}
     remove = []
+    forget = []
 
     # construct a working dir manifest
     mw = m1.copy()
@@ -114,6 +118,11 @@
 
     for f in added + modified + unknown:
         mw[f] = ""
+        # is the wfile new and matches m2?
+        if (f not in m1 and f in m2 and
+            not repo.file(f).cmp(m2[f], repo.wread(f))):
+            mw[f] = m2[f]
+
         mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
 
     for f in deleted + removed:
@@ -125,8 +134,8 @@
         # the file, then we need to remove it from the dirstate, to
         # prevent the dirstate from listing the file when it is no
         # longer in the manifest.
-        if not partial and linear_path and f not in m2:
-            repo.dirstate.forget((f,))
+        if linear_path and f not in m2:
+            forget.append(f)
 
     # Compare manifests
     for f, n in mw.iteritems():
@@ -135,25 +144,13 @@
         if f in m2:
             s = 0
 
-            # is the wfile new since m1, and match m2?
-            if f not in m1:
-                t1 = repo.wread(f)
-                t2 = repo.file(f).read(m2[f])
-                if cmp(t1, t2) == 0:
-                    n = m2[f]
-                del t1, t2
-
             # are files different?
             if n != m2[f]:
                 a = ma.get(f, nullid)
                 # are both different from the ancestor?
                 if n != a and m2[f] != a:
                     repo.ui.debug(_(" %s versions differ, resolve\n") % f)
-                    # merge executable bits
-                    # "if we changed or they changed, change in merge"
-                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
-                    mode = ((a^b) | (a^c)) ^ a
-                    merge[f] = (mode, m1.get(f, nullid), m2[f])
+                    merge[f] = (fmerge(f, mw, m2, ma), m1.get(f, nullid), m2[f])
                     s = 1
                 # are we clobbering?
                 # is remote's version newer?
@@ -172,9 +169,7 @@
                     repo.ui.debug(_(" updating permissions for %s\n") % f)
                     util.set_exec(repo.wjoin(f), m2.execf(f))
                 else:
-                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
-                    mode = ((a^b) | (a^c)) ^ a
-                    if mode != b:
+                    if fmerge(f, mw, m2, ma) != mw.execf(f):
                         repo.ui.debug(_(" updating permissions for %s\n")
                                       % f)
                         util.set_exec(repo.wjoin(f), mode)
@@ -230,6 +225,8 @@
 
     del mw, m1, m2, ma
 
+    ### apply phase
+
     if overwrite:
         for f in merge:
             get[f] = merge[f][:2]
@@ -257,11 +254,6 @@
         t = repo.file(f).read(node)
         repo.wwrite(f, t)
         util.set_exec(repo.wjoin(f), flag)
-        if not partial:
-            if branchmerge:
-                repo.dirstate.update([f], 'n', st_mtime=-1)
-            else:
-                repo.dirstate.update([f], 'n')
 
     # merge the tricky bits
     unresolved = []
@@ -274,19 +266,6 @@
         if ret:
             unresolved.append(f)
         util.set_exec(repo.wjoin(f), flag)
-        if not partial:
-            if branchmerge:
-                # We've done a branch merge, mark this file as merged
-                # so that we properly record the merger later
-                repo.dirstate.update([f], 'm')
-            else:
-                # We've update-merged a locally modified file, so
-                # we set the dirstate to emulate a normal checkout
-                # of that file some time in the past. Thus our
-                # merge will appear as a normal local file
-                # modification.
-                f_len = len(repo.file(f).read(other))
-                repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
 
     remove.sort()
     for f in remove:
@@ -298,14 +277,40 @@
             if inst.errno != errno.ENOENT:
                 repo.ui.warn(_("update failed to remove %s: %s!\n") %
                              (f, inst.strerror))
+
+    # update dirstate
     if not partial:
+        repo.dirstate.setparents(p1, p2)
+        repo.dirstate.forget(forget)
         if branchmerge:
             repo.dirstate.update(remove, 'r')
         else:
             repo.dirstate.forget(remove)
 
-    if not partial:
-        repo.dirstate.setparents(p1, p2)
+        files = get.keys()
+        files.sort()
+        for f in files:
+            if branchmerge:
+                repo.dirstate.update([f], 'n', st_mtime=-1)
+            else:
+                repo.dirstate.update([f], 'n')
+
+        files = merge.keys()
+        files.sort()
+        for f in files:
+            if branchmerge:
+                # We've done a branch merge, mark this file as merged
+                # so that we properly record the merger later
+                repo.dirstate.update([f], 'm')
+            else:
+                # We've update-merged a locally modified file, so
+                # we set the dirstate to emulate a normal checkout
+                # of that file some time in the past. Thus our
+                # merge will appear as a normal local file
+                # modification.
+                fl = repo.file(f)
+                f_len = fl.size(fl.rev(other))
+                repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
 
     if show_stats:
         stats = ((len(get), _("updated")),
--- a/mercurial/patch.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/patch.py	Wed Aug 16 10:52:19 2006 -0700
@@ -267,6 +267,20 @@
 
     return (files, fuzz)
 
+def diffopts(ui, opts={}):
+    return mdiff.diffopts(
+        text=opts.get('text'),
+        git=(opts.get('git') or
+                  ui.configbool('diff', 'git', None)),
+        showfunc=(opts.get('show_function') or
+                  ui.configbool('diff', 'showfunc', None)),
+        ignorews=(opts.get('ignore_all_space') or
+                  ui.configbool('diff', 'ignorews', None)),
+        ignorewsamount=(opts.get('ignore_space_change') or
+                        ui.configbool('diff', 'ignorewsamount', None)),
+        ignoreblanklines=(opts.get('ignore_blank_lines') or
+                          ui.configbool('diff', 'ignoreblanklines', None)))
+
 def diff(repo, node1=None, node2=None, files=None, match=util.always,
          fp=None, changes=None, opts=None):
     '''print diff of changes to files between two nodes, or node and
--- a/mercurial/revlog.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/revlog.py	Wed Aug 16 10:52:19 2006 -0700
@@ -766,6 +766,19 @@
 
         raise RevlogError(_("No match found"))
 
+    def cmp(self, node, text):
+        """compare text with a given file revision"""
+        p1, p2 = self.parents(node)
+        return hash(text, p1, p2) != node
+
+    def makenode(self, node, text):
+        """calculate a file nodeid for text, descended or possibly
+        unchanged from node"""
+
+        if self.cmp(node, text):
+            return hash(text, node, nullid)
+        return node
+
     def diff(self, a, b):
         """return a delta between two revisions"""
         return mdiff.textdiff(a, b)
--- a/mercurial/ui.py	Tue Aug 15 11:28:50 2006 -0700
+++ b/mercurial/ui.py	Wed Aug 16 10:52:19 2006 -0700
@@ -7,7 +7,7 @@
 
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
+demandload(globals(), "errno getpass os re socket sys tempfile")
 demandload(globals(), "ConfigParser mdiff templater traceback util")
 
 class ui(object):
@@ -169,20 +169,6 @@
             result[key.lower()] = value
         return result
 
-    def diffopts(self, opts={}):
-        return mdiff.diffopts(
-            text=opts.get('text'),
-            showfunc=(opts.get('show_function') or
-                      self.configbool('diff', 'showfunc', None)),
-            git=(opts.get('git') or
-                 self.configbool('diff', 'git', None)),
-            ignorews=(opts.get('ignore_all_space') or
-                      self.configbool('diff', 'ignorews', None)),
-            ignorewsamount=(opts.get('ignore_space_change') or
-                            self.configbool('diff', 'ignorewsamount', None)),
-            ignoreblanklines=(opts.get('ignore_blank_lines') or
-                              self.configbool('diff', 'ignoreblanklines', None)))
-
     def username(self):
         """Return default username to be used in commits.
 
@@ -295,62 +281,6 @@
 
         return t
 
-    def sendmail(self):
-        '''send mail message. object returned has one method, sendmail.
-        call as sendmail(sender, list-of-recipients, msg).'''
-
-        def smtp():
-            '''send mail using smtp.'''
-
-            local_hostname = self.config('smtp', 'local_hostname')
-            s = smtplib.SMTP(local_hostname=local_hostname)
-            mailhost = self.config('smtp', 'host')
-            if not mailhost:
-                raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
-            mailport = int(self.config('smtp', 'port', 25))
-            self.note(_('sending mail: smtp host %s, port %s\n') %
-                      (mailhost, mailport))
-            s.connect(host=mailhost, port=mailport)
-            if self.configbool('smtp', 'tls'):
-                self.note(_('(using tls)\n'))
-                s.ehlo()
-                s.starttls()
-                s.ehlo()
-            username = self.config('smtp', 'username')
-            password = self.config('smtp', 'password')
-            if username and password:
-                self.note(_('(authenticating to mail server as %s)\n') %
-                          (username))
-                s.login(username, password)
-            return s
-
-        class sendmail(object):
-            '''send mail using sendmail.'''
-
-            def __init__(self, ui, program):
-                self.ui = ui
-                self.program = program
-
-            def sendmail(self, sender, recipients, msg):
-                cmdline = '%s -f %s %s' % (
-                    self.program, templater.email(sender),
-                    ' '.join(map(templater.email, recipients)))
-                self.ui.note(_('sending mail: %s\n') % cmdline)
-                fp = os.popen(cmdline, 'w')
-                fp.write(msg)
-                ret = fp.close()
-                if ret:
-                    raise util.Abort('%s %s' % (
-                        os.path.basename(self.program.split(None, 1)[0]),
-                        util.explain_exit(ret)[0]))
-
-        method = self.config('email', 'method', 'smtp')
-        if method == 'smtp':
-            mail = smtp()
-        else:
-            mail = sendmail(self, method)
-        return mail
-
     def print_exc(self):
         '''print exception traceback if traceback printing enabled.
         only to call in exception handler. returns true if traceback