changeset 4484:c927c568a5ad

Automated merge with http://hg.intevation.org/mercurial/crew
author Bryan O'Sullivan <bos@serpentine.com>
date Sun, 27 May 2007 14:43:29 -0700
parents a11e13d50645 (current diff) 8fa54b9c6c5a (diff)
children 6d2d1dcd5f74
files mercurial/commands.py mercurial/patch.py
diffstat 9 files changed, 200 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/convert-repo
+++ b/contrib/convert-repo
@@ -30,7 +30,7 @@ from mercurial import hg, ui, util, fanc
 class Abort(Exception): pass
 class NoRepo(Exception): pass
 
-class commit:
+class commit(object):
     def __init__(self, **parts):
         for x in "author date desc parents".split():
             if not x in parts:
@@ -56,8 +56,89 @@ def recode(s):
         except:
             return s.decode("utf-8", "replace").encode("utf-8")
 
+class converter_source(object):
+    """Conversion source interface"""
+
+    def __init__(self, path):
+        """Initialize conversion source (or raise NoRepo("message")
+        exception if path is not a valid repository)"""
+        raise NotImplementedError()
+
+    def getheads(self):
+        """Return a list of this repository's heads"""
+        raise NotImplementedError()
+
+    def getfile(self, name, rev):
+        """Return file contents as a string"""
+        raise NotImplementedError()
+
+    def getmode(self, name, rev):
+        """Return file mode, eg. '', 'x', or 'l'"""
+        raise NotImplementedError()
+
+    def getchanges(self, version):
+        """Return sorted list of (filename, id) tuples for all files changed in rev.
+        
+        id just tells us which revision to return in getfile(), e.g. in
+        git it's an object hash."""
+        raise NotImplementedError()
+
+    def getcommit(self, version):
+        """Return the commit object for version"""
+        raise NotImplementedError()
+
+    def gettags(self):
+        """Return the tags as a dictionary of name: revision"""
+        raise NotImplementedError()
+
+class converter_sink(object):
+    """Conversion sink (target) interface"""
+
+    def __init__(self, path):
+        """Initialize conversion sink (or raise NoRepo("message")
+        exception if path is not a valid repository)"""
+        raise NotImplementedError()
+
+    def getheads(self):
+        """Return a list of this repository's heads"""
+        raise NotImplementedError()
+
+    def mapfile(self):
+        """Path to a file that will contain lines
+        source_rev_id sink_rev_id
+        mapping equivalent revision identifiers for each system."""
+        raise NotImplementedError()
+
+    def putfile(self, f, e, data):
+        """Put file for next putcommit().
+        f: path to file
+        e: '', 'x', or 'l' (regular file, executable, or symlink)
+        data: file contents"""
+        raise NotImplementedError()
+
+    def delfile(self, f):
+        """Delete file for next putcommit().
+        f: path to file"""
+        raise NotImplementedError()
+
+    def putcommit(self, files, parents, commit):
+        """Create a revision with all changed files listed in 'files'
+        and having listed parents. 'commit' is a commit object containing
+        at a minimum the author, date, and message for this changeset.
+        Called after putfile() and delfile() calls. Note that the sink
+        repository is not told to update itself to a particular revision
+        (or even what that revision would be) before it receives the
+        file data."""
+        raise NotImplementedError()
+
+    def puttags(self, tags):
+        """Put tags into sink.
+        tags: {tagname: sink_rev_id, ...}"""
+        raise NotImplementedError()
+
+
 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
-class convert_cvs:
+class convert_cvs(converter_source):
     def __init__(self, path):
         self.path = path
         cvs = os.path.join(path, "CVS")
@@ -288,7 +369,7 @@ class convert_cvs:
     def gettags(self):
         return self.tags
 
-class convert_git:
+class convert_git(converter_source):
     def __init__(self, path):
         if os.path.isdir(path + "/.git"):
             path += "/.git"
@@ -374,7 +455,7 @@ class convert_git:
 
         return tags
 
-class convert_mercurial:
+class convert_mercurial(converter_sink):
     def __init__(self, path):
         self.path = path
         u = ui.ui()
@@ -471,7 +552,7 @@ def converter(path):
             pass
     abort("%s: unknown repository type\n" % path)
 
-class convert:
+class convert(object):
     def __init__(self, source, dest, mapfile, opts):
 
         self.source = source
--- a/contrib/zsh_completion
+++ b/contrib/zsh_completion
@@ -380,7 +380,7 @@ typeset -A _hg_cmd_globals
   _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
   '(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \
   '(--message -m)'{-m+,--message}'[use <text> as commit message]:text:' \
-  '(--logfile -l)'{-l+,--logfile}'[read commit message from <file>]:log file:_file -g \*.txt' \
+  '(--logfile -l)'{-l+,--logfile}'[read commit message from <file>]:log file:_files -g \*.txt' \
   '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
   '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
   '*:file:_hg_files'
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -182,7 +182,7 @@ def archive(ui, repo, dest, **opts):
     archival.archive(repo, dest, node, kind, not opts['no_decode'],
                      matchfn, prefix)
 
-def backout(ui, repo, rev, **opts):
+def backout(ui, repo, node=None, rev=None, **opts):
     '''reverse effect of earlier changeset
 
     Commit the backed out changes as a new changeset.  The new
@@ -199,6 +199,11 @@ def backout(ui, repo, rev, **opts):
     changeset afterwards.  This saves you from doing the merge by
     hand.  The result of this merge is not committed, as for a normal
     merge.'''
+    if rev and node:
+        raise util.Abort(_("please specify just one revision"))
+
+    if not rev:
+        rev = node
 
     bail_if_changed(repo)
     op1, op2 = repo.dirstate.parents()
@@ -1511,10 +1516,10 @@ def import_(ui, repo, patch1, *patches, 
 
         if pf == '-':
             ui.status(_("applying patch from stdin\n"))
-            tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
+            tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
         else:
             ui.status(_("applying %s\n") % p)
-            tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
+            tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf))
 
         if tmpname is None:
             raise util.Abort(_('no diffs found'))
@@ -1542,6 +1547,7 @@ def import_(ui, repo, patch1, *patches, 
                 if p1 != wp[0].node():
                     hg.clean(repo, p1, wlock=wlock)
                 repo.dirstate.setparents(p1, p2)
+                repo.dirstate.setbranch(branch or 'default')
             elif p2:
                 try:
                     p1 = repo.lookup(p1)
@@ -1826,7 +1832,7 @@ def manifest(ui, repo, rev=None):
             ui.write("%3s " % (m.execf(f) and "755" or "644"))
         ui.write("%s\n" % f)
 
-def merge(ui, repo, node=None, force=None):
+def merge(ui, repo, node=None, force=None, rev=None):
     """merge working directory with another revision
 
     Merge the contents of the current working directory and the
@@ -1840,6 +1846,12 @@ def merge(ui, repo, node=None, force=Non
     revision to merge with must be provided.
     """
 
+    if rev and node:
+        raise util.Abort(_("please specify just one revision"))
+
+    if not node:
+        node = rev
+
     if not node:
         heads = repo.heads()
         if len(heads) > 2:
@@ -2552,7 +2564,7 @@ def unbundle(ui, repo, fname, **opts):
     modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
     return postincoming(ui, repo, modheads, opts['update'])
 
-def update(ui, repo, node=None, clean=False, date=None):
+def update(ui, repo, node=None, rev=None, clean=False, date=None):
     """update working directory
 
     Update the working directory to the specified revision, or the
@@ -2568,15 +2580,21 @@ def update(ui, repo, node=None, clean=Fa
     By default, update will refuse to run if doing so would require
     discarding local changes.
     """
+    if rev and node:
+        raise util.Abort(_("please specify just one revision"))
+
+    if not rev:
+        rev = node
+
     if date:
-        if node:
+        if rev:
             raise util.Abort(_("you can't specify a revision and a date"))
-        node = cmdutil.finddate(ui, repo, date)
+        rev = cmdutil.finddate(ui, repo, date)
 
     if clean:
-        return hg.clean(repo, node)
+        return hg.clean(repo, rev)
     else:
-        return hg.update(repo, node)
+        return hg.update(repo, rev)
 
 def verify(ui, repo):
     """verify the integrity of the repository
@@ -2676,8 +2694,9 @@ table = {
           ('d', 'date', '', _('record datecode as commit date')),
           ('', 'parent', '', _('parent to choose when backing out merge')),
           ('u', 'user', '', _('record user as committer')),
+          ('r', 'rev', '', _('revision to backout')),
          ] + walkopts + commitopts,
-         _('hg backout [OPTION]... REV')),
+         _('hg backout [OPTION]... [-r] REV')),
     "branch": (branch,
                [('f', 'force', None,
                  _('set branch name even if it shadows an existing branch'))],
@@ -2852,8 +2871,10 @@ table = {
     "manifest": (manifest, [], _('hg manifest [REV]')),
     "^merge":
         (merge,
-         [('f', 'force', None, _('force a merge with outstanding changes'))],
-         _('hg merge [-f] [REV]')),
+         [('f', 'force', None, _('force a merge with outstanding changes')),
+          ('r', 'rev', '', _('revision to merge')),
+             ],
+         _('hg merge [-f] [[-r] REV]')),
     "outgoing|out": (outgoing,
          [('M', 'no-merges', None, _('do not show merges')),
           ('f', 'force', None,
@@ -2984,8 +3005,9 @@ table = {
     "^update|up|checkout|co":
         (update,
          [('C', 'clean', None, _('overwrite locally modified files')),
-          ('d', 'date', '', _('tipmost revision matching date'))],
-         _('hg update [-C] [-d DATE] [REV]')),
+          ('d', 'date', '', _('tipmost revision matching date')),
+          ('r', 'rev', '', _('revision'))],
+         _('hg update [-C] [-d DATE] [[-r] REV]')),
     "verify": (verify, [], _('hg verify')),
     "version": (version_, [], _('hg version')),
 }
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -66,6 +66,8 @@ class dirstate(object):
         syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
         def parselines(fp):
             for line in fp:
+                if not line.endswith('\n'):
+                    line += '\n'
                 escape = False
                 for i in xrange(len(line)):
                     if escape: escape = False
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -55,6 +55,7 @@ def extract(ui, fileobj):
         # should try to parse msg['Date']
         date = None
         nodeid = None
+        branch = None
         parents = []
 
         if message:
@@ -99,6 +100,8 @@ def extract(ui, fileobj):
                             ui.debug('From: %s\n' % user)
                         elif line.startswith("# Date "):
                             date = line[7:]
+                        elif line.startswith("# Branch "):
+                            branch = line[9:]
                         elif line.startswith("# Node ID "):
                             nodeid = line[10:]
                         elif line.startswith("# Parent "):
@@ -123,10 +126,10 @@ def extract(ui, fileobj):
     tmpfp.close()
     if not diffs_seen:
         os.unlink(tmpname)
-        return None, message, user, date, None, None, None
+        return None, message, user, date, branch, None, None, None
     p1 = parents and parents.pop(0) or None
     p2 = parents and parents.pop(0) or None
-    return tmpname, message, user, date, nodeid, p1, p2
+    return tmpname, message, user, date, branch, nodeid, p1, p2
 
 GP_PATCH  = 1 << 0  # we have to run patch
 GP_FILTER = 1 << 1  # there's some copy/rename operation
--- a/tests/test-hgignore
+++ b/tests/test-hgignore
@@ -1,6 +1,25 @@
 #!/bin/sh
 
 hg init
+
+# Test issue 562: .hgignore requires newline at end
+touch foo
+touch bar
+touch baz
+cat > makeignore.py <<EOF
+f = open(".hgignore", "w")
+f.write("ignore\n")
+f.write("foo\n")
+# No EOL here
+f.write("bar")
+f.close()
+EOF
+
+python makeignore.py
+echo % should display baz only
+hg status
+rm foo bar baz .hgignore makeignore.py
+
 touch a.o
 touch a.c
 touch syntax
--- a/tests/test-hgignore.out
+++ b/tests/test-hgignore.out
@@ -1,3 +1,5 @@
+% should display baz only
+? baz
 --
 A dir/b.o
 ? a.c
new file mode 100755
--- /dev/null
+++ b/tests/test-impexp-branch
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+cat >findbranch.py <<EOF
+import re, sys
+
+head_re = re.compile('^#(?:(?:\\s+([A-Za-z][A-Za-z0-9_]*)(?:\\s.*)?)|(?:\\s*))$')
+
+for line in sys.stdin:
+    hmatch = head_re.match(line)
+    if not hmatch:
+        sys.exit(1)
+    if hmatch.group(1) == 'Branch':
+        sys.exit(0)
+sys.exit(1)
+EOF
+hg init a
+cd a
+echo "Rev 1" >rev
+hg add rev
+hg commit -m "No branch."
+hg branch abranch
+echo "Rev  2" >rev
+hg commit -m "With branch."
+if hg export 0 | python ../findbranch.py; then
+    echo "Export of default branch revision has Branch header" 1>&2
+    exit 1
+fi
+if hg export 1 | python ../findbranch.py; then
+    :  # Do nothing
+else
+    echo "Export of branch revision is missing Branch header" 1>&2
+    exit 1
+fi
+# Make sure import still works with branch information in patches.
+cd ..
+hg init b
+cd b
+hg -R ../a export 0 | hg import -
+hg -R ../a export 1 | hg import -
+cd ..
+rm -rf b
+hg init b
+cd b
+hg -R ../a export 0 | hg import --exact -
+hg -R ../a export 1 | hg import --exact -
new file mode 100644
--- /dev/null
+++ b/tests/test-impexp-branch.out
@@ -0,0 +1,4 @@
+applying patch from stdin
+applying patch from stdin
+applying patch from stdin
+applying patch from stdin