Ask git for author and committer name
[stgit] / stgit / git.py
index f5e2f32..13f7b87 100644 (file)
@@ -33,6 +33,38 @@ class GitException(Exception):
 #
 # Classes
 #
+
+class Person:
+    """An author, committer, etc."""
+    def __init__(self, name = None, email = None, date = '',
+                 desc = None):
+        if name or email or date:
+            assert not desc
+            self.name = name
+            self.email = email
+            self.date = date
+        elif desc:
+            assert not (name or email or date)
+            def parse_desc(s):
+                m = re.match(r'^(.+)<(.+)>(.*)$', s)
+                assert m
+                return [x.strip() or None for x in m.groups()]
+            self.name, self.email, self.date = parse_desc(desc)
+    def set_name(self, val):
+        if val:
+            self.name = val
+    def set_email(self, val):
+        if val:
+            self.email = val
+    def set_date(self, val):
+        if val:
+            self.date = val
+    def __str__(self):
+        if self.name and self.email:
+            return '%s <%s>' % (self.name, self.email)
+        else:
+            raise GitException, 'not enough identity data'
+
 class Commit:
     """Handle the commit objects
     """
@@ -182,9 +214,13 @@ def __run(cmd, args=None):
     return 0
 
 def __tree_status(files = None, tree_id = 'HEAD', unknown = False,
-                  noexclude = True):
+                  noexclude = True, verbose = False):
     """Returns a list of pairs - [status, filename]
     """
+    if verbose and sys.stdout.isatty():
+        print 'Checking for changes in the working directory...',
+        sys.stdout.flush()
+
     refresh_index()
 
     if not files:
@@ -221,12 +257,15 @@ def __tree_status(files = None, tree_id = 'HEAD', unknown = False,
         if fs[1] not in conflicts:
             cache_files.append(fs)
 
+    if verbose and sys.stdout.isatty():
+        print 'done'
+
     return cache_files
 
 def local_changes():
     """Return true if there are local changes in the tree
     """
-    return len(__tree_status()) != 0
+    return len(__tree_status(verbose = True)) != 0
 
 # HEAD value cached
 __head = None
@@ -395,13 +434,67 @@ def rm(files, force = False):
         if files:
             __run('git-update-index --force-remove --', files)
 
+# Persons caching
+__user = None
+__author = None
+__committer = None
+
+def user():
+    """Return the user information.
+    """
+    global __user
+    if not __user:
+        if config.has_option('user', 'name') \
+               and config.has_option('user', 'email'):
+            __user = Person(config.get('user', 'name'),
+                            config.get('user', 'email'))
+        else:
+            raise GitException, 'unknown user details'
+    return __user;
+
+def author():
+    """Return the author information.
+    """
+    global __author
+    if not __author:
+        try:
+            # the environment variables take priority over config
+            try:
+                date = os.environ['GIT_AUTHOR_DATE']
+            except KeyError:
+                date = ''
+            __author = Person(os.environ['GIT_AUTHOR_NAME'],
+                              os.environ['GIT_AUTHOR_EMAIL'],
+                              date)
+        except KeyError:
+            __author = user()
+    return __author
+
+def committer():
+    """Return the author information.
+    """
+    global __committer
+    if not __committer:
+        try:
+            # the environment variables take priority over config
+            try:
+                date = os.environ['GIT_COMMITTER_DATE']
+            except KeyError:
+                date = ''
+            __committer = Person(os.environ['GIT_COMMITTER_NAME'],
+                                 os.environ['GIT_COMMITTER_EMAIL'],
+                                 date)
+        except KeyError:
+            __committer = user()
+    return __committer
+
 def update_cache(files = None, force = False):
     """Update the cache information for the given files
     """
     if not files:
         files = []
 
-    cache_files = __tree_status(files)
+    cache_files = __tree_status(files, verbose = False)
 
     # everything is up-to-date
     if len(cache_files) == 0:
@@ -508,8 +601,12 @@ def merge(base, head1, head2):
     local tree
     """
     refresh_index()
-    if __run('git-read-tree -u -m --aggressive', [base, head1, head2]) != 0:
-        raise GitException, 'git-read-tree failed (local changes maybe?)'
+
+    try:
+        # use _output() to mask the verbose prints of the tool
+        _output('git-merge-recursive %s -- %s %s' % (base, head1, head2))
+    except GitException:
+        pass
 
     # check the index for unmerged entries
     files = {}
@@ -698,6 +795,11 @@ def pull(repository = 'origin', refspec = None):
     if __run(config.get('stgit', 'pullcmd'), args) != 0:
         raise GitException, 'Failed "git-pull %s"' % repository
 
+def repack():
+    """Repack all objects into a single pack
+    """
+    __run('git-repack -a -d -f')
+
 def apply_patch(filename = None, diff = None, base = None,
                 fail_dump = True):
     """Apply a patch onto the current or given index. There must not