We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Please restore --owner= and --group= options to setuptools' sdist command
Tar archives record the Unix ownership (user and group) of each file they contain.  This can cause undesirable variation between source tarballs generated from the same VCS checkout but in different build environments, so `distutils.command.sdist.sdist` has options `--owner=[username]` and `--group=[groupname]` to override the recorded ownership.  However, `setuptools.command.sdist.sdist` supersedes the `user_options` array of its parent class and makes most of the options inaccessible, including `--owner` and `--group`.

Please restore these options.  The simplest change to achieve this would be to copy the `--owner` and `--group` array entries from `distutils.command.sdist.sdist.user_options` to `setuptools.command.sdist.sdist.user_options`.  I have written a monkeypatch in my `setup.py` that does exactly this, so I can confirm that no other changes to setuptools' code are required.  However, a more future-proof change would be to have setuptools.command.sdist.sdist copy its parent class's `user_options` array and *remove* only those entries that are definitely not wanted.
Please restore --owner= and --group= options to setuptools' sdist command
Tar archives record the Unix ownership (user and group) of each file they contain.  This can cause undesirable variation between source tarballs generated from the same VCS checkout but in different build environments, so `distutils.command.sdist.sdist` has options `--owner=[username]` and `--group=[groupname]` to override the recorded ownership.  However, `setuptools.command.sdist.sdist` supersedes the `user_options` array of its parent class and makes most of the options inaccessible, including `--owner` and `--group`.

Please restore these options.  The simplest change to achieve this would be to copy the `--owner` and `--group` array entries from `distutils.command.sdist.sdist.user_options` to `setuptools.command.sdist.sdist.user_options`.  I have written a monkeypatch in my `setup.py` that does exactly this, so I can confirm that no other changes to setuptools' code are required.  However, a more future-proof change would be to have setuptools.command.sdist.sdist copy its parent class's `user_options` array and *remove* only those entries that are definitely not wanted.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setuptools/command/sdist.py`
Content:
```
1 from distutils import log
2 import distutils.command.sdist as orig
3 import os
4 import sys
5 import io
6 import contextlib
7 
8 from .py36compat import sdist_add_defaults
9 
10 import pkg_resources
11 
12 _default_revctrl = list
13 
14 
15 def walk_revctrl(dirname=''):
16     """Find all files under revision control"""
17     for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
18         for item in ep.load()(dirname):
19             yield item
20 
21 
22 class sdist(sdist_add_defaults, orig.sdist):
23     """Smart sdist that finds anything supported by revision control"""
24 
25     user_options = [
26         ('formats=', None,
27          "formats for source distribution (comma-separated list)"),
28         ('keep-temp', 'k',
29          "keep the distribution tree around after creating " +
30          "archive file(s)"),
31         ('dist-dir=', 'd',
32          "directory to put the source distribution archive(s) in "
33          "[default: dist]"),
34     ]
35 
36     negative_opt = {}
37 
38     README_EXTENSIONS = ['', '.rst', '.txt', '.md']
39     READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
40 
41     def run(self):
42         self.run_command('egg_info')
43         ei_cmd = self.get_finalized_command('egg_info')
44         self.filelist = ei_cmd.filelist
45         self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
46         self.check_readme()
47 
48         # Run sub commands
49         for cmd_name in self.get_sub_commands():
50             self.run_command(cmd_name)
51 
52         self.make_distribution()
53 
54         dist_files = getattr(self.distribution, 'dist_files', [])
55         for file in self.archive_files:
56             data = ('sdist', '', file)
57             if data not in dist_files:
58                 dist_files.append(data)
59 
60     def initialize_options(self):
61         orig.sdist.initialize_options(self)
62 
63         self._default_to_gztar()
64 
65     def _default_to_gztar(self):
66         # only needed on Python prior to 3.6.
67         if sys.version_info >= (3, 6, 0, 'beta', 1):
68             return
69         self.formats = ['gztar']
70 
71     def make_distribution(self):
72         """
73         Workaround for #516
74         """
75         with self._remove_os_link():
76             orig.sdist.make_distribution(self)
77 
78     @staticmethod
79     @contextlib.contextmanager
80     def _remove_os_link():
81         """
82         In a context, remove and restore os.link if it exists
83         """
84 
85         class NoValue:
86             pass
87 
88         orig_val = getattr(os, 'link', NoValue)
89         try:
90             del os.link
91         except Exception:
92             pass
93         try:
94             yield
95         finally:
96             if orig_val is not NoValue:
97                 setattr(os, 'link', orig_val)
98 
99     def _add_defaults_optional(self):
100         super()._add_defaults_optional()
101         if os.path.isfile('pyproject.toml'):
102             self.filelist.append('pyproject.toml')
103 
104     def _add_defaults_python(self):
105         """getting python files"""
106         if self.distribution.has_pure_modules():
107             build_py = self.get_finalized_command('build_py')
108             self.filelist.extend(build_py.get_source_files())
109             self._add_data_files(self._safe_data_files(build_py))
110 
111     def _safe_data_files(self, build_py):
112         """
113         Extracting data_files from build_py is known to cause
114         infinite recursion errors when `include_package_data`
115         is enabled, so suppress it in that case.
116         """
117         if self.distribution.include_package_data:
118             return ()
119         return build_py.data_files
120 
121     def _add_data_files(self, data_files):
122         """
123         Add data files as found in build_py.data_files.
124         """
125         self.filelist.extend(
126             os.path.join(src_dir, name)
127             for _, src_dir, _, filenames in data_files
128             for name in filenames
129         )
130 
131     def _add_defaults_data_files(self):
132         try:
133             super()._add_defaults_data_files()
134         except TypeError:
135             log.warn("data_files contains unexpected objects")
136 
137     def check_readme(self):
138         for f in self.READMES:
139             if os.path.exists(f):
140                 return
141         else:
142             self.warn(
143                 "standard file not found: should have one of " +
144                 ', '.join(self.READMES)
145             )
146 
147     def make_release_tree(self, base_dir, files):
148         orig.sdist.make_release_tree(self, base_dir, files)
149 
150         # Save any egg_info command line options used to create this sdist
151         dest = os.path.join(base_dir, 'setup.cfg')
152         if hasattr(os, 'link') and os.path.exists(dest):
153             # unlink and re-copy, since it might be hard-linked, and
154             # we don't want to change the source version
155             os.unlink(dest)
156             self.copy_file('setup.cfg', dest)
157 
158         self.get_finalized_command('egg_info').save_version_info(dest)
159 
160     def _manifest_is_not_generated(self):
161         # check for special comment used in 2.7.1 and higher
162         if not os.path.isfile(self.manifest):
163             return False
164 
165         with io.open(self.manifest, 'rb') as fp:
166             first_line = fp.readline()
167         return (first_line !=
168                 '# file GENERATED by distutils, do NOT edit\n'.encode())
169 
170     def read_manifest(self):
171         """Read the manifest file (named by 'self.manifest') and use it to
172         fill in 'self.filelist', the list of files to include in the source
173         distribution.
174         """
175         log.info("reading manifest file '%s'", self.manifest)
176         manifest = open(self.manifest, 'rb')
177         for line in manifest:
178             # The manifest must contain UTF-8. See #303.
179             try:
180                 line = line.decode('UTF-8')
181             except UnicodeDecodeError:
182                 log.warn("%r not UTF-8 decodable -- skipping" % line)
183                 continue
184             # ignore comments and blank lines
185             line = line.strip()
186             if line.startswith('#') or not line:
187                 continue
188             self.filelist.append(line)
189         manifest.close()
190
```
--- 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/setuptools/command/sdist.py b/setuptools/command/sdist.py
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -31,6 +31,10 @@
         ('dist-dir=', 'd',
          "directory to put the source distribution archive(s) in "
          "[default: dist]"),
+        ('owner=', 'u',
+         "Owner name used when creating a tar file [default: current user]"),
+        ('group=', 'g',
+         "Group name used when creating a tar file [default: current group]"),
     ]
 
     negative_opt = {}

{"golden_diff": "diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py\n--- a/setuptools/command/sdist.py\n+++ b/setuptools/command/sdist.py\n@@ -31,6 +31,10 @@\n         ('dist-dir=', 'd',\n          \"directory to put the source distribution archive(s) in \"\n          \"[default: dist]\"),\n+        ('owner=', 'u',\n+         \"Owner name used when creating a tar file [default: current user]\"),\n+        ('group=', 'g',\n+         \"Group name used when creating a tar file [default: current group]\"),\n     ]\n \n     negative_opt = {}\n", "issue": "Please restore --owner= and --group= options to setuptools' sdist command\nTar archives record the Unix ownership (user and group) of each file they contain.  This can cause undesirable variation between source tarballs generated from the same VCS checkout but in different build environments, so `distutils.command.sdist.sdist` has options `--owner=[username]` and `--group=[groupname]` to override the recorded ownership.  However, `setuptools.command.sdist.sdist` supersedes the `user_options` array of its parent class and makes most of the options inaccessible, including `--owner` and `--group`.\r\n\r\nPlease restore these options.  The simplest change to achieve this would be to copy the `--owner` and `--group` array entries from `distutils.command.sdist.sdist.user_options` to `setuptools.command.sdist.sdist.user_options`.  I have written a monkeypatch in my `setup.py` that does exactly this, so I can confirm that no other changes to setuptools' code are required.  However, a more future-proof change would be to have setuptools.command.sdist.sdist copy its parent class's `user_options` array and *remove* only those entries that are definitely not wanted.\nPlease restore --owner= and --group= options to setuptools' sdist command\nTar archives record the Unix ownership (user and group) of each file they contain.  This can cause undesirable variation between source tarballs generated from the same VCS checkout but in different build environments, so `distutils.command.sdist.sdist` has options `--owner=[username]` and `--group=[groupname]` to override the recorded ownership.  However, `setuptools.command.sdist.sdist` supersedes the `user_options` array of its parent class and makes most of the options inaccessible, including `--owner` and `--group`.\r\n\r\nPlease restore these options.  The simplest change to achieve this would be to copy the `--owner` and `--group` array entries from `distutils.command.sdist.sdist.user_options` to `setuptools.command.sdist.sdist.user_options`.  I have written a monkeypatch in my `setup.py` that does exactly this, so I can confirm that no other changes to setuptools' code are required.  However, a more future-proof change would be to have setuptools.command.sdist.sdist copy its parent class's `user_options` array and *remove* only those entries that are definitely not wanted.\n", "before_files": [{"content": "from distutils import log\nimport distutils.command.sdist as orig\nimport os\nimport sys\nimport io\nimport contextlib\n\nfrom .py36compat import sdist_add_defaults\n\nimport pkg_resources\n\n_default_revctrl = list\n\n\ndef walk_revctrl(dirname=''):\n    \"\"\"Find all files under revision control\"\"\"\n    for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):\n        for item in ep.load()(dirname):\n            yield item\n\n\nclass sdist(sdist_add_defaults, orig.sdist):\n    \"\"\"Smart sdist that finds anything supported by revision control\"\"\"\n\n    user_options = [\n        ('formats=', None,\n         \"formats for source distribution (comma-separated list)\"),\n        ('keep-temp', 'k',\n         \"keep the distribution tree around after creating \" +\n         \"archive file(s)\"),\n        ('dist-dir=', 'd',\n         \"directory to put the source distribution archive(s) in \"\n         \"[default: dist]\"),\n    ]\n\n    negative_opt = {}\n\n    README_EXTENSIONS = ['', '.rst', '.txt', '.md']\n    READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)\n\n    def run(self):\n        self.run_command('egg_info')\n        ei_cmd = self.get_finalized_command('egg_info')\n        self.filelist = ei_cmd.filelist\n        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))\n        self.check_readme()\n\n        # Run sub commands\n        for cmd_name in self.get_sub_commands():\n            self.run_command(cmd_name)\n\n        self.make_distribution()\n\n        dist_files = getattr(self.distribution, 'dist_files', [])\n        for file in self.archive_files:\n            data = ('sdist', '', file)\n            if data not in dist_files:\n                dist_files.append(data)\n\n    def initialize_options(self):\n        orig.sdist.initialize_options(self)\n\n        self._default_to_gztar()\n\n    def _default_to_gztar(self):\n        # only needed on Python prior to 3.6.\n        if sys.version_info >= (3, 6, 0, 'beta', 1):\n            return\n        self.formats = ['gztar']\n\n    def make_distribution(self):\n        \"\"\"\n        Workaround for #516\n        \"\"\"\n        with self._remove_os_link():\n            orig.sdist.make_distribution(self)\n\n    @staticmethod\n    @contextlib.contextmanager\n    def _remove_os_link():\n        \"\"\"\n        In a context, remove and restore os.link if it exists\n        \"\"\"\n\n        class NoValue:\n            pass\n\n        orig_val = getattr(os, 'link', NoValue)\n        try:\n            del os.link\n        except Exception:\n            pass\n        try:\n            yield\n        finally:\n            if orig_val is not NoValue:\n                setattr(os, 'link', orig_val)\n\n    def _add_defaults_optional(self):\n        super()._add_defaults_optional()\n        if os.path.isfile('pyproject.toml'):\n            self.filelist.append('pyproject.toml')\n\n    def _add_defaults_python(self):\n        \"\"\"getting python files\"\"\"\n        if self.distribution.has_pure_modules():\n            build_py = self.get_finalized_command('build_py')\n            self.filelist.extend(build_py.get_source_files())\n            self._add_data_files(self._safe_data_files(build_py))\n\n    def _safe_data_files(self, build_py):\n        \"\"\"\n        Extracting data_files from build_py is known to cause\n        infinite recursion errors when `include_package_data`\n        is enabled, so suppress it in that case.\n        \"\"\"\n        if self.distribution.include_package_data:\n            return ()\n        return build_py.data_files\n\n    def _add_data_files(self, data_files):\n        \"\"\"\n        Add data files as found in build_py.data_files.\n        \"\"\"\n        self.filelist.extend(\n            os.path.join(src_dir, name)\n            for _, src_dir, _, filenames in data_files\n            for name in filenames\n        )\n\n    def _add_defaults_data_files(self):\n        try:\n            super()._add_defaults_data_files()\n        except TypeError:\n            log.warn(\"data_files contains unexpected objects\")\n\n    def check_readme(self):\n        for f in self.READMES:\n            if os.path.exists(f):\n                return\n        else:\n            self.warn(\n                \"standard file not found: should have one of \" +\n                ', '.join(self.READMES)\n            )\n\n    def make_release_tree(self, base_dir, files):\n        orig.sdist.make_release_tree(self, base_dir, files)\n\n        # Save any egg_info command line options used to create this sdist\n        dest = os.path.join(base_dir, 'setup.cfg')\n        if hasattr(os, 'link') and os.path.exists(dest):\n            # unlink and re-copy, since it might be hard-linked, and\n            # we don't want to change the source version\n            os.unlink(dest)\n            self.copy_file('setup.cfg', dest)\n\n        self.get_finalized_command('egg_info').save_version_info(dest)\n\n    def _manifest_is_not_generated(self):\n        # check for special comment used in 2.7.1 and higher\n        if not os.path.isfile(self.manifest):\n            return False\n\n        with io.open(self.manifest, 'rb') as fp:\n            first_line = fp.readline()\n        return (first_line !=\n                '# file GENERATED by distutils, do NOT edit\\n'.encode())\n\n    def read_manifest(self):\n        \"\"\"Read the manifest file (named by 'self.manifest') and use it to\n        fill in 'self.filelist', the list of files to include in the source\n        distribution.\n        \"\"\"\n        log.info(\"reading manifest file '%s'\", self.manifest)\n        manifest = open(self.manifest, 'rb')\n        for line in manifest:\n            # The manifest must contain UTF-8. See #303.\n            try:\n                line = line.decode('UTF-8')\n            except UnicodeDecodeError:\n                log.warn(\"%r not UTF-8 decodable -- skipping\" % line)\n                continue\n            # ignore comments and blank lines\n            line = line.strip()\n            if line.startswith('#') or not line:\n                continue\n            self.filelist.append(line)\n        manifest.close()\n", "path": "setuptools/command/sdist.py"}], "after_files": [{"content": "from distutils import log\nimport distutils.command.sdist as orig\nimport os\nimport sys\nimport io\nimport contextlib\n\nfrom .py36compat import sdist_add_defaults\n\nimport pkg_resources\n\n_default_revctrl = list\n\n\ndef walk_revctrl(dirname=''):\n    \"\"\"Find all files under revision control\"\"\"\n    for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):\n        for item in ep.load()(dirname):\n            yield item\n\n\nclass sdist(sdist_add_defaults, orig.sdist):\n    \"\"\"Smart sdist that finds anything supported by revision control\"\"\"\n\n    user_options = [\n        ('formats=', None,\n         \"formats for source distribution (comma-separated list)\"),\n        ('keep-temp', 'k',\n         \"keep the distribution tree around after creating \" +\n         \"archive file(s)\"),\n        ('dist-dir=', 'd',\n         \"directory to put the source distribution archive(s) in \"\n         \"[default: dist]\"),\n        ('owner=', 'u',\n         \"Owner name used when creating a tar file [default: current user]\"),\n        ('group=', 'g',\n         \"Group name used when creating a tar file [default: current group]\"),\n    ]\n\n    negative_opt = {}\n\n    README_EXTENSIONS = ['', '.rst', '.txt', '.md']\n    READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)\n\n    def run(self):\n        self.run_command('egg_info')\n        ei_cmd = self.get_finalized_command('egg_info')\n        self.filelist = ei_cmd.filelist\n        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))\n        self.check_readme()\n\n        # Run sub commands\n        for cmd_name in self.get_sub_commands():\n            self.run_command(cmd_name)\n\n        self.make_distribution()\n\n        dist_files = getattr(self.distribution, 'dist_files', [])\n        for file in self.archive_files:\n            data = ('sdist', '', file)\n            if data not in dist_files:\n                dist_files.append(data)\n\n    def initialize_options(self):\n        orig.sdist.initialize_options(self)\n\n        self._default_to_gztar()\n\n    def _default_to_gztar(self):\n        # only needed on Python prior to 3.6.\n        if sys.version_info >= (3, 6, 0, 'beta', 1):\n            return\n        self.formats = ['gztar']\n\n    def make_distribution(self):\n        \"\"\"\n        Workaround for #516\n        \"\"\"\n        with self._remove_os_link():\n            orig.sdist.make_distribution(self)\n\n    @staticmethod\n    @contextlib.contextmanager\n    def _remove_os_link():\n        \"\"\"\n        In a context, remove and restore os.link if it exists\n        \"\"\"\n\n        class NoValue:\n            pass\n\n        orig_val = getattr(os, 'link', NoValue)\n        try:\n            del os.link\n        except Exception:\n            pass\n        try:\n            yield\n        finally:\n            if orig_val is not NoValue:\n                setattr(os, 'link', orig_val)\n\n    def _add_defaults_optional(self):\n        super()._add_defaults_optional()\n        if os.path.isfile('pyproject.toml'):\n            self.filelist.append('pyproject.toml')\n\n    def _add_defaults_python(self):\n        \"\"\"getting python files\"\"\"\n        if self.distribution.has_pure_modules():\n            build_py = self.get_finalized_command('build_py')\n            self.filelist.extend(build_py.get_source_files())\n            self._add_data_files(self._safe_data_files(build_py))\n\n    def _safe_data_files(self, build_py):\n        \"\"\"\n        Extracting data_files from build_py is known to cause\n        infinite recursion errors when `include_package_data`\n        is enabled, so suppress it in that case.\n        \"\"\"\n        if self.distribution.include_package_data:\n            return ()\n        return build_py.data_files\n\n    def _add_data_files(self, data_files):\n        \"\"\"\n        Add data files as found in build_py.data_files.\n        \"\"\"\n        self.filelist.extend(\n            os.path.join(src_dir, name)\n            for _, src_dir, _, filenames in data_files\n            for name in filenames\n        )\n\n    def _add_defaults_data_files(self):\n        try:\n            super()._add_defaults_data_files()\n        except TypeError:\n            log.warn(\"data_files contains unexpected objects\")\n\n    def check_readme(self):\n        for f in self.READMES:\n            if os.path.exists(f):\n                return\n        else:\n            self.warn(\n                \"standard file not found: should have one of \" +\n                ', '.join(self.READMES)\n            )\n\n    def make_release_tree(self, base_dir, files):\n        orig.sdist.make_release_tree(self, base_dir, files)\n\n        # Save any egg_info command line options used to create this sdist\n        dest = os.path.join(base_dir, 'setup.cfg')\n        if hasattr(os, 'link') and os.path.exists(dest):\n            # unlink and re-copy, since it might be hard-linked, and\n            # we don't want to change the source version\n            os.unlink(dest)\n            self.copy_file('setup.cfg', dest)\n\n        self.get_finalized_command('egg_info').save_version_info(dest)\n\n    def _manifest_is_not_generated(self):\n        # check for special comment used in 2.7.1 and higher\n        if not os.path.isfile(self.manifest):\n            return False\n\n        with io.open(self.manifest, 'rb') as fp:\n            first_line = fp.readline()\n        return (first_line !=\n                '# file GENERATED by distutils, do NOT edit\\n'.encode())\n\n    def read_manifest(self):\n        \"\"\"Read the manifest file (named by 'self.manifest') and use it to\n        fill in 'self.filelist', the list of files to include in the source\n        distribution.\n        \"\"\"\n        log.info(\"reading manifest file '%s'\", self.manifest)\n        manifest = open(self.manifest, 'rb')\n        for line in manifest:\n            # The manifest must contain UTF-8. See #303.\n            try:\n                line = line.decode('UTF-8')\n            except UnicodeDecodeError:\n                log.warn(\"%r not UTF-8 decodable -- skipping\" % line)\n                continue\n            # ignore comments and blank lines\n            line = line.strip()\n            if line.startswith('#') or not line:\n                continue\n            self.filelist.append(line)\n        manifest.close()\n", "path": "setuptools/command/sdist.py"}]}