Use dulwich rather than shelling out to external Git.
authorJelmer Vernooij <jelmer@samba.org>
Sat, 31 May 2014 02:05:36 +0000 (04:05 +0200)
committerJelmer Vernooij <jelmer@jelmer.uk>
Sun, 10 Apr 2016 11:43:46 +0000 (11:43 +0000)
calypso/webdav.py
requirements.txt

index b80ac74..ea2bb21 100644 (file)
@@ -29,6 +29,7 @@ Define the main classes of a collection as seen from the server.
 import os
 import codecs
 import time
+from dulwich import repo
 import hashlib
 import logging
 import tempfile
@@ -96,7 +97,7 @@ class Item(object):
                             break
                     if not name:
                         name = hashlib.sha1(text).hexdigest()
-                
+
             self.object.add("X-CALYPSO-NAME").value = name
         else:
             names = self.object.contents[u'x-calypso-name']
@@ -264,7 +265,7 @@ class Collection(acl.Entity):
                 old_items.append(old_item)
         for old_item in old_items:
             self.my_items.remove(old_item)
-        
+
     def scan_file(self, path):
         self.remove_file(path)
         self.insert_file(path)
@@ -327,10 +328,10 @@ class Collection(acl.Entity):
             h.update(item.etag)
         self._ctag = '%d-' % self.mtime + h.hexdigest()
         self.files = newfiles
-                
+
     def __init__(self, path):
         """Initialize the collection with ``cal`` and ``user`` parameters."""
-        
+
         self.log = logging.getLogger(__name__)
         self.encoding = "utf-8"
         self.urlpath = paths.base_prefix() if path == "/" else paths.base_prefix() + path + "/" # a collections's path always end with / as recommended in rfc4918 as suggestion
@@ -345,6 +346,10 @@ class Collection(acl.Entity):
         self.metadata_mtime = None
         self.scan_dir(False)
         self.tag = "Collection"
+        try:
+            self.repo = repo.Repo(self.path)
+        except repo.NotGitRepository:
+            self.repo = None
 
     def __str__(self):
         return "Calendar-%s (at %s)" % (self.name, self.path)
@@ -352,53 +357,48 @@ class Collection(acl.Entity):
     def __repr__(self):
         return "<Calendar %s>" % (self.name)
 
-    def has_git(self):
-        return True
-
     def git_commit(self, action, context):
         args = ["git", "commit", "--allow-empty"]
         env = {}
 
         message = action
 
-        if "user" in context:
-            # use environment variables instead of --author to avoid git
-            # looking it up in previous commits if it doesn't seem well-formed
-            env['GIT_AUTHOR_NAME'] = context["user"] or "unknown"
-            env['GIT_AUTHOR_EMAIL'] = "%s@webdav" % context["user"]
-            # supress a chatty message that we could configure author
-            # information explicitly in the config file. (slicing it in after
-            # the git command as position is important with git arguments)
-            args[1:1] = ["-c", "advice.implicitIdentity=false"]
+        if 'user' in context:
+            author_name = context['user'] or "unknown"
+            author_email = "%s@webdav" % context['user']
+        else:
+            author_name = author_email = None
 
         if context["client_info"]:
             message += u"\n"
             for key, value in context["client_info"].iteritems():
                 message += u"%s: %s\n" % (key, value)
 
-        args.extend(["-m", message.encode('utf8')])
-
-        subprocess.check_call(args, cwd=self.path, env=env)
+        self.repo.commit(message=message.encode('utf-8'),
+                author=author_name, author_email=author_email)
 
     def git_add(self, path, action, context):
-        if self.has_git():
-            subprocess.check_call(["git", "add", os.path.basename(path)], cwd=self.path)
-            self.git_commit(action, context)
+        if self.repo is None:
+            return
+        self.repo.stage([os.path.basename(path)])
+        self.git_commit(action, context)
 
     def git_rm(self, path, action, context):
-        if self.has_git():
-            subprocess.check_call(["git", "rm", os.path.basename(path)], cwd=self.path)
-            self.git_commit(action, context)
+        if self.repo is None:
+            return
+        self.repo.stage([os.path.basename(path)])
+        self.git_commit(action, context)
 
     def git_change(self, path, action, context):
-        if self.has_git():
-            subprocess.check_call(["git", "add", os.path.basename(path)], cwd=self.path)
-            self.git_commit(action, context)
-            # Touch directory so that another running instance will update
-            try:
-                os.utime(self.path, None)
-            except Exception, ex:
-                self.log.exception("Failed to set directory mtime")
+        if self.repo is None:
+            return
+        self.repo.stage([os.path.basename(path)])
+        self.git_commit(action, context)
+        # Touch directory so that another running instance will update
+        try:
+            os.utime(self.path, None)
+        except Exception, ex:
+            self.log.exception("Failed to set directory mtime")
 
     def write_file(self, item):
         fd, path = tempfile.mkstemp(item.file_extension, item.file_prefix, dir=self.path)
@@ -496,7 +496,7 @@ class Collection(acl.Entity):
         for old_item in self.my_items:
             if old_item.name == name:
                 self.destroy_file(old_item, context=context)
-                
+
     def replace(self, name, text, context):
         """Replace content by ``text`` in objet named ``name`` in collection."""
 
@@ -556,7 +556,7 @@ class Collection(acl.Entity):
         except Exception, ex:
             self.log.exception("Failed to import: %s", path)
             return False
-        
+
     def write(self, headers=None, items=None):
         return True
 
index c41513b..d52f175 100644 (file)
@@ -1,2 +1,3 @@
 daemon==1.5.5
 vobject==0.8.1c
+dulwich