changeset 5:d6c443a91b18

refactored the git handling stuff out into another class
author Scott Chacon <schacon@gmail.com>
date Thu, 23 Apr 2009 15:26:10 -0700
parents 9150a8f9d1f2
children c77197123d95
files DESIGN.txt __init__.py git_handler.py
diffstat 3 files changed, 93 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/DESIGN.txt
+++ b/DESIGN.txt
@@ -9,6 +9,14 @@
 
 (Dulwich library)
 
+= Lossless Two Way = 
+We need to store data that Git records that Merc does not in a git/extra_data file.  This would be parents over two and committer information (author will be mapped to Hg committer).  This way two Hg developers can collaborate without the Git transport messing up the local commits.
+Each Git commit should be reproducable as a Merc ID and vice versa on any system.
+
+= ISSUES =
+
+* currently sorts by date, though it should be sorting topologically.  if it gets to a commit where we haven't processed it's parents, it will probably fuck up.
+
 May need to use bookmarks extension to do everything better.
 
 * Cloning from a Git Repository *
--- a/__init__.py
+++ b/__init__.py
@@ -34,6 +34,7 @@
 import os, errno, sys
 import subprocess
 import dulwich
+from git_handler import GitHandler
 
 def gclone(ui, git_url, hg_repo_path=None):
     ## TODO : add git_url as the default remote path
@@ -50,7 +51,8 @@
     dulwich.repo.Repo.init_bare(git_hg_path)
     
     # fetch the initial git data
-    git_fetch(dest_repo, git_url)
+    git = GitHandler(dest_repo, ui)
+    git.fetch(git_url)
     
     # checkout the tip
     # hg.update(ui, dest_repo)
@@ -60,34 +62,7 @@
     
 def gpull(ui, repo):
     dest_repo.ui.status(_("pulling from git url\n"))
-    
-
-def git_fetch(dest_repo, git_url):
-    dest_repo.ui.status(_("fetching from git url\n"))
-    git_fetch_pack(dest_repo, git_url)
-    
-def git_fetch_pack(dest_repo, git_url):
-    from dulwich.repo import Repo
-    from dulwich.client import SimpleFetchGraphWalker
-    client, path = get_transport_and_path(git_url)
-    git_dir = os.path.join(dest_repo.path, 'git')
-    r = Repo(git_dir)
-    graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)
-    f, commit = r.object_store.add_pack()
-    refs = client.fetch_pack(path, r.object_store.determine_wants_all, graphwalker, f.write, sys.stdout.write)
-    f.close()
-    commit()
-    r.set_refs(refs)
-
-def get_transport_and_path(uri):
-    from dulwich.client import TCPGitClient, SSHGitClient, SubprocessGitClient
-    for handler, transport in (("git://", TCPGitClient), ("git+ssh://", SSHGitClient)):
-        if uri.startswith(handler):
-            host, path = uri[len(handler):].split("/", 1)
-            return transport(host), "/"+path
-    # if its not git or git+ssh, try a local url..
-    return SubprocessGitClient(), uri
-        
+           
 commands.norepo += " gclone"
 cmdtable = {
   "gclone":
@@ -102,4 +77,4 @@
          _('hg gpush remote')),
   "gpull":
         (gpull, [], _('hg gpull [--merge] remote')),
-}
\ No newline at end of file
+}    
new file mode 100644
--- /dev/null
+++ b/git_handler.py
@@ -0,0 +1,80 @@
+import os, errno, sys
+import dulwich
+from dulwich.repo import Repo
+from dulwich.client import SimpleFetchGraphWalker
+from hgext import bookmarks
+from mercurial.i18n import _
+
+class GitHandler(object):
+    
+    def __init__(self, dest_repo, ui):
+        self.repo = dest_repo
+        self.ui = ui
+        git_dir = os.path.join(self.repo.path, 'git')
+        self.git = Repo(git_dir)
+        
+    def fetch(self, git_url):
+        self.ui.status(_("fetching from git url: " + git_url + "\n"))
+        self.export_git_objects()
+        self.fetch_pack(git_url)
+        self.import_git_objects()
+    
+    def fetch_pack(self, git_url):
+        client, path = self.get_transport_and_path(git_url)
+        graphwalker = SimpleFetchGraphWalker(self.git.heads().values(), self.git.get_parents)
+        f, commit = self.git.object_store.add_pack()
+        try:
+            determine_wants = self.git.object_store.determine_wants_all
+            refs = client.fetch_pack(path, determine_wants, graphwalker, f.write, sys.stdout.write)
+            f.close()
+            commit()
+            self.git.set_refs(refs)
+        except:
+            f.close()
+            raise    
+
+    def import_git_objects(self):
+        self.ui.status(_("importing Git objects into Hg\n"))
+        # import heads as remote references
+        todo = []
+        done = set()
+        convert_list = []
+        for head, sha in self.git.heads().iteritems():
+            todo.append(sha)
+        while todo:
+            sha = todo.pop()
+            assert isinstance(sha, str)
+            if sha in done:
+                continue
+            done.add(sha)
+            commit = self.git.commit(sha)
+            convert_list.append(commit)
+            todo.extend([p for p in commit.parents if p not in done])
+        
+        convert_list.sort(cmp=lambda x,y: x.commit_time-y.commit_time)
+        for commit in convert_list:
+            print "commit: %s" % sha
+            self.import_git_commit(commit)
+    
+        print bookmarks.parse(self.repo)
+
+    def import_git_commit(self, commit):
+        # check that parents are all in Hg, or no parents
+        print commit.parents
+        pass
+
+    def export_git_objects(self):
+        pass
+
+    def check_bookmarks(self):
+        if self.ui.config('extensions', 'hgext.bookmarks') is not None:
+            print "YOU NEED TO SETUP BOOKMARKS"
+
+    def get_transport_and_path(self, uri):
+        from dulwich.client import TCPGitClient, SSHGitClient, SubprocessGitClient
+        for handler, transport in (("git://", TCPGitClient), ("git+ssh://", SSHGitClient)):
+            if uri.startswith(handler):
+                host, path = uri[len(handler):].split("/", 1)
+                return transport(host), "/"+path
+        # if its not git or git+ssh, try a local url..
+        return SubprocessGitClient(), uri