Allow StGIT commands to run correctly in subdirectories
authorCatalin Marinas <catalin.marinas@gmail.com>
Tue, 23 Oct 2007 21:20:53 +0000 (22:20 +0100)
committerCatalin Marinas <catalin.marinas@gmail.com>
Tue, 23 Oct 2007 22:30:53 +0000 (23:30 +0100)
This is mainly achieved by checking the file arguments with
git-ls-files. The patch solves two main issues - the refresh/diff/st
can run properly in subdirectories and commands like diff and status
may no longer get nonexistent files as arguments without complaining.

If one wants to check the status/diff or refresh the files in a
subdirectory, the command arguments should be "." and this is expanded
by git-ls-files to the subdirectory content (recursively).

The patch removes some asserts as they are no longer needed since
checks are performed by git-ls-files.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
stgit/commands/diff.py
stgit/commands/patches.py
stgit/commands/refresh.py
stgit/commands/status.py
stgit/git.py
t/t0002-status.sh
t/t2300-refresh-subdir.sh

index 42e8367..1425518 100644 (file)
@@ -27,7 +27,7 @@ from stgit import stack, git
 
 
 help = 'show the tree diff'
 
 
 help = 'show the tree diff'
-usage = """%prog [options] [<files...>]
+usage = """%prog [options] [<files or dirs>]
 
 Show the diff (default) or diffstat between the current working copy
 or a tree-ish object and another tree-ish object. File names can also
 
 Show the diff (default) or diffstat between the current working copy
 or a tree-ish object and another tree-ish object. File names can also
@@ -56,6 +56,9 @@ options = [make_option('-r', '--range',
 def func(parser, options, args):
     """Show the tree diff
     """
 def func(parser, options, args):
     """Show the tree diff
     """
+    args = git.ls_files(args)
+    directory.cd_to_topdir()
+
     if options.revs:
         rev_list = options.revs.split('..')
         rev_list_len = len(rev_list)
     if options.revs:
         rev_list = options.revs.split('..')
         rev_list_len = len(rev_list)
index 0b618fe..140699d 100644 (file)
@@ -26,7 +26,7 @@ from stgit import stack, git
 
 
 help = 'show the applied patches modifying a file'
 
 
 help = 'show the applied patches modifying a file'
-usage = """%prog [options] [<files...>]
+usage = """%prog [options] [<files or dirs>]
 
 Show the applied patches modifying the given files. Without arguments,
 it shows the patches affected by the local tree modifications. The
 
 Show the applied patches modifying the given files. Without arguments,
 it shows the patches affected by the local tree modifications. The
@@ -53,8 +53,10 @@ def func(parser, options, args):
     """
     if not args:
         files = [path for (stat,path) in git.tree_status(verbose = True)]
     """
     if not args:
         files = [path for (stat,path) in git.tree_status(verbose = True)]
+        # git.tree_status returns absolute paths
     else:
     else:
-        files = args
+        files = git.ls_files(args)
+    directory.cd_to_topdir()
 
     if not files:
         raise CmdException, 'No files specified or no local changes'
 
     if not files:
         raise CmdException, 'No files specified or no local changes'
index 7cde392..6e8ed0c 100644 (file)
@@ -27,7 +27,7 @@ from stgit.config import config
 
 
 help = 'generate a new commit for the current patch'
 
 
 help = 'generate a new commit for the current patch'
-usage = """%prog [options] [<files...>]
+usage = """%prog [options] [<files or dirs>]
 
 Include the latest tree changes in the current patch. This command
 generates a new GIT commit object with the patch details, the previous
 
 Include the latest tree changes in the current patch. This command
 generates a new GIT commit object with the patch details, the previous
@@ -37,7 +37,7 @@ options. The '--force' option is useful when a commit object was
 created with a different tool but the changes need to be included in
 the current patch."""
 
 created with a different tool but the changes need to be included in
 the current patch."""
 
-directory = DirectoryGotoToplevel()
+directory = DirectoryHasRepository()
 options = [make_option('-f', '--force',
                        help = 'force the refresh even if HEAD and '\
                        'top differ',
 options = [make_option('-f', '--force',
                        help = 'force the refresh even if HEAD and '\
                        'top differ',
@@ -55,8 +55,12 @@ options = [make_option('-f', '--force',
            ]
 
 def func(parser, options, args):
            ]
 
 def func(parser, options, args):
-    autoresolved = config.get('stgit.autoresolved')
+    """Generate a new commit for the current or given patch.
+    """
+    args = git.ls_files(args)
+    directory.cd_to_topdir()
 
 
+    autoresolved = config.get('stgit.autoresolved')
     if autoresolved != 'yes':
         check_conflicts()
 
     if autoresolved != 'yes':
         check_conflicts()
 
@@ -81,9 +85,7 @@ def func(parser, options, args):
         out.done()
         return
 
         out.done()
         return
 
-    files = [path for (stat,path) in git.tree_status(verbose = True)]
-    if args:
-        files = [f for f in files if f in args]
+    files = [path for (stat, path) in git.tree_status(files = args, verbose = True)]
 
     if files or not crt_series.head_top_equal():
         if options.patch:
 
     if files or not crt_series.head_top_equal():
         if options.patch:
index a688f7e..5763d09 100644 (file)
@@ -25,7 +25,7 @@ from stgit import stack, git
 
 
 help = 'show the tree status'
 
 
 help = 'show the tree status'
-usage = """%prog [options] [<files...>]
+usage = """%prog [options] [<files or dirs>]
 
 Show the status of the whole working copy or the given files. The
 command also shows the files in the current directory which are not
 
 Show the status of the whole working copy or the given files. The
 command also shows the files in the current directory which are not
@@ -72,7 +72,7 @@ def status(files = None, modified = False, new = False, deleted = False,
     """Show the tree status
     """
     cache_files = git.tree_status(files,
     """Show the tree status
     """
     cache_files = git.tree_status(files,
-                                  unknown = (files == None),
+                                  unknown = (not files),
                                   noexclude = noexclude,
                                   diff_flags = diff_flags)
     filtered = (modified or new or deleted or conflict or unknown)
                                   noexclude = noexclude,
                                   diff_flags = diff_flags)
     filtered = (modified or new or deleted or conflict or unknown)
@@ -94,7 +94,6 @@ def status(files = None, modified = False, new = False, deleted = False,
 
     output = []
     for st, fn in cache_files:
 
     output = []
     for st, fn in cache_files:
-        assert files == None or fn in files
         if filtered:
             output.append(fn)
         else:
         if filtered:
             output.append(fn)
         else:
@@ -105,6 +104,9 @@ def status(files = None, modified = False, new = False, deleted = False,
 def func(parser, options, args):
     """Show the tree status
     """
 def func(parser, options, args):
     """Show the tree status
     """
+    args = git.ls_files(args)
+    directory.cd_to_topdir()
+
     if options.reset:
         if args:
             for f in args:
     if options.reset:
         if args:
             for f in args:
@@ -119,9 +121,6 @@ def func(parser, options, args):
         else:
             diff_flags = []
 
         else:
             diff_flags = []
 
-        # No args means all files
-        if not args:
-            args = None
         status(args, options.modified, options.new, options.deleted,
                options.conflict, options.unknown, options.noexclude,
                diff_flags = diff_flags)
         status(args, options.modified, options.new, options.deleted,
                options.conflict, options.unknown, options.noexclude,
                diff_flags = diff_flags)
index 78aae05..7e1df1e 100644 (file)
@@ -166,16 +166,37 @@ def exclude_files():
         files.append(user_exclude)
     return files
 
         files.append(user_exclude)
     return files
 
+def ls_files(files, tree = None, full_name = True):
+    """Return the files known to GIT or raise an error otherwise. It also
+    converts the file to the full path relative the the .git directory.
+    """
+    if not files:
+        return []
+
+    args = []
+    if tree:
+        args.append('--with-tree=%s' % tree)
+    if full_name:
+        args.append('--full-name')
+    args.append('--')
+    args.extend(files)
+    try:
+        return GRun('git-ls-files', '--error-unmatch', *args).output_lines()
+    except GitRunException:
+        # just hide the details of the git-ls-files command we use
+        raise GitException, \
+            'Some of the given paths are either missing or not known to GIT'
+
 def tree_status(files = None, tree_id = 'HEAD', unknown = False,
                   noexclude = True, verbose = False, diff_flags = []):
     """Get the status of all changed files, or of a selected set of
     files. Returns a list of pairs - (status, filename).
 
 def tree_status(files = None, tree_id = 'HEAD', unknown = False,
                   noexclude = True, verbose = False, diff_flags = []):
     """Get the status of all changed files, or of a selected set of
     files. Returns a list of pairs - (status, filename).
 
-    If 'files' is None, it will check all files, and optionally all
+    If 'not files', it will check all files, and optionally all
     unknown files.  If 'files' is a list, it will only check the files
     in the list.
     """
     unknown files.  If 'files' is a list, it will only check the files
     in the list.
     """
-    assert files == None or not unknown
+    assert not files or not unknown
 
     if verbose:
         out.start('Checking for changes in the working directory')
 
     if verbose:
         out.start('Checking for changes in the working directory')
@@ -204,11 +225,11 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
     if not conflicts:
         conflicts = []
     cache_files += [('C', filename) for filename in conflicts
     if not conflicts:
         conflicts = []
     cache_files += [('C', filename) for filename in conflicts
-                    if files == None or filename in files]
+                    if not files or filename in files]
 
     # the rest
     args = diff_flags + [tree_id]
 
     # the rest
     args = diff_flags + [tree_id]
-    if files != None:
+    if files:
         args += ['--'] + files
     for line in GRun('git-diff-index', *args).output_lines():
         fs = tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
         args += ['--'] + files
     for line in GRun('git-diff-index', *args).output_lines():
         fs = tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
@@ -218,7 +239,6 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
     if verbose:
         out.done()
 
     if verbose:
         out.done()
 
-    assert files == None or set(f for s,f in cache_files) <= set(files)
     return cache_files
 
 def local_changes(verbose = True):
     return cache_files
 
 def local_changes(verbose = True):
index d0c31b2..6389a23 100755 (executable)
@@ -127,6 +127,7 @@ test_expect_success 'Status of file' '
 '
 
 cat > expected.txt <<EOF
 '
 
 cat > expected.txt <<EOF
+C foo/bar
 EOF
 test_expect_success 'Status of dir' '
     stg status foo > output.txt &&
 EOF
 test_expect_success 'Status of dir' '
     stg status foo > output.txt &&
index bdd27c5..750e429 100755 (executable)
@@ -24,4 +24,25 @@ test_expect_success 'Refresh again' '
     [ "$(stg status)" = "" ]
 '
 
     [ "$(stg status)" = "" ]
 '
 
+test_expect_success 'Refresh file in subdirectory' '
+    echo foo3 >> foo.txt &&
+    echo bar3 >> bar/bar.txt &&
+    cd bar &&
+    stg refresh bar.txt &&
+    cd .. &&
+    [ "$(stg status)" = "M foo.txt" ]
+'
+
+test_expect_success 'Refresh whole subdirectory' '
+    echo bar4 >> bar/bar.txt &&
+    stg refresh bar &&
+    [ "$(stg status)" = "M foo.txt" ]
+'
+
+test_expect_success 'Refresh subdirectories recursively' '
+    echo bar5 >> bar/bar.txt &&
+    stg refresh . &&
+    [ "$(stg status)" = "" ]
+'
+
 test_done
 test_done