We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`spack pkg` command and tests fail for git < 1.8.5
The implementation of the `spack pkg` command assumes one is working in an environment with a git >= 1.8.5, as the `-C` option is used for all invocations of the `git` command. Associated tests also fail, see `spack test cmd/pkg`:

```console
$ spack test cmd/pkg
...
E                                  ProcessError: Command exited with status 129:
E                                      '/usr/bin/git' '-C' '/tmp/pytest-of-greenc/pytest-52/mock_pkg_git_repo0/builtin.mock/packages' 'ls-tree' '--name-only' 'HEAD^^'

../util/executable.py:189: ProcessError
-------------------------------------------------------------------------- Captured stderr call ---------------------------------------------------------------------------
Unknown option: -C
usage: git [--version] [--help] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]
```

On a standard `Scientific7` (or `RHEL7`) system, the version of git available is `1.8.3.1`. On `RHEL6` (still in extensive use in HEP), it is `1.7.1`.

A reasonable solution might be to test for the version and fall back on a function wrapper to the git `Executable` that invokes it with the current directory corresponding to the desired `path`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/spack/spack/cmd/pkg.py`
Content:
```
1 # Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
2 # Spack Project Developers. See the top-level COPYRIGHT file for details.
3 #
4 # SPDX-License-Identifier: (Apache-2.0 OR MIT)
5 
6 from __future__ import print_function
7 
8 import os
9 import argparse
10 import re
11 
12 import llnl.util.tty as tty
13 from llnl.util.tty.colify import colify
14 
15 import spack.cmd
16 import spack.paths
17 import spack.repo
18 from spack.util.executable import which
19 
20 description = "query packages associated with particular git revisions"
21 section = "developer"
22 level = "long"
23 
24 
25 def setup_parser(subparser):
26     sp = subparser.add_subparsers(
27         metavar='SUBCOMMAND', dest='pkg_command')
28 
29     add_parser = sp.add_parser('add', help=pkg_add.__doc__)
30     add_parser.add_argument('packages', nargs=argparse.REMAINDER,
31                             help="names of packages to add to git repo")
32 
33     list_parser = sp.add_parser('list', help=pkg_list.__doc__)
34     list_parser.add_argument('rev', default='HEAD', nargs='?',
35                              help="revision to list packages for")
36 
37     diff_parser = sp.add_parser('diff', help=pkg_diff.__doc__)
38     diff_parser.add_argument(
39         'rev1', nargs='?', default='HEAD^',
40         help="revision to compare against")
41     diff_parser.add_argument(
42         'rev2', nargs='?', default='HEAD',
43         help="revision to compare to rev1 (default is HEAD)")
44 
45     add_parser = sp.add_parser('added', help=pkg_added.__doc__)
46     add_parser.add_argument(
47         'rev1', nargs='?', default='HEAD^',
48         help="revision to compare against")
49     add_parser.add_argument(
50         'rev2', nargs='?', default='HEAD',
51         help="revision to compare to rev1 (default is HEAD)")
52 
53     add_parser = sp.add_parser('changed', help=pkg_changed.__doc__)
54     add_parser.add_argument(
55         'rev1', nargs='?', default='HEAD^',
56         help="revision to compare against")
57     add_parser.add_argument(
58         'rev2', nargs='?', default='HEAD',
59         help="revision to compare to rev1 (default is HEAD)")
60     add_parser.add_argument(
61         '-t', '--type', action='store', default='C',
62         help="Types of changes to show (A: added, R: removed, "
63         "C: changed); default is 'C'")
64 
65     rm_parser = sp.add_parser('removed', help=pkg_removed.__doc__)
66     rm_parser.add_argument(
67         'rev1', nargs='?', default='HEAD^',
68         help="revision to compare against")
69     rm_parser.add_argument(
70         'rev2', nargs='?', default='HEAD',
71         help="revision to compare to rev1 (default is HEAD)")
72 
73 
74 def packages_path():
75     """Get the test repo if it is active, otherwise the builtin repo."""
76     try:
77         return spack.repo.path.get_repo('builtin.mock').packages_path
78     except spack.repo.UnknownNamespaceError:
79         return spack.repo.path.get_repo('builtin').packages_path
80 
81 
82 def get_git():
83     """Get a git executable that runs *within* the packages path."""
84     git = which('git', required=True)
85     git.add_default_arg('-C')
86     git.add_default_arg(packages_path())
87     return git
88 
89 
90 def list_packages(rev):
91     git = get_git()
92 
93     # git ls-tree does not support ... merge-base syntax, so do it manually
94     if rev.endswith('...'):
95         ref = rev.replace('...', '')
96         rev = git('merge-base', ref, 'HEAD', output=str).strip()
97 
98     output = git('ls-tree', '--name-only', rev, output=str)
99     return sorted(line for line in output.split('\n')
100                   if line and not line.startswith('.'))
101 
102 
103 def pkg_add(args):
104     """add a package to the git stage with `git add`"""
105     for pkg_name in args.packages:
106         filename = spack.repo.path.filename_for_package_name(pkg_name)
107         if not os.path.isfile(filename):
108             tty.die("No such package: %s.  Path does not exist:" %
109                     pkg_name, filename)
110 
111         git = get_git()
112         git('add', filename)
113 
114 
115 def pkg_list(args):
116     """list packages associated with a particular spack git revision"""
117     colify(list_packages(args.rev))
118 
119 
120 def diff_packages(rev1, rev2):
121     p1 = set(list_packages(rev1))
122     p2 = set(list_packages(rev2))
123     return p1.difference(p2), p2.difference(p1)
124 
125 
126 def pkg_diff(args):
127     """compare packages available in two different git revisions"""
128     u1, u2 = diff_packages(args.rev1, args.rev2)
129 
130     if u1:
131         print("%s:" % args.rev1)
132         colify(sorted(u1), indent=4)
133         if u1:
134             print()
135 
136     if u2:
137         print("%s:" % args.rev2)
138         colify(sorted(u2), indent=4)
139 
140 
141 def pkg_removed(args):
142     """show packages removed since a commit"""
143     u1, u2 = diff_packages(args.rev1, args.rev2)
144     if u1:
145         colify(sorted(u1))
146 
147 
148 def pkg_added(args):
149     """show packages added since a commit"""
150     u1, u2 = diff_packages(args.rev1, args.rev2)
151     if u2:
152         colify(sorted(u2))
153 
154 
155 def pkg_changed(args):
156     """show packages changed since a commit"""
157     lower_type = args.type.lower()
158     if not re.match('^[arc]*$', lower_type):
159         tty.die("Invald change type: '%s'." % args.type,
160                 "Can contain only A (added), R (removed), or C (changed)")
161 
162     removed, added = diff_packages(args.rev1, args.rev2)
163 
164     git = get_git()
165     out = git('diff', '--relative', '--name-only', args.rev1, args.rev2,
166               output=str).strip()
167 
168     lines = [] if not out else re.split(r'\s+', out)
169     changed = set()
170     for path in lines:
171         pkg_name, _, _ = path.partition(os.sep)
172         if pkg_name not in added and pkg_name not in removed:
173             changed.add(pkg_name)
174 
175     packages = set()
176     if 'a' in lower_type:
177         packages |= added
178     if 'r' in lower_type:
179         packages |= removed
180     if 'c' in lower_type:
181         packages |= changed
182 
183     if packages:
184         colify(sorted(packages))
185 
186 
187 def pkg(parser, args):
188     if not spack.cmd.spack_is_git_repo():
189         tty.die("This spack is not a git clone. Can't use 'spack pkg'")
190 
191     action = {'add': pkg_add,
192               'diff': pkg_diff,
193               'list': pkg_list,
194               'removed': pkg_removed,
195               'added': pkg_added,
196               'changed': pkg_changed}
197     action[args.pkg_command](args)
198
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/spack/spack/cmd/pkg.py b/lib/spack/spack/cmd/pkg.py
--- a/lib/spack/spack/cmd/pkg.py
+++ b/lib/spack/spack/cmd/pkg.py
@@ -11,6 +11,7 @@
 
 import llnl.util.tty as tty
 from llnl.util.tty.colify import colify
+from llnl.util.filesystem import working_dir
 
 import spack.cmd
 import spack.paths
@@ -79,12 +80,28 @@
         return spack.repo.path.get_repo('builtin').packages_path
 
 
+class GitExe:
+    # Wrapper around Executable for git to set working directory for all
+    # invocations.
+    #
+    # Not using -C as that is not supported for git < 1.8.5.
+    def __init__(self):
+        self._git_cmd = which('git', required=True)
+
+    def __call__(self, *args, **kwargs):
+        with working_dir(packages_path()):
+            return self._git_cmd(*args, **kwargs)
+
+
+_git = None
+
+
 def get_git():
     """Get a git executable that runs *within* the packages path."""
-    git = which('git', required=True)
-    git.add_default_arg('-C')
-    git.add_default_arg(packages_path())
-    return git
+    global _git
+    if _git is None:
+        _git = GitExe()
+    return _git
 
 
 def list_packages(rev):
@@ -102,13 +119,14 @@
 
 def pkg_add(args):
     """add a package to the git stage with `git add`"""
+    git = get_git()
+
     for pkg_name in args.packages:
         filename = spack.repo.path.filename_for_package_name(pkg_name)
         if not os.path.isfile(filename):
             tty.die("No such package: %s.  Path does not exist:" %
                     pkg_name, filename)
 
-        git = get_git()
         git('add', filename)

{"golden_diff": "diff --git a/lib/spack/spack/cmd/pkg.py b/lib/spack/spack/cmd/pkg.py\n--- a/lib/spack/spack/cmd/pkg.py\n+++ b/lib/spack/spack/cmd/pkg.py\n@@ -11,6 +11,7 @@\n \n import llnl.util.tty as tty\n from llnl.util.tty.colify import colify\n+from llnl.util.filesystem import working_dir\n \n import spack.cmd\n import spack.paths\n@@ -79,12 +80,28 @@\n         return spack.repo.path.get_repo('builtin').packages_path\n \n \n+class GitExe:\n+    # Wrapper around Executable for git to set working directory for all\n+    # invocations.\n+    #\n+    # Not using -C as that is not supported for git < 1.8.5.\n+    def __init__(self):\n+        self._git_cmd = which('git', required=True)\n+\n+    def __call__(self, *args, **kwargs):\n+        with working_dir(packages_path()):\n+            return self._git_cmd(*args, **kwargs)\n+\n+\n+_git = None\n+\n+\n def get_git():\n     \"\"\"Get a git executable that runs *within* the packages path.\"\"\"\n-    git = which('git', required=True)\n-    git.add_default_arg('-C')\n-    git.add_default_arg(packages_path())\n-    return git\n+    global _git\n+    if _git is None:\n+        _git = GitExe()\n+    return _git\n \n \n def list_packages(rev):\n@@ -102,13 +119,14 @@\n \n def pkg_add(args):\n     \"\"\"add a package to the git stage with `git add`\"\"\"\n+    git = get_git()\n+\n     for pkg_name in args.packages:\n         filename = spack.repo.path.filename_for_package_name(pkg_name)\n         if not os.path.isfile(filename):\n             tty.die(\"No such package: %s.  Path does not exist:\" %\n                     pkg_name, filename)\n \n-        git = get_git()\n         git('add', filename)\n", "issue": "`spack pkg` command and tests fail for git < 1.8.5\nThe implementation of the `spack pkg` command assumes one is working in an environment with a git >= 1.8.5, as the `-C` option is used for all invocations of the `git` command. Associated tests also fail, see `spack test cmd/pkg`:\r\n\r\n```console\r\n$ spack test cmd/pkg\r\n...\r\nE                                  ProcessError: Command exited with status 129:\r\nE                                      '/usr/bin/git' '-C' '/tmp/pytest-of-greenc/pytest-52/mock_pkg_git_repo0/builtin.mock/packages' 'ls-tree' '--name-only' 'HEAD^^'\r\n\r\n../util/executable.py:189: ProcessError\r\n-------------------------------------------------------------------------- Captured stderr call ---------------------------------------------------------------------------\r\nUnknown option: -C\r\nusage: git [--version] [--help] [-c name=value]\r\n           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\r\n           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\r\n           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\r\n           <command> [<args>]\r\n```\r\n\r\nOn a standard `Scientific7` (or `RHEL7`) system, the version of git available is `1.8.3.1`. On `RHEL6` (still in extensive use in HEP), it is `1.7.1`.\r\n\r\nA reasonable solution might be to test for the version and fall back on a function wrapper to the git `Executable` that invokes it with the current directory corresponding to the desired `path`.\n", "before_files": [{"content": "# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other\n# Spack Project Developers. See the top-level COPYRIGHT file for details.\n#\n# SPDX-License-Identifier: (Apache-2.0 OR MIT)\n\nfrom __future__ import print_function\n\nimport os\nimport argparse\nimport re\n\nimport llnl.util.tty as tty\nfrom llnl.util.tty.colify import colify\n\nimport spack.cmd\nimport spack.paths\nimport spack.repo\nfrom spack.util.executable import which\n\ndescription = \"query packages associated with particular git revisions\"\nsection = \"developer\"\nlevel = \"long\"\n\n\ndef setup_parser(subparser):\n    sp = subparser.add_subparsers(\n        metavar='SUBCOMMAND', dest='pkg_command')\n\n    add_parser = sp.add_parser('add', help=pkg_add.__doc__)\n    add_parser.add_argument('packages', nargs=argparse.REMAINDER,\n                            help=\"names of packages to add to git repo\")\n\n    list_parser = sp.add_parser('list', help=pkg_list.__doc__)\n    list_parser.add_argument('rev', default='HEAD', nargs='?',\n                             help=\"revision to list packages for\")\n\n    diff_parser = sp.add_parser('diff', help=pkg_diff.__doc__)\n    diff_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    diff_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n    add_parser = sp.add_parser('added', help=pkg_added.__doc__)\n    add_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    add_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n    add_parser = sp.add_parser('changed', help=pkg_changed.__doc__)\n    add_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    add_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n    add_parser.add_argument(\n        '-t', '--type', action='store', default='C',\n        help=\"Types of changes to show (A: added, R: removed, \"\n        \"C: changed); default is 'C'\")\n\n    rm_parser = sp.add_parser('removed', help=pkg_removed.__doc__)\n    rm_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    rm_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n\ndef packages_path():\n    \"\"\"Get the test repo if it is active, otherwise the builtin repo.\"\"\"\n    try:\n        return spack.repo.path.get_repo('builtin.mock').packages_path\n    except spack.repo.UnknownNamespaceError:\n        return spack.repo.path.get_repo('builtin').packages_path\n\n\ndef get_git():\n    \"\"\"Get a git executable that runs *within* the packages path.\"\"\"\n    git = which('git', required=True)\n    git.add_default_arg('-C')\n    git.add_default_arg(packages_path())\n    return git\n\n\ndef list_packages(rev):\n    git = get_git()\n\n    # git ls-tree does not support ... merge-base syntax, so do it manually\n    if rev.endswith('...'):\n        ref = rev.replace('...', '')\n        rev = git('merge-base', ref, 'HEAD', output=str).strip()\n\n    output = git('ls-tree', '--name-only', rev, output=str)\n    return sorted(line for line in output.split('\\n')\n                  if line and not line.startswith('.'))\n\n\ndef pkg_add(args):\n    \"\"\"add a package to the git stage with `git add`\"\"\"\n    for pkg_name in args.packages:\n        filename = spack.repo.path.filename_for_package_name(pkg_name)\n        if not os.path.isfile(filename):\n            tty.die(\"No such package: %s.  Path does not exist:\" %\n                    pkg_name, filename)\n\n        git = get_git()\n        git('add', filename)\n\n\ndef pkg_list(args):\n    \"\"\"list packages associated with a particular spack git revision\"\"\"\n    colify(list_packages(args.rev))\n\n\ndef diff_packages(rev1, rev2):\n    p1 = set(list_packages(rev1))\n    p2 = set(list_packages(rev2))\n    return p1.difference(p2), p2.difference(p1)\n\n\ndef pkg_diff(args):\n    \"\"\"compare packages available in two different git revisions\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n\n    if u1:\n        print(\"%s:\" % args.rev1)\n        colify(sorted(u1), indent=4)\n        if u1:\n            print()\n\n    if u2:\n        print(\"%s:\" % args.rev2)\n        colify(sorted(u2), indent=4)\n\n\ndef pkg_removed(args):\n    \"\"\"show packages removed since a commit\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n    if u1:\n        colify(sorted(u1))\n\n\ndef pkg_added(args):\n    \"\"\"show packages added since a commit\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n    if u2:\n        colify(sorted(u2))\n\n\ndef pkg_changed(args):\n    \"\"\"show packages changed since a commit\"\"\"\n    lower_type = args.type.lower()\n    if not re.match('^[arc]*$', lower_type):\n        tty.die(\"Invald change type: '%s'.\" % args.type,\n                \"Can contain only A (added), R (removed), or C (changed)\")\n\n    removed, added = diff_packages(args.rev1, args.rev2)\n\n    git = get_git()\n    out = git('diff', '--relative', '--name-only', args.rev1, args.rev2,\n              output=str).strip()\n\n    lines = [] if not out else re.split(r'\\s+', out)\n    changed = set()\n    for path in lines:\n        pkg_name, _, _ = path.partition(os.sep)\n        if pkg_name not in added and pkg_name not in removed:\n            changed.add(pkg_name)\n\n    packages = set()\n    if 'a' in lower_type:\n        packages |= added\n    if 'r' in lower_type:\n        packages |= removed\n    if 'c' in lower_type:\n        packages |= changed\n\n    if packages:\n        colify(sorted(packages))\n\n\ndef pkg(parser, args):\n    if not spack.cmd.spack_is_git_repo():\n        tty.die(\"This spack is not a git clone. Can't use 'spack pkg'\")\n\n    action = {'add': pkg_add,\n              'diff': pkg_diff,\n              'list': pkg_list,\n              'removed': pkg_removed,\n              'added': pkg_added,\n              'changed': pkg_changed}\n    action[args.pkg_command](args)\n", "path": "lib/spack/spack/cmd/pkg.py"}], "after_files": [{"content": "# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other\n# Spack Project Developers. See the top-level COPYRIGHT file for details.\n#\n# SPDX-License-Identifier: (Apache-2.0 OR MIT)\n\nfrom __future__ import print_function\n\nimport os\nimport argparse\nimport re\n\nimport llnl.util.tty as tty\nfrom llnl.util.tty.colify import colify\nfrom llnl.util.filesystem import working_dir\n\nimport spack.cmd\nimport spack.paths\nimport spack.repo\nfrom spack.util.executable import which\n\ndescription = \"query packages associated with particular git revisions\"\nsection = \"developer\"\nlevel = \"long\"\n\n\ndef setup_parser(subparser):\n    sp = subparser.add_subparsers(\n        metavar='SUBCOMMAND', dest='pkg_command')\n\n    add_parser = sp.add_parser('add', help=pkg_add.__doc__)\n    add_parser.add_argument('packages', nargs=argparse.REMAINDER,\n                            help=\"names of packages to add to git repo\")\n\n    list_parser = sp.add_parser('list', help=pkg_list.__doc__)\n    list_parser.add_argument('rev', default='HEAD', nargs='?',\n                             help=\"revision to list packages for\")\n\n    diff_parser = sp.add_parser('diff', help=pkg_diff.__doc__)\n    diff_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    diff_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n    add_parser = sp.add_parser('added', help=pkg_added.__doc__)\n    add_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    add_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n    add_parser = sp.add_parser('changed', help=pkg_changed.__doc__)\n    add_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    add_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n    add_parser.add_argument(\n        '-t', '--type', action='store', default='C',\n        help=\"Types of changes to show (A: added, R: removed, \"\n        \"C: changed); default is 'C'\")\n\n    rm_parser = sp.add_parser('removed', help=pkg_removed.__doc__)\n    rm_parser.add_argument(\n        'rev1', nargs='?', default='HEAD^',\n        help=\"revision to compare against\")\n    rm_parser.add_argument(\n        'rev2', nargs='?', default='HEAD',\n        help=\"revision to compare to rev1 (default is HEAD)\")\n\n\ndef packages_path():\n    \"\"\"Get the test repo if it is active, otherwise the builtin repo.\"\"\"\n    try:\n        return spack.repo.path.get_repo('builtin.mock').packages_path\n    except spack.repo.UnknownNamespaceError:\n        return spack.repo.path.get_repo('builtin').packages_path\n\n\nclass GitExe:\n    # Wrapper around Executable for git to set working directory for all\n    # invocations.\n    #\n    # Not using -C as that is not supported for git < 1.8.5.\n    def __init__(self):\n        self._git_cmd = which('git', required=True)\n\n    def __call__(self, *args, **kwargs):\n        with working_dir(packages_path()):\n            return self._git_cmd(*args, **kwargs)\n\n\n_git = None\n\n\ndef get_git():\n    \"\"\"Get a git executable that runs *within* the packages path.\"\"\"\n    global _git\n    if _git is None:\n        _git = GitExe()\n    return _git\n\n\ndef list_packages(rev):\n    git = get_git()\n\n    # git ls-tree does not support ... merge-base syntax, so do it manually\n    if rev.endswith('...'):\n        ref = rev.replace('...', '')\n        rev = git('merge-base', ref, 'HEAD', output=str).strip()\n\n    output = git('ls-tree', '--name-only', rev, output=str)\n    return sorted(line for line in output.split('\\n')\n                  if line and not line.startswith('.'))\n\n\ndef pkg_add(args):\n    \"\"\"add a package to the git stage with `git add`\"\"\"\n    git = get_git()\n\n    for pkg_name in args.packages:\n        filename = spack.repo.path.filename_for_package_name(pkg_name)\n        if not os.path.isfile(filename):\n            tty.die(\"No such package: %s.  Path does not exist:\" %\n                    pkg_name, filename)\n\n        git('add', filename)\n\n\ndef pkg_list(args):\n    \"\"\"list packages associated with a particular spack git revision\"\"\"\n    colify(list_packages(args.rev))\n\n\ndef diff_packages(rev1, rev2):\n    p1 = set(list_packages(rev1))\n    p2 = set(list_packages(rev2))\n    return p1.difference(p2), p2.difference(p1)\n\n\ndef pkg_diff(args):\n    \"\"\"compare packages available in two different git revisions\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n\n    if u1:\n        print(\"%s:\" % args.rev1)\n        colify(sorted(u1), indent=4)\n        if u1:\n            print()\n\n    if u2:\n        print(\"%s:\" % args.rev2)\n        colify(sorted(u2), indent=4)\n\n\ndef pkg_removed(args):\n    \"\"\"show packages removed since a commit\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n    if u1:\n        colify(sorted(u1))\n\n\ndef pkg_added(args):\n    \"\"\"show packages added since a commit\"\"\"\n    u1, u2 = diff_packages(args.rev1, args.rev2)\n    if u2:\n        colify(sorted(u2))\n\n\ndef pkg_changed(args):\n    \"\"\"show packages changed since a commit\"\"\"\n    lower_type = args.type.lower()\n    if not re.match('^[arc]*$', lower_type):\n        tty.die(\"Invald change type: '%s'.\" % args.type,\n                \"Can contain only A (added), R (removed), or C (changed)\")\n\n    removed, added = diff_packages(args.rev1, args.rev2)\n\n    git = get_git()\n    out = git('diff', '--relative', '--name-only', args.rev1, args.rev2,\n              output=str).strip()\n\n    lines = [] if not out else re.split(r'\\s+', out)\n    changed = set()\n    for path in lines:\n        pkg_name, _, _ = path.partition(os.sep)\n        if pkg_name not in added and pkg_name not in removed:\n            changed.add(pkg_name)\n\n    packages = set()\n    if 'a' in lower_type:\n        packages |= added\n    if 'r' in lower_type:\n        packages |= removed\n    if 'c' in lower_type:\n        packages |= changed\n\n    if packages:\n        colify(sorted(packages))\n\n\ndef pkg(parser, args):\n    if not spack.cmd.spack_is_git_repo():\n        tty.die(\"This spack is not a git clone. Can't use 'spack pkg'\")\n\n    action = {'add': pkg_add,\n              'diff': pkg_diff,\n              'list': pkg_list,\n              'removed': pkg_removed,\n              'added': pkg_added,\n              'changed': pkg_changed}\n    action[args.pkg_command](args)\n", "path": "lib/spack/spack/cmd/pkg.py"}]}