git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v3 0/6] New remote-hg helper
@ 2012-10-21 17:48 Felipe Contreras
  2012-10-21 17:48 ` [PATCH v3 1/6] Add new remote-hg transport helper Felipe Contreras
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:48 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

I've looked at many hg<->git tools and none satisfy me. Too complicated, or too
slow, or to difficult to setup, etc.

The only one I've liked so far is hg-fast-export[1], which is indeed fast,
relatively simple, and relatively easy to use. But it's not properly maintained
any more.

So, I decided to write my own from scratch, using hg-fast-export as
inspiration, and voila.

This one doesn't have any dependencies, just put it into your $PATH, and you
can clone and fetch hg repositories. More importantly to me; the code is
simple, and easy to maintain.

One important remote-hg alternative is the one written by Sverre Rabbelier that
is now maintained and distributed in msysgit, however, in my opinion the code
is bloated, and there isn't even a standalone branch to take a look at the
patches, and give them a try.

This version has some features that Sverre's version doesn't:

 * Support for tags
 * Support to specify branches to pull

Sverre's version has some features this one doesn't:

 * Support for octopus merges

[1] http://repo.or.cz/w/fast-export.git

Changes since v2:

 * Added support for pushing
 * Tests copied from original remote-hg
 * Custom default -> master renames removed
 * Code reorganized

Changes since v1:

 * Improved documentation
 * Use more common 'python' binary
 * Warn, don't barf when a branch has multiple heads
 * Fixed marks to fetch after cloned
 * Support for cloning/pulling remote repositories
 * Use a more appropriate internal directory (e.g. .git/hg/origin)
 * Fixes for python3

Felipe Contreras (6):
  Add new remote-hg transport helper
  remote-hg: add support for pushing
  remote-hg: add support for remote pushing
  remote-hg: add support for trivial features
  tests: add remote-hg tests
  tests: fix remote-hg warnings for modern git

 contrib/remote-hg/git-remote-hg | 489 ++++++++++++++++++++++++++++++++++++++++
 t/t5801-remote-hg.sh            | 143 ++++++++++++
 2 files changed, 632 insertions(+)
 create mode 100755 contrib/remote-hg/git-remote-hg
 create mode 100755 t/t5801-remote-hg.sh

-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/6] Add new remote-hg transport helper
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
@ 2012-10-21 17:48 ` Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 2/6] remote-hg: add support for pushing Felipe Contreras
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:48 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/remote-hg/git-remote-hg | 313 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 313 insertions(+)
 create mode 100755 contrib/remote-hg/git-remote-hg

diff --git a/contrib/remote-hg/git-remote-hg b/contrib/remote-hg/git-remote-hg
new file mode 100755
index 0000000..f0ce4a4
--- /dev/null
+++ b/contrib/remote-hg/git-remote-hg
@@ -0,0 +1,313 @@
+#!/usr/bin/python
+
+# Inspired by Rocco Rutte's hg-fast-export
+
+# Just copy to your ~/bin, or anywhere in your $PATH.
+# Then you can clone with:
+# git clone hg::/path/to/mercurial/repo/
+
+from mercurial import hg, ui
+
+import re
+import sys
+import os
+import json
+
+first = True
+
+AUTHOR_RE = re.compile('^((.+?) )?(<.+?>)$')
+
+def die(msg, *args):
+    sys.stderr.write('ERROR: %s\n' % (msg % args))
+    sys.exit(1)
+
+def warn(msg, *args):
+    sys.stderr.write('WARNING: %s\n' % (msg % args))
+
+def gitmode(flags):
+    return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
+
+class Marks:
+
+    def __init__(self, path):
+        self.path = path
+        self.tips = {}
+        self.marks = {}
+        self.last_mark = 0
+
+        self.load()
+
+    def load(self):
+        if not os.path.exists(self.path):
+            return
+
+        tmp = json.load(open(self.path))
+
+        self.tips = tmp['tips']
+        self.marks = tmp['marks']
+        self.last_mark = tmp['last-mark']
+
+    def dict(self):
+        return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
+
+    def store(self):
+        json.dump(self.dict(), open(self.path, 'w'))
+
+    def __str__(self):
+        return str(self.dict())
+
+    def from_rev(self, rev):
+        return self.marks[str(rev)]
+
+    def next_mark(self, rev):
+        self.last_mark += 1
+        self.marks[str(rev)] = self.last_mark
+        return self.last_mark
+
+    def is_marked(self, rev):
+        return self.marks.has_key(str(rev))
+
+    def get_tip(self, branch):
+        return self.tips.get(branch, 0)
+
+    def set_tip(self, branch, tip):
+        self.tips[branch] = tip
+
+class Parser:
+
+    def __init__(self, repo):
+        self.repo = repo
+        self.line = self.get_line()
+
+    def get_line(self):
+        return sys.stdin.readline().strip()
+
+    def __getitem__(self, i):
+        return self.line.split()[i]
+
+    def check(self, word):
+        return self.line.startswith(word)
+
+    def each_block(self, separator):
+        while self.line != separator:
+            yield self.line
+            self.line = self.get_line()
+
+    def __iter__(self):
+        return self.each_block('')
+
+def export_file(fc):
+    if fc.path() == '.hgtags':
+        return
+    d = fc.data()
+    print "M %s inline %s" % (gitmode(fc.flags()), fc.path())
+    print "data %d" % len(d)
+    print d
+
+def get_filechanges(repo, ctx, parents):
+    l = [repo.status(p, ctx)[:3] for p in parents]
+    changed, added, removed = [sum(e, []) for e in zip(*l)]
+    return added + changed, removed
+
+def fixup_user(user):
+    user = user.replace('"', '')
+    m = AUTHOR_RE.match(user)
+    if m:
+        name = m.group(2)
+        mail = m.group(3)
+    else:
+        name = user
+        mail = None
+
+    if not name:
+        name = 'Unknown'
+    if not mail:
+        mail = '<unknown>'
+
+    return '%s %s' % (name, mail)
+
+def get_repo(url, alias):
+    global dirname
+
+    myui = ui.ui()
+    myui.setconfig('ui', 'interactive', 'off')
+
+    if hg.islocal(url):
+        repo = hg.repository(myui, url)
+    else:
+        local_path = os.path.join(dirname, 'clone')
+        if not os.path.exists(local_path):
+            srcpeer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
+            repo = dstpeer.local()
+        else:
+            repo = hg.repository(myui, local_path)
+            peer = hg.peer(myui, {}, url)
+            repo.pull(peer, heads=None, force=True)
+
+    return repo
+
+def rev_to_mark(rev):
+    global marks
+    return marks.from_rev(rev)
+
+def export_tag(repo, tag):
+    global prefix
+    print "reset %s/tags/%s" % (prefix, tag)
+    print "from :%s" % (rev_to_mark(repo[tag].rev()))
+    print
+
+def export_branch(repo, branch):
+    global prefix, marks, branches
+
+    heads = branches[branch]
+
+    # verify there's only one head
+    if (len(heads) > 1):
+        warn("Branch '%s' has more than one head, consider merging" % branch)
+        tip = repo.branchtip(branch)
+        head = repo[tip]
+    else:
+        head = repo[heads[0]]
+
+    tip = marks.get_tip(branch)
+    # mercurial takes too much time checking this
+    if tip and tip == head.rev():
+        # nothing to do
+        return
+    revs = repo.revs('%u:%u' % (tip, head))
+    count = 0
+
+    revs = [rev for rev in revs if not marks.is_marked(rev)]
+
+    for rev in revs:
+
+        c = repo[rev]
+        (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node())
+        rev_branch = extra['branch']
+
+        tz = '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60)
+
+        print "commit %s/branches/%s" % (prefix, rev_branch)
+        print "mark :%d" % (marks.next_mark(rev))
+        print "committer %s %d %s" % (fixup_user(user), time, tz)
+        print "data %d" % (len(desc) + 1)
+        print desc
+        print
+
+        parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0]
+
+        if len(parents) == 0:
+            modified = c.manifest().keys()
+            removed = []
+        else:
+            added = []
+            changed = []
+            print "from :%s" % (rev_to_mark(parents[0]))
+            if len(parents) > 1:
+                print "merge :%s" % (rev_to_mark(parents[1]))
+            modified, removed = get_filechanges(repo, c, parents)
+
+        for f in removed:
+            print "D %s" % (f)
+        for f in modified:
+            export_file(c.filectx(f))
+        print
+
+        count += 1
+        if (count % 100 == 0):
+            print "progress revision %d '%s' (%d/%d)" % (rev, branch, count, len(revs))
+            print "#############################################################"
+
+    # make sure the ref is updated
+    print "reset %s/branches/%s" % (prefix, branch)
+    print "from :%u" % rev_to_mark(rev)
+    print
+
+    marks.set_tip(branch, rev)
+
+def do_capabilities(parser):
+    global prefix, dirname
+
+    print "import"
+    print "refspec refs/heads/*:%s/branches/*" % prefix
+    print "refspec refs/tags/*:%s/tags/*" % prefix
+    print
+
+def do_list(parser):
+    global branches
+
+    repo = parser.repo
+    head = repo.dirstate.branch()
+    for branch in repo.branchmap():
+        heads = repo.branchheads(branch)
+        if len(heads):
+            branches[branch] = heads
+
+    for branch in branches:
+        print "? refs/heads/%s" % branch
+    for tag, node in repo.tagslist():
+        if tag == 'tip':
+            continue
+        print "? refs/tags/%s" % tag
+    print "@refs/heads/%s HEAD" % head
+    print
+
+def do_import(parser):
+    global first
+
+    repo = parser.repo
+    ref = parser[1]
+
+    if first:
+        path = os.path.join(dirname, 'marks-git')
+
+        if os.path.exists(path):
+            print "feature import-marks=%s" % path
+        print "feature export-marks=%s" % path
+        sys.stdout.flush()
+        first = False
+
+    if (ref == 'HEAD'):
+        return
+
+    if ref.startswith('refs/heads/'):
+        branch = ref[len('refs/heads/'):]
+        export_branch(repo, branch)
+    elif ref.startswith('refs/tags/'):
+        tag = ref[len('refs/tags/'):]
+        export_tag(repo, tag)
+
+def main(args):
+    global prefix, dirname, marks, branches
+
+    alias = args[1]
+    url = args[2]
+
+    gitdir = os.environ['GIT_DIR']
+    dirname = os.path.join(gitdir, 'hg', alias)
+    branches = {}
+
+    repo = get_repo(url, alias)
+    prefix = 'refs/hg/%s' % alias
+
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+
+    marks_path = os.path.join(dirname, 'marks-hg')
+    marks = Marks(marks_path)
+
+    parser = Parser(repo)
+    for line in parser:
+        if parser.check('capabilities'):
+            do_capabilities(parser)
+        elif parser.check('list'):
+            do_list(parser)
+        elif parser.check('import'):
+            do_import(parser)
+        elif parser.check('export'):
+            do_export(parser)
+        sys.stdout.flush()
+
+    marks.store()
+
+sys.exit(main(sys.argv))
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/6] remote-hg: add support for pushing
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
  2012-10-21 17:48 ` [PATCH v3 1/6] Add new remote-hg transport helper Felipe Contreras
@ 2012-10-21 17:49 ` Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 3/6] remote-hg: add support for remote pushing Felipe Contreras
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

Some parsing of fast-export parsing might be missing, but I couldn't find any.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/remote-hg/git-remote-hg | 156 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 2 deletions(-)

diff --git a/contrib/remote-hg/git-remote-hg b/contrib/remote-hg/git-remote-hg
index f0ce4a4..fc4510c 100755
--- a/contrib/remote-hg/git-remote-hg
+++ b/contrib/remote-hg/git-remote-hg
@@ -6,7 +6,7 @@
 # Then you can clone with:
 # git clone hg::/path/to/mercurial/repo/
 
-from mercurial import hg, ui
+from mercurial import hg, ui, context
 
 import re
 import sys
@@ -16,6 +16,7 @@ import json
 first = True
 
 AUTHOR_RE = re.compile('^((.+?) )?(<.+?>)$')
+RAW_AUTHOR_RE = re.compile('^(\w+) (.+) <(.+)> (\d+) ([+-]\d+)')
 
 def die(msg, *args):
     sys.stderr.write('ERROR: %s\n' % (msg % args))
@@ -27,12 +28,17 @@ def warn(msg, *args):
 def gitmode(flags):
     return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
 
+def hgmode(mode):
+    m = { '0100755': 'x', '0120000': 'l' }
+    return m.get(mode, '')
+
 class Marks:
 
     def __init__(self, path):
         self.path = path
         self.tips = {}
         self.marks = {}
+        self.rev_hgmarks = {}
         self.last_mark = 0
 
         self.load()
@@ -47,6 +53,9 @@ class Marks:
         self.marks = tmp['marks']
         self.last_mark = tmp['last-mark']
 
+        for rev, mark in self.marks.iteritems():
+            self.rev_hgmarks[mark] = int(rev)
+
     def dict(self):
         return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
 
@@ -59,11 +68,19 @@ class Marks:
     def from_rev(self, rev):
         return self.marks[str(rev)]
 
+    def to_rev(self, mark):
+        return self.rev_hgmarks[mark]
+
     def next_mark(self, rev):
         self.last_mark += 1
         self.marks[str(rev)] = self.last_mark
         return self.last_mark
 
+    def new_mark(self, rev, mark):
+        self.marks[str(rev)] = mark
+        self.rev_hgmarks[mark] = rev
+        self.last_mark = mark
+
     def is_marked(self, rev):
         return self.marks.has_key(str(rev))
 
@@ -96,6 +113,28 @@ class Parser:
     def __iter__(self):
         return self.each_block('')
 
+    def next(self):
+        self.line = self.get_line()
+        if self.line == 'done':
+            self.line = None
+
+    def get_mark(self):
+        i = self.line.index(':') + 1
+        return int(self.line[i:])
+
+    def get_data(self):
+        if not self.check('data'):
+            return None
+        i = self.line.index(' ') + 1
+        size = int(self.line[i:])
+        return sys.stdin.read(size)
+
+    def get_author(self):
+        m = RAW_AUTHOR_RE.match(self.line)
+        if not m:
+            return None
+        return list(m.groups())[1:]
+
 def export_file(fc):
     if fc.path() == '.hgtags':
         return
@@ -150,6 +189,10 @@ def rev_to_mark(rev):
     global marks
     return marks.from_rev(rev)
 
+def mark_to_rev(mark):
+    global marks
+    return marks.to_rev(mark)
+
 def export_tag(repo, tag):
     global prefix
     print "reset %s/tags/%s" % (prefix, tag)
@@ -229,8 +272,16 @@ def do_capabilities(parser):
     global prefix, dirname
 
     print "import"
+    print "export"
     print "refspec refs/heads/*:%s/branches/*" % prefix
     print "refspec refs/tags/*:%s/tags/*" % prefix
+
+    path = os.path.join(dirname, 'marks-git')
+
+    if os.path.exists(path):
+        print "*import-marks %s" % path
+    print "*export-marks %s" % path
+
     print
 
 def do_list(parser):
@@ -277,8 +328,108 @@ def do_import(parser):
         tag = ref[len('refs/tags/'):]
         export_tag(repo, tag)
 
+def parse_blob(parser):
+    global blob_marks
+
+    parser.next()
+    if parser.check('mark'):
+        mark = parser.get_mark()
+        parser.next()
+    data = parser.get_data()
+    blob_marks[mark] = data
+    return
+
+def parse_commit(parser):
+    global marks, blob_marks
+
+    from_mark = merge_mark = None
+
+    a = parser.line.split(' ')
+    ref = a[1]
+    if ref.startswith('refs/heads/'):
+        branch = ref[len('refs/heads/'):]
+    parser.next()
+
+    if parser.check('mark'):
+        commit_mark = parser.get_mark()
+        parser.next()
+    if parser.check('author'):
+        author = parser.get_author()
+        parser.next()
+    committer = parser.get_author()
+    parser.next()
+    data = parser.get_data()
+    parser.next()
+    if parser.check('from'):
+        from_mark = parser.get_mark()
+        parser.next()
+    if parser.check('merge'):
+        merge_mark = parser.get_mark()
+        parser.next()
+        if parser.check('merge'):
+            die('octopus merges are not supported yet')
+
+    files = {}
+
+    for line in parser:
+        if parser.check('M'):
+            t, mode, mark_ref, path = line.split(' ')
+            mark = int(mark_ref[1:])
+            f = { 'mode' : hgmode(mode), 'data' : blob_marks[mark] }
+        elif parser.check('D'):
+            t, path = line.split(' ')
+            f = { 'deleted' : True }
+        else:
+            die('Unknown file command: %s' % line)
+        files[path] = f
+
+    def getfilectx(repo, memctx, f):
+        of = files[f]
+        if 'deleted' in of:
+            raise IOError
+        return context.memfilectx(f, of['data'], False, False, None)
+
+    repo = parser.repo
+
+    committer_name, committer_email, date, tz = committer
+    date = int(date)
+    tz = int(tz)
+    tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
+    extra = {}
+    extra['branch'] = branch
+
+    if from_mark:
+        p1 = repo.changelog.node(mark_to_rev(from_mark))
+    else:
+        p1 = '\0' * 20
+
+    if merge_mark:
+        p2 = repo.changelog.node(mark_to_rev(merge_mark))
+    else:
+        p2 = '\0' * 20
+
+    ctx = context.memctx(repo, (p1, p2), data,
+            files.keys(), getfilectx,
+            '%s <%s>' % (committer_name, committer_email), (date, -tz), extra)
+
+    node = repo.commitctx(ctx)
+    rev = repo[node].rev()
+
+    marks.new_mark(rev, commit_mark)
+
+    print "ok %s" % ref
+
+def do_export(parser):
+    for line in parser.each_block('done'):
+        if parser.check('blob'):
+            parse_blob(parser)
+        elif parser.check('commit'):
+            parse_commit(parser)
+    print
+
 def main(args):
-    global prefix, dirname, marks, branches
+    global prefix, dirname, branches
+    global marks, blob_marks
 
     alias = args[1]
     url = args[2]
@@ -286,6 +437,7 @@ def main(args):
     gitdir = os.environ['GIT_DIR']
     dirname = os.path.join(gitdir, 'hg', alias)
     branches = {}
+    blob_marks = {}
 
     repo = get_repo(url, alias)
     prefix = 'refs/hg/%s' % alias
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/6] remote-hg: add support for remote pushing
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
  2012-10-21 17:48 ` [PATCH v3 1/6] Add new remote-hg transport helper Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 2/6] remote-hg: add support for pushing Felipe Contreras
@ 2012-10-21 17:49 ` Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 4/6] remote-hg: add support for trivial features Felipe Contreras
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

I'm not happy with this, but works.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/remote-hg/git-remote-hg | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/contrib/remote-hg/git-remote-hg b/contrib/remote-hg/git-remote-hg
index fc4510c..34a00cd 100755
--- a/contrib/remote-hg/git-remote-hg
+++ b/contrib/remote-hg/git-remote-hg
@@ -167,6 +167,7 @@ def fixup_user(user):
 
 def get_repo(url, alias):
     global dirname
+    global peer
 
     myui = ui.ui()
     myui.setconfig('ui', 'interactive', 'off')
@@ -176,7 +177,7 @@ def get_repo(url, alias):
     else:
         local_path = os.path.join(dirname, 'clone')
         if not os.path.exists(local_path):
-            srcpeer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
+            peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
             repo = dstpeer.local()
         else:
             repo = hg.repository(myui, local_path)
@@ -420,6 +421,8 @@ def parse_commit(parser):
     print "ok %s" % ref
 
 def do_export(parser):
+    global peer
+
     for line in parser.each_block('done'):
         if parser.check('blob'):
             parse_blob(parser)
@@ -427,12 +430,17 @@ def do_export(parser):
             parse_commit(parser)
     print
 
+    if peer:
+        parser.repo.push(peer, force=False)
+
 def main(args):
     global prefix, dirname, branches
     global marks, blob_marks
+    global peer
 
     alias = args[1]
     url = args[2]
+    peer = None
 
     gitdir = os.environ['GIT_DIR']
     dirname = os.path.join(gitdir, 'hg', alias)
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/6] remote-hg: add support for trivial features
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
                   ` (2 preceding siblings ...)
  2012-10-21 17:49 ` [PATCH v3 3/6] remote-hg: add support for remote pushing Felipe Contreras
@ 2012-10-21 17:49 ` Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 5/6] tests: add remote-hg tests Felipe Contreras
  2012-10-21 17:49 ` [PATCH v3 6/6] tests: fix remote-hg warnings for modern git Felipe Contreras
  5 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

So that the other remote-hg tests don't barf.

I'm not particularily happy with this code, but does the trick.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/remote-hg/git-remote-hg | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/contrib/remote-hg/git-remote-hg b/contrib/remote-hg/git-remote-hg
index 34a00cd..772bb69 100755
--- a/contrib/remote-hg/git-remote-hg
+++ b/contrib/remote-hg/git-remote-hg
@@ -12,6 +12,7 @@ import re
 import sys
 import os
 import json
+import shutil
 
 first = True
 
@@ -172,7 +173,13 @@ def get_repo(url, alias):
     myui = ui.ui()
     myui.setconfig('ui', 'interactive', 'off')
 
-    if hg.islocal(url):
+    if url.startswith("remote://"):
+        remote = True
+        url = "file://%s" % url[9:]
+    else:
+        remote = False
+
+    if hg.islocal(url) and not remote:
         repo = hg.repository(myui, url)
     else:
         local_path = os.path.join(dirname, 'clone')
@@ -442,6 +449,12 @@ def main(args):
     url = args[2]
     peer = None
 
+    if not alias.isalnum():
+        is_tmp = True
+        alias = "tmp"
+    else:
+        is_tmp = False
+
     gitdir = os.environ['GIT_DIR']
     dirname = os.path.join(gitdir, 'hg', alias)
     branches = {}
@@ -468,6 +481,9 @@ def main(args):
             do_export(parser)
         sys.stdout.flush()
 
-    marks.store()
+    if not is_tmp:
+        marks.store()
+    else:
+        shutil.rmtree(dirname)
 
 sys.exit(main(sys.argv))
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 5/6] tests: add remote-hg tests
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
                   ` (3 preceding siblings ...)
  2012-10-21 17:49 ` [PATCH v3 4/6] remote-hg: add support for trivial features Felipe Contreras
@ 2012-10-21 17:49 ` Felipe Contreras
  2012-10-21 21:02   ` Sverre Rabbelier
  2012-10-21 17:49 ` [PATCH v3 6/6] tests: fix remote-hg warnings for modern git Felipe Contreras
  5 siblings, 1 reply; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

>From the original remote-hg.

You need git-remote-hg already in your path to run them.

I'm not proposing to include this patch like this, but should make it easier to
test.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 t/t5801-remote-hg.sh | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)
 create mode 100755 t/t5801-remote-hg.sh

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
new file mode 100755
index 0000000..2e68372
--- /dev/null
+++ b/t/t5801-remote-hg.sh
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Sverre Rabbelier
+#
+
+test_description='Test remote-helper import and export commands'
+
+. ./test-lib.sh
+
+if test_have_prereq PYTHON && "$PYTHON_PATH" -c '
+import sys
+if sys.hexversion < 0x02040000:
+    sys.exit(1)
+'
+then
+	:
+else
+	skip_all='skipping git remote-hg tests: requires Python 2.4 or newer'
+	test_done
+fi
+
+if ! type hg >/dev/null 2>&1
+then
+	skip_all='skipping git remote-hg tests: requires hg'
+	test_done
+fi
+
+# Call cmp with the arguments -x ".hg" -x ".git" <left> <right>
+
+vcs_cmp () {
+	$DIFF -u -x ".hg" -x ".git" $1 $2
+}
+
+ROOT=$PWD
+
+test_expect_success 'setup repository' '
+	printf "[ui]\nusername = A U Thor <author@example.com>" > \
+		${HOME}/.hgrc &&
+	mkdir server &&
+	hg init server/.hg &&
+	hg clone "$ROOT/server" public &&
+	(cd public &&
+	 echo content >file &&
+	 hg add file &&
+	 hg commit -m one &&
+	 hg push)
+'
+
+test_expect_success 'cloning from local repo' '
+	git clone "hg::file://${ROOT}/server" localclone &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'cloning from remote repo' '
+	git clone "hg::remote://${ROOT}/server" clone &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'create new commit on remote' '
+	(cd public &&
+	 echo content >>file &&
+	 hg commit -A -m two &&
+	 hg push)
+'
+
+test_expect_success 'pulling from local repo' '
+	(cd localclone && git pull) &&
+	vcs_cmp public localclone
+'
+
+test_expect_success 'pulling from remote remote' '
+	(cd clone && git pull) &&
+	vcs_cmp public clone
+'
+
+test_expect_success 'pushing to local empty repo' '
+	hg init localempty &&
+	(cd localclone &&
+	git push --all "hg::file://${ROOT}/localempty") &&
+	(cd localempty &&
+	hg up tip) &&
+	vcs_cmp localclone localempty
+'
+
+test_expect_success 'pushing to remote empty repo' '
+	hg init empty &&
+	(cd localclone &&
+	git push --all "hg::remote://${ROOT}/empty") &&
+	(cd empty &&
+	hg up tip) &&
+	vcs_cmp localclone empty
+'
+
+test_expect_success 'pushing to local repo' '
+	(cd localclone &&
+	echo content >>file &&
+	git commit -a -m three &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp localclone server
+'
+
+test_expect_success 'synch with changes from localclone' '
+	(cd clone &&
+	 git pull)
+'
+
+test_expect_success 'pushing remote local repo' '
+	(cd clone &&
+	echo content >>file &&
+	git commit -a -m four &&
+	git push) &&
+	(cd server &&
+	hg up tip) &&
+	vcs_cmp clone server
+'
+
+test_expect_success 'creating new branch' '
+	(cd public &&
+	hg branch different-branch &&
+	echo different >> file &&
+	hg commit -m five &&
+	hg push -f)
+'
+
+test_expect_success 'pull in new branch to local repository' '
+	(cd localclone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_expect_success 'pull in new branch to remote repository' '
+	(cd clone &&
+	git fetch origin default &&
+	test_must_fail git rev-parse -q --verify refs/remotes/origin/different-branch &&
+	git fetch &&
+	git rev-parse --no-revs --verify refs/remotes/origin/different-branch)
+'
+
+test_done
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 6/6] tests: fix remote-hg warnings for modern git
  2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
                   ` (4 preceding siblings ...)
  2012-10-21 17:49 ` [PATCH v3 5/6] tests: add remote-hg tests Felipe Contreras
@ 2012-10-21 17:49 ` Felipe Contreras
  5 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-21 17:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Sverre Rabbelier, Johannes Schindelin,
	Ilari Liusvaara, Daniel Barkalow, Jeff King, Michael J Gruber,
	Felipe Contreras

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 t/t5801-remote-hg.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t5801-remote-hg.sh b/t/t5801-remote-hg.sh
index 2e68372..ba4d7a2 100755
--- a/t/t5801-remote-hg.sh
+++ b/t/t5801-remote-hg.sh
@@ -95,7 +95,7 @@ test_expect_success 'pushing to local repo' '
 	(cd localclone &&
 	echo content >>file &&
 	git commit -a -m three &&
-	git push) &&
+	git push --all) &&
 	(cd server &&
 	hg up tip) &&
 	vcs_cmp localclone server
@@ -110,7 +110,7 @@ test_expect_success 'pushing remote local repo' '
 	(cd clone &&
 	echo content >>file &&
 	git commit -a -m four &&
-	git push) &&
+	git push --all) &&
 	(cd server &&
 	hg up tip) &&
 	vcs_cmp clone server
-- 
1.8.0.rc2.7.g0961fdf.dirty

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 5/6] tests: add remote-hg tests
  2012-10-21 17:49 ` [PATCH v3 5/6] tests: add remote-hg tests Felipe Contreras
@ 2012-10-21 21:02   ` Sverre Rabbelier
  2012-10-24 15:47     ` Felipe Contreras
  0 siblings, 1 reply; 9+ messages in thread
From: Sverre Rabbelier @ 2012-10-21 21:02 UTC (permalink / raw)
  To: Felipe Contreras
  Cc: git, Junio C Hamano, Johannes Schindelin, Ilari Liusvaara,
	Daniel Barkalow, Jeff King, Michael J Gruber

On Sun, Oct 21, 2012 at 10:49 AM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:
> From the original remote-hg.
>
> You need git-remote-hg already in your path to run them.
>
> I'm not proposing to include this patch like this, but should make it easier to
> test.

You should also have a look at the tests that were marked as "expected
to fail", since they point out a bug with fast-export. I'd sent a
series to fix that, but didn't follow-up to get it merged:

http://thread.gmane.org/gmane.comp.version-control.git/184874

It'd be great if you want to pick this up (like you did with the tests).

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 5/6] tests: add remote-hg tests
  2012-10-21 21:02   ` Sverre Rabbelier
@ 2012-10-24 15:47     ` Felipe Contreras
  0 siblings, 0 replies; 9+ messages in thread
From: Felipe Contreras @ 2012-10-24 15:47 UTC (permalink / raw)
  To: Sverre Rabbelier
  Cc: git, Junio C Hamano, Johannes Schindelin, Ilari Liusvaara,
	Daniel Barkalow, Jeff King, Michael J Gruber

On Sun, Oct 21, 2012 at 11:02 PM, Sverre Rabbelier <srabbelier@gmail.com> wrote:
> On Sun, Oct 21, 2012 at 10:49 AM, Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
>> From the original remote-hg.
>>
>> You need git-remote-hg already in your path to run them.
>>
>> I'm not proposing to include this patch like this, but should make it easier to
>> test.
>
> You should also have a look at the tests that were marked as "expected
> to fail", since they point out a bug with fast-export.

What tests? All the tests I see in msysgit are expected to succeed:
https://github.com/msysgit/git/blob/devel/t/t5801-remote-hg.sh

> I'd sent a
> series to fix that, but didn't follow-up to get it merged:
>
> http://thread.gmane.org/gmane.comp.version-control.git/184874

I have read that thread multiple times now, and I still don't see the
problem. Everything works fine in my remote-hg. I still don't
understand what changes are required in upstream that your remote-hg
needs, and the fact that there is no up-to-date remote-hg branch
doesn't help.

Cheers.

-- 
Felipe Contreras

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-10-24 15:47 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-21 17:48 [PATCH v3 0/6] New remote-hg helper Felipe Contreras
2012-10-21 17:48 ` [PATCH v3 1/6] Add new remote-hg transport helper Felipe Contreras
2012-10-21 17:49 ` [PATCH v3 2/6] remote-hg: add support for pushing Felipe Contreras
2012-10-21 17:49 ` [PATCH v3 3/6] remote-hg: add support for remote pushing Felipe Contreras
2012-10-21 17:49 ` [PATCH v3 4/6] remote-hg: add support for trivial features Felipe Contreras
2012-10-21 17:49 ` [PATCH v3 5/6] tests: add remote-hg tests Felipe Contreras
2012-10-21 21:02   ` Sverre Rabbelier
2012-10-24 15:47     ` Felipe Contreras
2012-10-21 17:49 ` [PATCH v3 6/6] tests: fix remote-hg warnings for modern git Felipe Contreras

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).