chiark / gitweb /
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 42e836792febc94567650f15d4e3e095b3ed5ddc..1425518d5a21fbab30c5705dea0c42d8f8ef10c3 100644 (file)
@@ -27,7 +27,7 @@ from stgit import stack, git
 
 
 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
@@ -56,6 +56,9 @@ options = [make_option('-r', '--range',
 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)
index 0b618fefa4ac6a1e2014a82f10beee1cd76b82f9..140699dd001cc386dd6bf3eabce80f12139b1111 100644 (file)
@@ -26,7 +26,7 @@ from stgit import stack, git
 
 
 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
@@ -53,8 +53,10 @@ def func(parser, options, args):
     """
     if not args:
         files = [path for (stat,path) in git.tree_status(verbose = True)]
+        # git.tree_status returns absolute paths
     else:
-        files = args
+        files = git.ls_files(args)
+    directory.cd_to_topdir()
 
     if not files:
         raise CmdException, 'No files specified or no local changes'
index 7cde3922322ae93fe48306b2e68a36181b5c1482..6e8ed0c313f87e3ec9bd3a1f80cf6a1b1f19eb80 100644 (file)
@@ -27,7 +27,7 @@ from stgit.config import config
 
 
 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
@@ -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."""
 
-directory = DirectoryGotoToplevel()
+directory = DirectoryHasRepository()
 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):
-    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()
 
@@ -81,9 +85,7 @@ def func(parser, options, args):
         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:
index a688f7ee46fc157240dfd2896849a2072158accc..5763d09356408160c7bae23c2d44475c1d4b6697 100644 (file)
@@ -25,7 +25,7 @@ from stgit import stack, git
 
 
 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
@@ -72,7 +72,7 @@ def status(files = None, modified = False, new = False, deleted = False,
     """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)
@@ -94,7 +94,6 @@ def status(files = None, modified = False, new = False, deleted = False,
 
     output = []
     for st, fn in cache_files:
-        assert files == None or fn in files
         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
     """
+    args = git.ls_files(args)
+    directory.cd_to_topdir()
+
     if options.reset:
         if args:
             for f in args:
@@ -119,9 +121,6 @@ def func(parser, options, args):
         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)
index 78aae05ea57f4b3de71ed9929af5a6aedd0fcf33..7e1df1eadbcff7b4631260db74f5b4b402999209 100644 (file)
@@ -166,16 +166,37 @@ def exclude_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).
 
-    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.
     """
-    assert files == None or not unknown
+    assert not files or not unknown
 
     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 files == None or filename in files]
+                    if not files or filename in files]
 
     # 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))
@@ -218,7 +239,6 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
     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):
index d0c31b250926482e113c32b59a9d01cc0cf95b05..6389a23f0464a52a13213e4b0d1a607bcfbfc6bc 100755 (executable)
@@ -127,6 +127,7 @@ test_expect_success 'Status of file' '
 '
 
 cat > expected.txt <<EOF
+C foo/bar
 EOF
 test_expect_success 'Status of dir' '
     stg status foo > output.txt &&
index bdd27c5740ed9839ab7409d8d1dc2fe969536690..750e4291bb675662eed035c6b7e73557783792f8 100755 (executable)
@@ -24,4 +24,25 @@ test_expect_success 'Refresh again' '
     [ "$(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