All of lore.kernel.org
 help / color / mirror / 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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.