changeset 1:9461f5c3a67c

Actually imports something - incredible!
author Paul Crowley <paul@lshift.net>
date Fri, 29 Feb 2008 17:58:31 +0000
parents d107c6d36780
children c0be990fe8a8
files fastimport/__init__.py fastimport/commands.py fastimport/hgechoprocessor.py fastimport/hgimport.py fastimport/parser.py fastimport/processor.py
diffstat 6 files changed, 197 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/fastimport/__init__.py	Fri Feb 29 12:19:18 2008 +0000
+++ b/fastimport/__init__.py	Fri Feb 29 17:58:31 2008 +0000
@@ -1,17 +1,14 @@
 from mercurial import commands
 
 import parser
-#import dates
-#import commands
-#from fastimport.hgechoprocessor import HgEchoProcessor
 import hgechoprocessor
-#import hhhh
-#from hhhh import HgEchoProcessor
+import hgimport
 
 def fastimport(ui, repo, source, **opts):
     ui.write("Source is %s\n" % source)
     f = open(source)
-    proc = hgechoprocessor.HgEchoProcessor(ui, repo, **opts)
+    proc = hgimport.HgImportProcessor(ui, repo, **opts)
+    #proc = hgechoprocessor.HgEchoProcessor(ui, repo, **opts)
     p = parser.ImportParser(f)
     proc.process(p.iter_commands)
 
--- a/fastimport/commands.py	Fri Feb 29 12:19:18 2008 +0000
+++ b/fastimport/commands.py	Fri Feb 29 17:58:31 2008 +0000
@@ -85,14 +85,15 @@
 
 class CommitCommand(ImportCommand):
 
-    def __init__(self, ref, mark, author, committer, message, parents,
-        file_iter, lineno=0):
+    def __init__(self, ref, mark, author, committer, message, from_,
+        parents, file_iter, lineno=0):
         ImportCommand.__init__(self, 'commit')
         self.ref = ref
         self.mark = mark
         self.author = author
         self.committer = committer
         self.message = message
+        self.from_ = from_
         self.parents = parents
         self.file_iter = file_iter
         self.lineno = lineno
--- a/fastimport/hgechoprocessor.py	Fri Feb 29 12:19:18 2008 +0000
+++ b/fastimport/hgechoprocessor.py	Fri Feb 29 17:58:31 2008 +0000
@@ -32,40 +32,24 @@
         self.finished = False
         
     def progress_handler(self, cmd):
-        """Process a ProgressCommand."""
-        self.ui.write("Cmd: %s\n" % repr(cmd))
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
     def blob_handler(self, cmd):
-        """Process a BlobCommand."""
-        self.ui.write("Cmd: %s\n" % repr(cmd))
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
     def checkpoint_handler(self, cmd):
-        """Process a CheckpointCommand."""
-        self.ui.write("Cmd: %s\n" % repr(cmd))
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
     def commit_handler(self, cmd):
-        """Process a CommitCommand."""
-        self.ui.write("Commit: %s\n" % repr(cmd))
         commit_handler = HgEchoCommitHandler(cmd, self.ui, self.repo, **self.opts)
         commit_handler.process()
-        self.ui.write("Done commit\n")
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
     def reset_handler(self, cmd):
-        """Process a ResetCommand."""
-        self.ui.write("Cmd: %s\n" % repr(cmd))
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
     def tag_handler(self, cmd):
-        """Process a TagCommand."""
-        self.ui.write("Cmd: %s\n" % repr(cmd))
-
-    def finished(self):
-        self.ui.write("Finished")
-
-    def pre_handler(self, cmd):
-        self.ui.write("Pre-handler: %s\n" % repr(cmd))
-
-    def post_handler(self, cmd):
-        self.ui.write("Post-handler: %s\n" % repr(cmd))
+        self.ui.write(cmd.dump_str(verbose=True) + "\n")
 
 class HgEchoCommitHandler(processor.CommitHandler):
 
@@ -75,41 +59,17 @@
         self.repo = repo
         self.opts = opts
 
-    def process(self):
-        self.pre_process_files()
-        for fc in self.command.file_iter():
-            try:
-                handler = self.__class__.__dict__[fc.name[4:] + "_handler"]
-            except KeyError:
-                raise errors.MissingHandler(fc.name)
-            else:
-                handler(self, fc)
-        self.post_process_files()
-
-    def pre_process_files(self):
-        """Prepare for committing."""
-        pass
-
-    def post_process_files(self):
-        """Save the revision."""
-        pass
-
     def modify_handler(self, filecmd):
-        """Handle a filemodify command."""
-        self.ui.write("Cmd: %s\n" % repr(filecmd))
+        self.ui.write(filecmd.dump_str(verbose=True) + "\n")
 
     def delete_handler(self, filecmd):
-        """Handle a filedelete command."""
-        self.ui.write("Cmd: %s\n" % repr(filecmd))
+        self.ui.write(filecmd.dump_str(verbose=True) + "\n")
 
     def copy_handler(self, filecmd):
-        """Handle a filecopy command."""
-        self.ui.write("Cmd: %s\n" % repr(filecmd))
+        self.ui.write(filecmd.dump_str(verbose=True) + "\n")
 
     def rename_handler(self, filecmd):
-        """Handle a filerename command."""
-        self.ui.write("Cmd: %s\n" % repr(filecmd))
+        self.ui.write(filecmd.dump_str(verbose=True) + "\n")
 
     def deleteall_handler(self, filecmd):
-        """Handle a filedeleteall command."""
-        self.ui.write("Cmd: %s\n" % repr(filecmd))
+        self.ui.write(filecmd.dump_str(verbose=True) + "\n")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fastimport/hgimport.py	Fri Feb 29 17:58:31 2008 +0000
@@ -0,0 +1,157 @@
+# Copyright (C) 2008 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Processor of import commands.
+
+This module provides core processing functionality including an abstract class
+for basing real processors on. See the processors package for examples.
+"""
+
+import os
+import os.path
+import mercurial.hg
+import mercurial.commands
+from mercurial.node import nullrev
+import processor
+
+import hgechoprocessor
+
+class HgImportProcessor(processor.ImportProcessor):
+    
+    def __init__(self, ui, repo, **opts):
+        self.ui = ui
+        self.repo = repo
+        self.opts = opts
+        self.last_mark = None
+        self.mark_map = {}
+        self.branch_map = {}
+        #self.tag_map = {}
+        #self.tag_back_map = {}
+        self.finished = False
+
+    def progress_handler(self, cmd):
+        self.ui.write("Progress: %s\n" % cmd.message)
+
+    # We can't handle blobs - fail
+    #def blob_handler(self, cmd):
+
+    def checkpoint_handler(self, cmd):
+        # This command means nothing to us
+        pass
+
+    def committish_rev(self, committish):
+        if committish.startswith(":"):
+            return self.mark_map[committish]
+        else:
+            return self.branch_map[committish]
+        
+    def commit_handler(self, cmd):
+        if cmd.ref == "refs/heads/TAG.FIXUP":
+            #self.tag_back_map[cmd.mark] == first_parent
+            commit_handler = hgechoprocessor.HgEchoCommitHandler(cmd, self.ui, self.repo, **self.opts)
+            commit_handler.process()
+            return
+        if cmd.from_:
+            first_parent = self.committish_rev(cmd.from_)
+        else:
+            first_parent = self.branch_map.get(cmd.ref, nullrev)
+        # Update to the first parent
+        mercurial.hg.clean(self.repo, self.repo.lookup(first_parent))
+        if cmd.parents:
+            if len(cmd.parents) > 1:
+                raise NotImplementedError("Can't handle more than two parents")
+            second_parent = cmd.parents[0]
+            mercurial.commands.debugsetparents(self.ui, self.repo, 
+                first_parent, second_parent)
+        if cmd.ref == "refs/heads/master":
+            branch = "default"
+        else:
+            branch = cmd.ref[len("refs/heads/"):]
+        self.repo.dirstate.setbranch(branch)
+        #print "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
+        commit_handler = HgImportCommitHandler(cmd, self.ui, self.repo, **self.opts)
+        commit_handler.process()
+        #print "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
+        node = self.repo.rawcommit(files = commit_handler.filelist(),
+            text = cmd.message,
+            user = cmd.committer[1],
+            date = self.convert_date(cmd.committer))
+        rev = self.repo.changelog.rev(node)
+        self.mark_map[cmd.mark] = rev
+        self.branch_map[cmd.ref] = rev
+        self.ui.write("Done commit of rev %d\n" % rev)
+
+    def convert_date(self, c):
+        res = (int(c[2]), int(c[3]))
+        #print c, res
+        #print type((0, 0)), type(res), len(res), type(res) is type((0, 0))
+        #if type(res) is type((0, 0)) and len(res) == 2:
+        #    print "go for it"
+        #return res
+        return "%d %d" % res
+        
+    def reset_handler(self, cmd):
+        #self.ui.write("Cmd: %s\n" % repr(cmd))
+        if cmd.from_ is not None:
+            self.branch_map[cmd.from_] = self.committish_rev(cmd.ref)
+        
+    def tag_handler(self, cmd):
+        # self.tag_map[cmd.id] = self.tag_back_map[cmd.from_]
+        pass
+
+class HgImportCommitHandler(processor.CommitHandler):
+
+    def __init__(self, command, ui, repo, **opts):
+        self.command = command
+        self.ui = ui
+        self.repo = repo
+        self.opts = opts
+        self.files = set()
+
+    def _make_container(self, path):
+        if '/' in path:
+            d = os.path.dirname(path)
+            if not os.path.isdir(d):
+                os.makedirs(d)
+        
+    def modify_handler(self, filecmd):
+        #print "============================" + filecmd.path
+        # FIXME: handle mode
+        self.files.add(filecmd.path)
+        self._make_container(filecmd.path)
+        #print "made dirs, writing file"
+        f = open(filecmd.path, "w")
+        f.write(filecmd.data)
+        f.close()
+        #print self.repo.add([filecmd.path])
+        #print "Done:", filecmd.path
+
+    #def delete_handler(self, filecmd):
+    #    self.files.add(filecmd.path)
+    #    os.remove(filecmd.path)
+
+    #def copy_handler(self, filecmd):
+    #    self.files.add(filecmd.path)
+    #    """Handle a filecopy command."""
+    #    self.ui.write("Cmd: %s\n" % repr(filecmd))
+
+    #def rename_handler(self, filecmd):
+    #    self.files.add(filecmd.path)
+    #    """Handle a filerename command."""
+    #    self.ui.write("Cmd: %s\n" % repr(filecmd))
+
+    def filelist(self):
+        return list(self.files)
--- a/fastimport/parser.py	Fri Feb 29 12:19:18 2008 +0000
+++ b/fastimport/parser.py	Fri Feb 29 17:58:31 2008 +0000
@@ -268,7 +268,6 @@
         self.output = output
         # We auto-detect the date format when a date is first encountered
         self.date_parser = None
-        self.last_mark = None
 
     def iter_commands(self):
         """Iterator returning ImportCommand objects."""
@@ -292,7 +291,7 @@
             elif line.startswith('checkpoint'):
                 yield commands.CheckpointCommand()
             else:
-                #print line
+                print line
                 self.abort(errors.InvalidCommand, line)
 
     def iter_file_commands(self):
@@ -340,20 +339,14 @@
         committer = self._get_user_info('commit', 'committer')
         message = self._get_data('commit', 'message')
         from_ = self._get_from()
-        if from_ is None:
-            from_ = self.last_mark
-        self.last_mark = mark
-        if from_ is not None:
-            parents = [from_]
-            while True:
-                merge = self._get_merge()
-                if merge is not None:
-                    parents.append(merge)
-                else:
-                    break
-        else:
-            parents = []
-        return commands.CommitCommand(ref, mark, author, committer, message,
+        parents = []
+        while True:
+            merge = self._get_merge()
+            if merge is not None:
+                parents.append(merge)
+            else:
+                break
+        return commands.CommitCommand(ref, mark, author, committer, message, from_,
             parents, self.iter_file_commands, lineno)
 
     def _parse_file_modify(self, info):
@@ -442,9 +435,12 @@
                 size = int(rest)
                 res = self.read_bytes(size)
                 # consume extra LF if present
-                line = self.next_line()
-                if line != '':
-                    self.push_line(line)
+                while True:
+                    line = self.next_line()
+                    if line != '':
+                        self.push_line(line)
+                        break
+                return res
         else:
             self.abort(errors.MissingSection, required_for, section)
 
@@ -474,9 +470,13 @@
         """Parse a path."""
         if s.startswith('"'):
             if s[-1] != '"':
-                self.abort(errors.BadFormat, cmd, section, s)
+                self.abort(errors.BadFormat)
             else:
-                return _unquote_c_string(s[1:-1])
+                s = _unquote_c_string(s[1:-1])
+        # Check path for sanity
+        sp = s.split("/")
+        if "" in sp or ".." in sp:
+            self.abort(errors.BadFormat)
         return s
 
     def _path_pair(self, s):
--- a/fastimport/processor.py	Fri Feb 29 12:19:18 2008 +0000
+++ b/fastimport/processor.py	Fri Feb 29 17:58:31 2008 +0000
@@ -46,6 +46,7 @@
     def _process(self, command_iter):
         self.pre_process()
         for cmd in command_iter():
+            #print cmd.dump_str(verbose=True)
             #print "starting"
             try:
                 #print cmd.name
@@ -121,6 +122,7 @@
     def process(self):
         self.pre_process_files()
         for fc in self.command.file_iter():
+            #print fc.dump_str(verbose=True)
             try:
                 handler = self.__class__.__dict__[fc.name[4:] + "_handler"]
             except KeyError: