[PATCH] Really fix import --edit invoking editor twice
[stgit] / stgit / git.py
index 3a999e4..5abe902 100644 (file)
@@ -75,10 +75,23 @@ class Commit:
     def get_committer(self):
         return self.__committer
 
     def get_committer(self):
         return self.__committer
 
+# dictionary of Commit objects, used to avoid multiple calls to git
+__commits = dict()
 
 #
 # Functions
 #
 
 #
 # Functions
 #
+def get_commit(id_hash):
+    """Commit objects factory. Save/look-up them in the __commits
+    dictionary
+    """
+    if id_hash in __commits:
+        return __commits[id_hash]
+    else:
+        commit = Commit(id_hash)
+        __commits[id_hash] = commit
+        return commit
+
 def get_conflicts():
     """Return the list of file conflicts
     """
 def get_conflicts():
     """Return the list of file conflicts
     """
@@ -94,7 +107,6 @@ def get_conflicts():
 def _input(cmd, file_desc):
     p = popen2.Popen3(cmd)
     for line in file_desc:
 def _input(cmd, file_desc):
     p = popen2.Popen3(cmd)
     for line in file_desc:
-        print line
         p.tochild.write(line)
     p.tochild.close()
     if p.wait():
         p.tochild.write(line)
     p.tochild.close()
     if p.wait():
@@ -242,41 +254,45 @@ def rm(files, force = False):
         if files:
             __run('git-update-cache --force-remove --', files)
 
         if files:
             __run('git-update-cache --force-remove --', files)
 
-def update_cache(files):
+def update_cache(files = [], force = False):
     """Update the cache information for the given files
     """
     """Update the cache information for the given files
     """
-    files_here = []
-    files_gone = []
+    cache_files = __tree_status(files)
 
 
-    for f in files:
-        if os.path.exists(f):
-            files_here.append(f)
-        else:
-            files_gone.append(f)
+    # everything is up-to-date
+    if len(cache_files) == 0:
+        return False
+
+    # check for unresolved conflicts
+    if not force and [x for x in cache_files
+                      if x[0] not in ['M', 'N', 'A', 'D']]:
+        raise GitException, 'Updating cache failed: unresolved conflicts'
 
 
-    if files_here:
-        __run('git-update-cache --', files_here)
-    if files_gone:
-        __run('git-update-cache --remove --', files_gone)
+    # update the cache
+    add_files = [x[1] for x in cache_files if x[0] in ['N', 'A']]
+    rm_files =  [x[1] for x in cache_files if x[0] in ['D']]
+    m_files =   [x[1] for x in cache_files if x[0] in ['M']]
+
+    if add_files and __run('git-update-cache --add --', add_files) != 0:
+        raise GitException, 'Failed git-update-cache --add'
+    if rm_files and __run('git-update-cache --force-remove --', rm_files) != 0:
+        raise GitException, 'Failed git-update-cache --rm'
+    if m_files and __run('git-update-cache --', m_files) != 0:
+        raise GitException, 'Failed git-update-cache'
+
+    return True
 
 def commit(message, files = [], parents = [], allowempty = False,
 
 def commit(message, files = [], parents = [], allowempty = False,
+           cache_update = True,
            author_name = None, author_email = None, author_date = None,
            committer_name = None, committer_email = None):
     """Commit the current tree to repository
     """
            author_name = None, author_email = None, author_date = None,
            committer_name = None, committer_email = None):
     """Commit the current tree to repository
     """
-    first = (parents == [])
-
     # Get the tree status
     # Get the tree status
-    if not first:
-        cache_files = __tree_status(files)
-
-    if not first and len(cache_files) == 0 and not allowempty:
-        raise GitException, 'No changes to commit'
-
-    # check for unresolved conflicts
-    if not first and len(filter(lambda x: x[0] not in ['M', 'N', 'A', 'D'],
-                                cache_files)) != 0:
-        raise GitException, 'Commit failed: unresolved conflicts'
+    if cache_update and parents != []:
+        changes = update_cache(files)
+        if not changes and not allowempty:
+            raise GitException, 'No changes to commit'
 
     # get the commit message
     f = file('.commitmsg', 'w+')
 
     # get the commit message
     f = file('.commitmsg', 'w+')
@@ -286,29 +302,6 @@ def commit(message, files = [], parents = [], allowempty = False,
         print >> f, message
     f.close()
 
         print >> f, message
     f.close()
 
-    # update the cache
-    if not first:
-        add_files=[]
-        rm_files=[]
-        m_files=[]
-        for f in cache_files:
-            if f[0] in ['N', 'A']:
-                add_files.append(f[1])
-            elif f[0] == 'D':
-                rm_files.append(f[1])
-            else:
-                m_files.append(f[1])
-
-    if add_files:
-        if __run('git-update-cache --add --', add_files):
-            raise GitException, 'Failed git-update-cache --add'
-    if rm_files:
-        if __run('git-update-cache --force-remove --', rm_files):
-            raise GitException, 'Failed git-update-cache --rm'
-    if m_files:
-        if __run('git-update-cache --', m_files):
-            raise GitException, 'Failed git-update-cache'
-
     # write the index to repository
     tree_id = _output_one_line('git-write-tree')
 
     # write the index to repository
     tree_id = _output_one_line('git-write-tree')
 
@@ -349,10 +342,6 @@ def merge(base, head1, head2):
     if os.system('git-merge-cache -o gitmergeonefile.py -a') != 0:
         raise GitException, 'git-merge-cache failed (possible conflicts)'
 
     if os.system('git-merge-cache -o gitmergeonefile.py -a') != 0:
         raise GitException, 'git-merge-cache failed (possible conflicts)'
 
-    # this should not fail
-    if os.system('git-checkout-cache -f -a') != 0:
-        raise GitException, 'Failed git-checkout-cache'
-
 def status(files = [], modified = False, new = False, deleted = False,
            conflict = False, unknown = False):
     """Show the tree status
 def status(files = [], modified = False, new = False, deleted = False,
            conflict = False, unknown = False):
     """Show the tree status
@@ -373,7 +362,7 @@ def status(files = [], modified = False, new = False, deleted = False,
             filestat.append('C')
         if unknown:
             filestat.append('?')
             filestat.append('C')
         if unknown:
             filestat.append('?')
-        cache_files = filter(lambda x: x[0] in filestat, cache_files)
+        cache_files = [x for x in cache_files if x[0] in filestat]
 
     for fs in cache_files:
         if all:
 
     for fs in cache_files:
         if all:
@@ -440,17 +429,28 @@ def checkout(files = [], tree_id = None, force = False):
 def switch(tree_id):
     """Switch the tree to the given id
     """
 def switch(tree_id):
     """Switch the tree to the given id
     """
-    to_delete = filter(lambda x: x[0] in ['N', 'A'],
-                       __tree_status(tree_id = tree_id))
+    if __run('git-read-tree -u -m', [get_head(), tree_id]) != 0:
+        raise GitException, 'git-read-tree failed (local changes maybe?)'
+
+    __set_head(tree_id)
+
+def reset(tree_id = None):
+    """Revert the tree changes relative to the given tree_id. It removes
+    any local changes
+    """
+    if not tree_id:
+        tree_id = get_head()
+
+    cache_files = __tree_status(tree_id = tree_id)
+    rm_files =  [x[1] for x in cache_files if x[0] in ['D']]
 
     checkout(tree_id = tree_id, force = True)
     __set_head(tree_id)
 
     # checkout doesn't remove files
 
     checkout(tree_id = tree_id, force = True)
     __set_head(tree_id)
 
     # checkout doesn't remove files
-    for fs in to_delete:
-        os.remove(fs[1])
+    map(os.remove, rm_files)
 
 
-def fetch(location, head = None, tag = None):
+def pull(location, head = None, tag = None):
     """Fetch changes from the remote repository. At the moment, just
     use the 'git fetch' scripts
     """
     """Fetch changes from the remote repository. At the moment, just
     use the 'git fetch' scripts
     """
@@ -460,11 +460,9 @@ def fetch(location, head = None, tag = None):
     elif tag:
         args += ['tag', tag]
 
     elif tag:
         args += ['tag', tag]
 
-    if __run('git fetch', args) != 0:
+    if __run('git pull', args) != 0:
         raise GitException, 'Failed "git fetch %s"' % location
 
         raise GitException, 'Failed "git fetch %s"' % location
 
-    return read_string(os.path.join(base_dir, 'FETCH_HEAD'))
-
 def apply_patch(filename = None):
     """Apply a patch onto the current index. There must not be any
     local changes in the tree, otherwise the command fails
 def apply_patch(filename = None):
     """Apply a patch onto the current index. There must not be any
     local changes in the tree, otherwise the command fails