update
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
Package containing implementation of all the standard Distutils
|
||||
commands."""
|
||||
|
||||
__all__ = [ # noqa: F822
|
||||
__all__ = [
|
||||
'build',
|
||||
'build_py',
|
||||
'build_ext',
|
||||
@@ -16,10 +16,8 @@ __all__ = [ # noqa: F822
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
'sdist',
|
||||
'register',
|
||||
'bdist',
|
||||
'bdist_dumb',
|
||||
'bdist_rpm',
|
||||
'check',
|
||||
'upload',
|
||||
]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,15 +2,14 @@
|
||||
Backward compatibility for homebrew builds on macOS.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import functools
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
@functools.lru_cache
|
||||
def enabled():
|
||||
"""
|
||||
Only enabled for Python 3.9 framework homebrew builds
|
||||
@@ -38,7 +37,7 @@ schemes = dict(
|
||||
)
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
@functools.lru_cache
|
||||
def vars():
|
||||
if not enabled():
|
||||
return {}
|
||||
|
||||
@@ -7,7 +7,7 @@ import os
|
||||
import warnings
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsPlatformError, DistutilsOptionError
|
||||
from ..errors import DistutilsOptionError, DistutilsPlatformError
|
||||
from ..util import get_platform
|
||||
|
||||
|
||||
@@ -15,9 +15,10 @@ def show_formats():
|
||||
"""Print list of available formats (arguments to "--format" option)."""
|
||||
from ..fancy_getopt import FancyGetopt
|
||||
|
||||
formats = []
|
||||
for format in bdist.format_commands:
|
||||
formats.append(("formats=" + format, None, bdist.format_commands[format][1]))
|
||||
formats = [
|
||||
("formats=" + format, None, bdist.format_commands[format][1])
|
||||
for format in bdist.format_commands
|
||||
]
|
||||
pretty_printer = FancyGetopt(formats)
|
||||
pretty_printer.print_help("List of available distribution formats:")
|
||||
|
||||
@@ -41,24 +42,24 @@ class bdist(Command):
|
||||
'plat-name=',
|
||||
'p',
|
||||
"platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_platform(),
|
||||
f"[default: {get_platform()}]",
|
||||
),
|
||||
('formats=', None, "formats for distribution (comma-separated list)"),
|
||||
(
|
||||
'dist-dir=',
|
||||
'd',
|
||||
"directory to put final built distributions in " "[default: dist]",
|
||||
"directory to put final built distributions in [default: dist]",
|
||||
),
|
||||
('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
|
||||
(
|
||||
'owner=',
|
||||
'u',
|
||||
"Owner name used when creating a tar file" " [default: current user]",
|
||||
"Owner name used when creating a tar file [default: current user]",
|
||||
),
|
||||
(
|
||||
'group=',
|
||||
'g',
|
||||
"Group name used when creating a tar file" " [default: current group]",
|
||||
"Group name used when creating a tar file [default: current group]",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -76,17 +77,15 @@ class bdist(Command):
|
||||
default_format = {'posix': 'gztar', 'nt': 'zip'}
|
||||
|
||||
# Define commands in preferred order for the --help-formats option
|
||||
format_commands = ListCompat(
|
||||
{
|
||||
'rpm': ('bdist_rpm', "RPM distribution"),
|
||||
'gztar': ('bdist_dumb', "gzip'ed tar file"),
|
||||
'bztar': ('bdist_dumb', "bzip2'ed tar file"),
|
||||
'xztar': ('bdist_dumb', "xz'ed tar file"),
|
||||
'ztar': ('bdist_dumb', "compressed tar file"),
|
||||
'tar': ('bdist_dumb', "tar file"),
|
||||
'zip': ('bdist_dumb', "ZIP file"),
|
||||
}
|
||||
)
|
||||
format_commands = ListCompat({
|
||||
'rpm': ('bdist_rpm', "RPM distribution"),
|
||||
'gztar': ('bdist_dumb', "gzip'ed tar file"),
|
||||
'bztar': ('bdist_dumb', "bzip2'ed tar file"),
|
||||
'xztar': ('bdist_dumb', "xz'ed tar file"),
|
||||
'ztar': ('bdist_dumb', "compressed tar file"),
|
||||
'tar': ('bdist_dumb', "tar file"),
|
||||
'zip': ('bdist_dumb', "ZIP file"),
|
||||
})
|
||||
|
||||
# for compatibility until consumers only reference format_commands
|
||||
format_command = format_commands
|
||||
@@ -96,7 +95,7 @@ class bdist(Command):
|
||||
self.plat_name = None
|
||||
self.formats = None
|
||||
self.dist_dir = None
|
||||
self.skip_build = 0
|
||||
self.skip_build = False
|
||||
self.group = None
|
||||
self.owner = None
|
||||
|
||||
@@ -122,7 +121,7 @@ class bdist(Command):
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create built distributions "
|
||||
"on platform %s" % os.name
|
||||
f"on platform {os.name}"
|
||||
)
|
||||
|
||||
if self.dist_dir is None:
|
||||
@@ -135,7 +134,7 @@ class bdist(Command):
|
||||
try:
|
||||
commands.append(self.format_commands[format][0])
|
||||
except KeyError:
|
||||
raise DistutilsOptionError("invalid format '%s'" % format)
|
||||
raise DistutilsOptionError(f"invalid format '{format}'")
|
||||
|
||||
# Reinitialize and run each command.
|
||||
for i in range(len(self.formats)):
|
||||
@@ -152,5 +151,5 @@ class bdist(Command):
|
||||
# If we're going to need to run this command again, tell it to
|
||||
# keep its temporary files around so subsequent runs go faster.
|
||||
if cmd_name in commands[i + 1 :]:
|
||||
sub_cmd.keep_temp = 1
|
||||
sub_cmd.keep_temp = True
|
||||
self.run_command(cmd_name)
|
||||
|
||||
@@ -5,12 +5,13 @@ distribution -- i.e., just an archive to be unpacked under $prefix or
|
||||
$exec_prefix)."""
|
||||
|
||||
import os
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..util import get_platform
|
||||
from ..dir_util import remove_tree, ensure_relative
|
||||
from ..dir_util import ensure_relative, remove_tree
|
||||
from ..errors import DistutilsPlatformError
|
||||
from ..sysconfig import get_python_version
|
||||
from distutils._log import log
|
||||
from ..util import get_platform
|
||||
|
||||
|
||||
class bdist_dumb(Command):
|
||||
@@ -22,35 +23,34 @@ class bdist_dumb(Command):
|
||||
'plat-name=',
|
||||
'p',
|
||||
"platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_platform(),
|
||||
f"[default: {get_platform()}]",
|
||||
),
|
||||
(
|
||||
'format=',
|
||||
'f',
|
||||
"archive format to create (tar, gztar, bztar, xztar, " "ztar, zip)",
|
||||
"archive format to create (tar, gztar, bztar, xztar, ztar, zip)",
|
||||
),
|
||||
(
|
||||
'keep-temp',
|
||||
'k',
|
||||
"keep the pseudo-installation tree around after "
|
||||
+ "creating the distribution archive",
|
||||
"keep the pseudo-installation tree around after creating the distribution archive",
|
||||
),
|
||||
('dist-dir=', 'd', "directory to put final built distributions in"),
|
||||
('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
|
||||
(
|
||||
'relative',
|
||||
None,
|
||||
"build the archive using relative paths " "(default: false)",
|
||||
"build the archive using relative paths [default: false]",
|
||||
),
|
||||
(
|
||||
'owner=',
|
||||
'u',
|
||||
"Owner name used when creating a tar file" " [default: current user]",
|
||||
"Owner name used when creating a tar file [default: current user]",
|
||||
),
|
||||
(
|
||||
'group=',
|
||||
'g',
|
||||
"Group name used when creating a tar file" " [default: current group]",
|
||||
"Group name used when creating a tar file [default: current group]",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -62,10 +62,10 @@ class bdist_dumb(Command):
|
||||
self.bdist_dir = None
|
||||
self.plat_name = None
|
||||
self.format = None
|
||||
self.keep_temp = 0
|
||||
self.keep_temp = False
|
||||
self.dist_dir = None
|
||||
self.skip_build = None
|
||||
self.relative = 0
|
||||
self.relative = False
|
||||
self.owner = None
|
||||
self.group = None
|
||||
|
||||
@@ -80,7 +80,7 @@ class bdist_dumb(Command):
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create dumb built distributions "
|
||||
"on platform %s" % os.name
|
||||
f"on platform {os.name}"
|
||||
)
|
||||
|
||||
self.set_undefined_options(
|
||||
@@ -94,19 +94,17 @@ class bdist_dumb(Command):
|
||||
if not self.skip_build:
|
||||
self.run_command('build')
|
||||
|
||||
install = self.reinitialize_command('install', reinit_subcommands=1)
|
||||
install = self.reinitialize_command('install', reinit_subcommands=True)
|
||||
install.root = self.bdist_dir
|
||||
install.skip_build = self.skip_build
|
||||
install.warn_dir = 0
|
||||
install.warn_dir = False
|
||||
|
||||
log.info("installing to %s", self.bdist_dir)
|
||||
self.run_command('install')
|
||||
|
||||
# And make an archive relative to the root of the
|
||||
# pseudo-installation tree.
|
||||
archive_basename = "{}.{}".format(
|
||||
self.distribution.get_fullname(), self.plat_name
|
||||
)
|
||||
archive_basename = f"{self.distribution.get_fullname()}.{self.plat_name}"
|
||||
|
||||
pseudoinstall_root = os.path.join(self.dist_dir, archive_basename)
|
||||
if not self.relative:
|
||||
@@ -117,8 +115,7 @@ class bdist_dumb(Command):
|
||||
):
|
||||
raise DistutilsPlatformError(
|
||||
"can't make a dumb built distribution where "
|
||||
"base and platbase are different (%s, %s)"
|
||||
% (repr(install.install_base), repr(install.install_platbase))
|
||||
f"base and platbase are different ({install.install_base!r}, {install.install_platbase!r})"
|
||||
)
|
||||
else:
|
||||
archive_root = os.path.join(
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
Implements the Distutils 'bdist_rpm' command (create RPM source and binary
|
||||
distributions)."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..debug import DEBUG
|
||||
from ..file_util import write_file
|
||||
from ..errors import (
|
||||
DistutilsExecError,
|
||||
DistutilsFileError,
|
||||
DistutilsOptionError,
|
||||
DistutilsPlatformError,
|
||||
DistutilsFileError,
|
||||
DistutilsExecError,
|
||||
)
|
||||
from ..file_util import write_file
|
||||
from ..sysconfig import get_python_version
|
||||
from distutils._log import log
|
||||
|
||||
|
||||
class bdist_rpm(Command):
|
||||
@@ -34,13 +34,13 @@ class bdist_rpm(Command):
|
||||
(
|
||||
'dist-dir=',
|
||||
'd',
|
||||
"directory to put final RPM files in " "(and .spec files if --spec-only)",
|
||||
"directory to put final RPM files in (and .spec files if --spec-only)",
|
||||
),
|
||||
(
|
||||
'python=',
|
||||
None,
|
||||
"path to Python interpreter to hard-code in the .spec file "
|
||||
"(default: \"python\")",
|
||||
"[default: \"python\"]",
|
||||
),
|
||||
(
|
||||
'fix-python',
|
||||
@@ -75,7 +75,7 @@ class bdist_rpm(Command):
|
||||
(
|
||||
'packager=',
|
||||
None,
|
||||
"RPM packager (eg. \"Jane Doe <jane@example.net>\") " "[default: vendor]",
|
||||
"RPM packager (eg. \"Jane Doe <jane@example.net>\") [default: vendor]",
|
||||
),
|
||||
('doc-files=', None, "list of documentation files (space or comma-separated)"),
|
||||
('changelog=', None, "RPM changelog"),
|
||||
@@ -187,13 +187,13 @@ class bdist_rpm(Command):
|
||||
self.build_requires = None
|
||||
self.obsoletes = None
|
||||
|
||||
self.keep_temp = 0
|
||||
self.use_rpm_opt_flags = 1
|
||||
self.rpm3_mode = 1
|
||||
self.no_autoreq = 0
|
||||
self.keep_temp = False
|
||||
self.use_rpm_opt_flags = True
|
||||
self.rpm3_mode = True
|
||||
self.no_autoreq = False
|
||||
|
||||
self.force_arch = None
|
||||
self.quiet = 0
|
||||
self.quiet = False
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('bdist', ('bdist_base', 'bdist_base'))
|
||||
@@ -214,7 +214,7 @@ class bdist_rpm(Command):
|
||||
|
||||
if os.name != 'posix':
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create RPM " "distributions on platform %s" % os.name
|
||||
f"don't know how to create RPM distributions on platform {os.name}"
|
||||
)
|
||||
if self.binary_only and self.source_only:
|
||||
raise DistutilsOptionError(
|
||||
@@ -223,7 +223,7 @@ class bdist_rpm(Command):
|
||||
|
||||
# don't pass CFLAGS to pure python distributions
|
||||
if not self.distribution.has_ext_modules():
|
||||
self.use_rpm_opt_flags = 0
|
||||
self.use_rpm_opt_flags = False
|
||||
|
||||
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
||||
self.finalize_package_data()
|
||||
@@ -232,8 +232,7 @@ class bdist_rpm(Command):
|
||||
self.ensure_string('group', "Development/Libraries")
|
||||
self.ensure_string(
|
||||
'vendor',
|
||||
"%s <%s>"
|
||||
% (self.distribution.get_contact(), self.distribution.get_contact_email()),
|
||||
f"{self.distribution.get_contact()} <{self.distribution.get_contact_email()}>",
|
||||
)
|
||||
self.ensure_string('packager')
|
||||
self.ensure_string_list('doc_files')
|
||||
@@ -296,9 +295,9 @@ class bdist_rpm(Command):
|
||||
|
||||
# Spec file goes into 'dist_dir' if '--spec-only specified',
|
||||
# build/rpm.<plat> otherwise.
|
||||
spec_path = os.path.join(spec_dir, "%s.spec" % self.distribution.get_name())
|
||||
spec_path = os.path.join(spec_dir, f"{self.distribution.get_name()}.spec")
|
||||
self.execute(
|
||||
write_file, (spec_path, self._make_spec_file()), "writing '%s'" % spec_path
|
||||
write_file, (spec_path, self._make_spec_file()), f"writing '{spec_path}'"
|
||||
)
|
||||
|
||||
if self.spec_only: # stop if requested
|
||||
@@ -323,7 +322,7 @@ class bdist_rpm(Command):
|
||||
if os.path.exists(self.icon):
|
||||
self.copy_file(self.icon, source_dir)
|
||||
else:
|
||||
raise DistutilsFileError("icon file '%s' does not exist" % self.icon)
|
||||
raise DistutilsFileError(f"icon file '{self.icon}' does not exist")
|
||||
|
||||
# build package
|
||||
log.info("building RPMs")
|
||||
@@ -335,9 +334,9 @@ class bdist_rpm(Command):
|
||||
rpm_cmd.append('-bb')
|
||||
else:
|
||||
rpm_cmd.append('-ba')
|
||||
rpm_cmd.extend(['--define', '__python %s' % self.python])
|
||||
rpm_cmd.extend(['--define', f'__python {self.python}'])
|
||||
if self.rpm3_mode:
|
||||
rpm_cmd.extend(['--define', '_topdir %s' % os.path.abspath(self.rpm_base)])
|
||||
rpm_cmd.extend(['--define', f'_topdir {os.path.abspath(self.rpm_base)}'])
|
||||
if not self.keep_temp:
|
||||
rpm_cmd.append('--clean')
|
||||
|
||||
@@ -352,11 +351,7 @@ class bdist_rpm(Command):
|
||||
nvr_string = "%{name}-%{version}-%{release}"
|
||||
src_rpm = nvr_string + ".src.rpm"
|
||||
non_src_rpm = "%{arch}/" + nvr_string + ".%{arch}.rpm"
|
||||
q_cmd = r"rpm -q --qf '{} {}\n' --specfile '{}'".format(
|
||||
src_rpm,
|
||||
non_src_rpm,
|
||||
spec_path,
|
||||
)
|
||||
q_cmd = rf"rpm -q --qf '{src_rpm} {non_src_rpm}\n' --specfile '{spec_path}'"
|
||||
|
||||
out = os.popen(q_cmd)
|
||||
try:
|
||||
@@ -375,7 +370,7 @@ class bdist_rpm(Command):
|
||||
|
||||
status = out.close()
|
||||
if status:
|
||||
raise DistutilsExecError("Failed to execute: %s" % repr(q_cmd))
|
||||
raise DistutilsExecError(f"Failed to execute: {q_cmd!r}")
|
||||
|
||||
finally:
|
||||
out.close()
|
||||
@@ -401,9 +396,11 @@ class bdist_rpm(Command):
|
||||
if os.path.exists(rpm):
|
||||
self.move_file(rpm, self.dist_dir)
|
||||
filename = os.path.join(self.dist_dir, os.path.basename(rpm))
|
||||
self.distribution.dist_files.append(
|
||||
('bdist_rpm', pyversion, filename)
|
||||
)
|
||||
self.distribution.dist_files.append((
|
||||
'bdist_rpm',
|
||||
pyversion,
|
||||
filename,
|
||||
))
|
||||
|
||||
def _dist_path(self, path):
|
||||
return os.path.join(self.dist_dir, os.path.basename(path))
|
||||
@@ -428,14 +425,14 @@ class bdist_rpm(Command):
|
||||
# Generate a potential replacement value for __os_install_post (whilst
|
||||
# normalizing the whitespace to simplify the test for whether the
|
||||
# invocation of brp-python-bytecompile passes in __python):
|
||||
vendor_hook = '\n'.join(
|
||||
[' %s \\' % line.strip() for line in vendor_hook.splitlines()]
|
||||
)
|
||||
vendor_hook = '\n'.join([
|
||||
f' {line.strip()} \\' for line in vendor_hook.splitlines()
|
||||
])
|
||||
problem = "brp-python-bytecompile \\\n"
|
||||
fixed = "brp-python-bytecompile %{__python} \\\n"
|
||||
fixed_hook = vendor_hook.replace(problem, fixed)
|
||||
if fixed_hook != vendor_hook:
|
||||
spec_file.append('# Workaround for http://bugs.python.org/issue14443')
|
||||
spec_file.append('# Workaround for https://bugs.python.org/issue14443')
|
||||
spec_file.append('%define __os_install_post ' + fixed_hook + '\n')
|
||||
|
||||
# put locale summaries into spec file
|
||||
@@ -445,13 +442,11 @@ class bdist_rpm(Command):
|
||||
# spec_file.append('Summary(%s): %s' % (locale,
|
||||
# self.summaries[locale]))
|
||||
|
||||
spec_file.extend(
|
||||
[
|
||||
'Name: %{name}',
|
||||
'Version: %{version}',
|
||||
'Release: %{release}',
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'Name: %{name}',
|
||||
'Version: %{version}',
|
||||
'Release: %{release}',
|
||||
])
|
||||
|
||||
# XXX yuck! this filename is available from the "sdist" command,
|
||||
# but only after it has run: and we create the spec file before
|
||||
@@ -461,21 +456,19 @@ class bdist_rpm(Command):
|
||||
else:
|
||||
spec_file.append('Source0: %{name}-%{unmangled_version}.tar.gz')
|
||||
|
||||
spec_file.extend(
|
||||
[
|
||||
'License: ' + (self.distribution.get_license() or "UNKNOWN"),
|
||||
'Group: ' + self.group,
|
||||
'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot',
|
||||
'Prefix: %{_prefix}',
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'License: ' + (self.distribution.get_license() or "UNKNOWN"),
|
||||
'Group: ' + self.group,
|
||||
'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot',
|
||||
'Prefix: %{_prefix}',
|
||||
])
|
||||
|
||||
if not self.force_arch:
|
||||
# noarch if no extension modules
|
||||
if not self.distribution.has_ext_modules():
|
||||
spec_file.append('BuildArch: noarch')
|
||||
else:
|
||||
spec_file.append('BuildArch: %s' % self.force_arch)
|
||||
spec_file.append(f'BuildArch: {self.force_arch}')
|
||||
|
||||
for field in (
|
||||
'Vendor',
|
||||
@@ -489,7 +482,7 @@ class bdist_rpm(Command):
|
||||
if isinstance(val, list):
|
||||
spec_file.append('{}: {}'.format(field, ' '.join(val)))
|
||||
elif val is not None:
|
||||
spec_file.append('{}: {}'.format(field, val))
|
||||
spec_file.append(f'{field}: {val}')
|
||||
|
||||
if self.distribution.get_url():
|
||||
spec_file.append('Url: ' + self.distribution.get_url())
|
||||
@@ -506,13 +499,11 @@ class bdist_rpm(Command):
|
||||
if self.no_autoreq:
|
||||
spec_file.append('AutoReq: 0')
|
||||
|
||||
spec_file.extend(
|
||||
[
|
||||
'',
|
||||
'%description',
|
||||
self.distribution.get_long_description() or "",
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%description',
|
||||
self.distribution.get_long_description() or "",
|
||||
])
|
||||
|
||||
# put locale descriptions into spec file
|
||||
# XXX again, suppressed because config file syntax doesn't
|
||||
@@ -526,8 +517,8 @@ class bdist_rpm(Command):
|
||||
|
||||
# rpm scripts
|
||||
# figure out default build script
|
||||
def_setup_call = "{} {}".format(self.python, os.path.basename(sys.argv[0]))
|
||||
def_build = "%s build" % def_setup_call
|
||||
def_setup_call = f"{self.python} {os.path.basename(sys.argv[0])}"
|
||||
def_build = f"{def_setup_call} build"
|
||||
if self.use_rpm_opt_flags:
|
||||
def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build
|
||||
|
||||
@@ -537,9 +528,7 @@ class bdist_rpm(Command):
|
||||
# that we open and interpolate into the spec file, but the defaults
|
||||
# are just text that we drop in as-is. Hmmm.
|
||||
|
||||
install_cmd = (
|
||||
'%s install -O1 --root=$RPM_BUILD_ROOT ' '--record=INSTALLED_FILES'
|
||||
) % def_setup_call
|
||||
install_cmd = f'{def_setup_call} install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES'
|
||||
|
||||
script_options = [
|
||||
('prep', 'prep_script', "%setup -n %{name}-%{unmangled_version}"),
|
||||
@@ -558,12 +547,10 @@ class bdist_rpm(Command):
|
||||
# use 'default' as contents of script
|
||||
val = getattr(self, attr)
|
||||
if val or default:
|
||||
spec_file.extend(
|
||||
[
|
||||
'',
|
||||
'%' + rpm_opt,
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%' + rpm_opt,
|
||||
])
|
||||
if val:
|
||||
with open(val) as f:
|
||||
spec_file.extend(f.read().split('\n'))
|
||||
@@ -571,24 +558,20 @@ class bdist_rpm(Command):
|
||||
spec_file.append(default)
|
||||
|
||||
# files section
|
||||
spec_file.extend(
|
||||
[
|
||||
'',
|
||||
'%files -f INSTALLED_FILES',
|
||||
'%defattr(-,root,root)',
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%files -f INSTALLED_FILES',
|
||||
'%defattr(-,root,root)',
|
||||
])
|
||||
|
||||
if self.doc_files:
|
||||
spec_file.append('%doc ' + ' '.join(self.doc_files))
|
||||
|
||||
if self.changelog:
|
||||
spec_file.extend(
|
||||
[
|
||||
'',
|
||||
'%changelog',
|
||||
]
|
||||
)
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%changelog',
|
||||
])
|
||||
spec_file.extend(self.changelog)
|
||||
|
||||
return spec_file
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
Implements the Distutils 'build' command."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsOptionError
|
||||
from ..util import get_platform
|
||||
@@ -25,16 +27,14 @@ class build(Command):
|
||||
(
|
||||
'build-lib=',
|
||||
None,
|
||||
"build directory for all distribution (defaults to either "
|
||||
+ "build-purelib or build-platlib",
|
||||
"build directory for all distribution (defaults to either build-purelib or build-platlib",
|
||||
),
|
||||
('build-scripts=', None, "build directory for scripts"),
|
||||
('build-temp=', 't', "temporary build directory"),
|
||||
(
|
||||
'plat-name=',
|
||||
'p',
|
||||
"platform name to build for, if supported "
|
||||
"(default: %s)" % get_platform(),
|
||||
f"platform name to build for, if supported [default: {get_platform()}]",
|
||||
),
|
||||
('compiler=', 'c', "specify the compiler type"),
|
||||
('parallel=', 'j', "number of parallel build jobs"),
|
||||
@@ -61,7 +61,7 @@ class build(Command):
|
||||
self.compiler = None
|
||||
self.plat_name = None
|
||||
self.debug = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.executable = None
|
||||
self.parallel = None
|
||||
|
||||
@@ -78,7 +78,11 @@ class build(Command):
|
||||
"using './configure --help' on your platform)"
|
||||
)
|
||||
|
||||
plat_specifier = ".{}-{}".format(self.plat_name, sys.implementation.cache_tag)
|
||||
plat_specifier = f".{self.plat_name}-{sys.implementation.cache_tag}"
|
||||
|
||||
# Python 3.13+ with --disable-gil shouldn't share build directories
|
||||
if sysconfig.get_config_var('Py_GIL_DISABLED'):
|
||||
plat_specifier += 't'
|
||||
|
||||
# Make it so Python 2.x and Python 2.x with --with-pydebug don't
|
||||
# share the same build directories. Doing so confuses the build
|
||||
|
||||
@@ -15,10 +15,11 @@ module."""
|
||||
# cut 'n paste. Sigh.
|
||||
|
||||
import os
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsSetupError
|
||||
from ..sysconfig import customize_compiler
|
||||
from distutils._log import log
|
||||
|
||||
|
||||
def show_compilers():
|
||||
@@ -56,7 +57,7 @@ class build_clib(Command):
|
||||
self.define = None
|
||||
self.undef = None
|
||||
self.debug = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.compiler = None
|
||||
|
||||
def finalize_options(self):
|
||||
@@ -137,8 +138,8 @@ class build_clib(Command):
|
||||
|
||||
if '/' in name or (os.sep != '/' and os.sep in name):
|
||||
raise DistutilsSetupError(
|
||||
"bad library name '%s': "
|
||||
"may not contain directory separators" % lib[0]
|
||||
f"bad library name '{lib[0]}': "
|
||||
"may not contain directory separators"
|
||||
)
|
||||
|
||||
if not isinstance(build_info, dict):
|
||||
@@ -154,7 +155,7 @@ class build_clib(Command):
|
||||
return None
|
||||
|
||||
lib_names = []
|
||||
for lib_name, build_info in self.libraries:
|
||||
for lib_name, _build_info in self.libraries:
|
||||
lib_names.append(lib_name)
|
||||
return lib_names
|
||||
|
||||
@@ -165,9 +166,9 @@ class build_clib(Command):
|
||||
sources = build_info.get('sources')
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
f"in 'libraries' option (library '{lib_name}'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name
|
||||
"a list of source filenames"
|
||||
)
|
||||
|
||||
filenames.extend(sources)
|
||||
@@ -178,9 +179,9 @@ class build_clib(Command):
|
||||
sources = build_info.get('sources')
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
f"in 'libraries' option (library '{lib_name}'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name
|
||||
"a list of source filenames"
|
||||
)
|
||||
sources = list(sources)
|
||||
|
||||
|
||||
@@ -8,24 +8,22 @@ import contextlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from distutils._log import log
|
||||
from site import USER_BASE
|
||||
|
||||
from .._modified import newer_group
|
||||
from ..core import Command
|
||||
from ..errors import (
|
||||
DistutilsOptionError,
|
||||
DistutilsSetupError,
|
||||
CCompilerError,
|
||||
DistutilsError,
|
||||
CompileError,
|
||||
DistutilsError,
|
||||
DistutilsOptionError,
|
||||
DistutilsPlatformError,
|
||||
DistutilsSetupError,
|
||||
)
|
||||
from ..sysconfig import customize_compiler, get_python_version
|
||||
from ..sysconfig import get_config_h_filename
|
||||
from ..dep_util import newer_group
|
||||
from ..extension import Extension
|
||||
from ..util import get_platform
|
||||
from distutils._log import log
|
||||
from . import py37compat
|
||||
|
||||
from site import USER_BASE
|
||||
from ..sysconfig import customize_compiler, get_config_h_filename, get_python_version
|
||||
from ..util import get_platform, is_mingw
|
||||
|
||||
# An extension name is just a dot-separated list of Python NAMEs (ie.
|
||||
# the same as a fully-qualified module name).
|
||||
@@ -59,7 +57,7 @@ class build_ext(Command):
|
||||
# takes care of both command-line and client options
|
||||
# in between initialize_options() and finalize_options())
|
||||
|
||||
sep_by = " (separated by '%s')" % os.pathsep
|
||||
sep_by = f" (separated by '{os.pathsep}')"
|
||||
user_options = [
|
||||
('build-lib=', 'b', "directory for compiled extension modules"),
|
||||
('build-temp=', 't', "directory for temporary files (build by-products)"),
|
||||
@@ -67,13 +65,13 @@ class build_ext(Command):
|
||||
'plat-name=',
|
||||
'p',
|
||||
"platform name to cross-compile for, if supported "
|
||||
"(default: %s)" % get_platform(),
|
||||
f"[default: {get_platform()}]",
|
||||
),
|
||||
(
|
||||
'inplace',
|
||||
'i',
|
||||
"ignore build-lib and put compiled extensions into the source "
|
||||
+ "directory alongside your pure Python modules",
|
||||
"directory alongside your pure Python modules",
|
||||
),
|
||||
(
|
||||
'include-dirs=',
|
||||
@@ -111,7 +109,7 @@ class build_ext(Command):
|
||||
self.build_lib = None
|
||||
self.plat_name = None
|
||||
self.build_temp = None
|
||||
self.inplace = 0
|
||||
self.inplace = False
|
||||
self.package = None
|
||||
|
||||
self.include_dirs = None
|
||||
@@ -130,6 +128,31 @@ class build_ext(Command):
|
||||
self.user = None
|
||||
self.parallel = None
|
||||
|
||||
@staticmethod
|
||||
def _python_lib_dir(sysconfig):
|
||||
"""
|
||||
Resolve Python's library directory for building extensions
|
||||
that rely on a shared Python library.
|
||||
|
||||
See python/cpython#44264 and python/cpython#48686
|
||||
"""
|
||||
if not sysconfig.get_config_var('Py_ENABLE_SHARED'):
|
||||
return
|
||||
|
||||
if sysconfig.python_build:
|
||||
yield '.'
|
||||
return
|
||||
|
||||
if sys.platform == 'zos':
|
||||
# On z/OS, a user is not required to install Python to
|
||||
# a predetermined path, but can use Python portably
|
||||
installed_dir = sysconfig.get_config_var('base')
|
||||
lib_dir = sysconfig.get_config_var('platlibdir')
|
||||
yield os.path.join(installed_dir, lib_dir)
|
||||
else:
|
||||
# building third party extensions
|
||||
yield sysconfig.get_config_var('LIBDIR')
|
||||
|
||||
def finalize_options(self): # noqa: C901
|
||||
from distutils import sysconfig
|
||||
|
||||
@@ -152,7 +175,7 @@ class build_ext(Command):
|
||||
# Make sure Python's include directories (for Python.h, pyconfig.h,
|
||||
# etc.) are in the include search path.
|
||||
py_include = sysconfig.get_python_inc()
|
||||
plat_py_include = sysconfig.get_python_inc(plat_specific=1)
|
||||
plat_py_include = sysconfig.get_python_inc(plat_specific=True)
|
||||
if self.include_dirs is None:
|
||||
self.include_dirs = self.distribution.include_dirs or []
|
||||
if isinstance(self.include_dirs, str):
|
||||
@@ -189,7 +212,7 @@ class build_ext(Command):
|
||||
# for extensions under windows use different directories
|
||||
# for Release and Debug builds.
|
||||
# also Python's library directory must be appended to library_dirs
|
||||
if os.name == 'nt':
|
||||
if os.name == 'nt' and not is_mingw():
|
||||
# the 'libs' directory is for binary installs - we assume that
|
||||
# must be the *native* platform. But we don't really support
|
||||
# cross-compiling via a binary install anyway, so we let it go.
|
||||
@@ -231,16 +254,7 @@ class build_ext(Command):
|
||||
# building python standard extensions
|
||||
self.library_dirs.append('.')
|
||||
|
||||
# For building extensions with a shared Python library,
|
||||
# Python's library directory must be appended to library_dirs
|
||||
# See Issues: #1600860, #4366
|
||||
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
|
||||
if not sysconfig.python_build:
|
||||
# building third party extensions
|
||||
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
|
||||
else:
|
||||
# building python standard extensions
|
||||
self.library_dirs.append('.')
|
||||
self.library_dirs.extend(self._python_lib_dir(sysconfig))
|
||||
|
||||
# The argument parsing will result in self.define being a string, but
|
||||
# it has to be a list of 2-tuples. All the preprocessor symbols
|
||||
@@ -412,9 +426,7 @@ class build_ext(Command):
|
||||
# Medium-easy stuff: same syntax/semantics, different names.
|
||||
ext.runtime_library_dirs = build_info.get('rpath')
|
||||
if 'def_file' in build_info:
|
||||
log.warning(
|
||||
"'def_file' element of build info dict " "no longer supported"
|
||||
)
|
||||
log.warning("'def_file' element of build info dict no longer supported")
|
||||
|
||||
# Non-trivial stuff: 'macros' split into 'define_macros'
|
||||
# and 'undef_macros'.
|
||||
@@ -453,10 +465,7 @@ class build_ext(Command):
|
||||
# And build the list of output (built) filenames. Note that this
|
||||
# ignores the 'inplace' flag, and assumes everything goes in the
|
||||
# "build" tree.
|
||||
outputs = []
|
||||
for ext in self.extensions:
|
||||
outputs.append(self.get_ext_fullpath(ext.name))
|
||||
return outputs
|
||||
return [self.get_ext_fullpath(ext.name) for ext in self.extensions]
|
||||
|
||||
def build_extensions(self):
|
||||
# First, sanity-check the 'extensions' list
|
||||
@@ -499,15 +508,15 @@ class build_ext(Command):
|
||||
except (CCompilerError, DistutilsError, CompileError) as e:
|
||||
if not ext.optional:
|
||||
raise
|
||||
self.warn('building extension "{}" failed: {}'.format(ext.name, e))
|
||||
self.warn(f'building extension "{ext.name}" failed: {e}')
|
||||
|
||||
def build_extension(self, ext):
|
||||
sources = ext.sources
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'ext_modules' option (extension '%s'), "
|
||||
f"in 'ext_modules' option (extension '{ext.name}'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % ext.name
|
||||
"a list of source filenames"
|
||||
)
|
||||
# sort to make the resulting .so file build reproducible
|
||||
sources = sorted(sources)
|
||||
@@ -629,8 +638,7 @@ class build_ext(Command):
|
||||
|
||||
# Do not override commandline arguments
|
||||
if not self.swig_opts:
|
||||
for o in extension.swig_opts:
|
||||
swig_cmd.append(o)
|
||||
swig_cmd.extend(extension.swig_opts)
|
||||
|
||||
for source in swig_sources:
|
||||
target = swig_targets[source]
|
||||
@@ -651,7 +659,7 @@ class build_ext(Command):
|
||||
# Windows (or so I presume!). If we find it there, great;
|
||||
# if not, act like Unix and assume it's in the PATH.
|
||||
for vers in ("1.3", "1.2", "1.1"):
|
||||
fn = os.path.join("c:\\swig%s" % vers, "swig.exe")
|
||||
fn = os.path.join(f"c:\\swig{vers}", "swig.exe")
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
else:
|
||||
@@ -659,7 +667,7 @@ class build_ext(Command):
|
||||
else:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know how to find (much less run) SWIG "
|
||||
"on platform '%s'" % os.name
|
||||
f"on platform '{os.name}'"
|
||||
)
|
||||
|
||||
# -- Name generators -----------------------------------------------
|
||||
@@ -742,7 +750,7 @@ class build_ext(Command):
|
||||
# pyconfig.h that MSVC groks. The other Windows compilers all seem
|
||||
# to need it mentioned explicitly, though, so that's what we do.
|
||||
# Append '_d' to the python import library on debug builds.
|
||||
if sys.platform == "win32":
|
||||
if sys.platform == "win32" and not is_mingw():
|
||||
from .._msvccompiler import MSVCCompiler
|
||||
|
||||
if not isinstance(self.compiler, MSVCCompiler):
|
||||
@@ -772,7 +780,7 @@ class build_ext(Command):
|
||||
# A native build on an Android device or on Cygwin
|
||||
if hasattr(sys, 'getandroidapilevel'):
|
||||
link_libpython = True
|
||||
elif sys.platform == 'cygwin':
|
||||
elif sys.platform == 'cygwin' or is_mingw():
|
||||
link_libpython = True
|
||||
elif '_PYTHON_HOST_PLATFORM' in os.environ:
|
||||
# We are cross-compiling for one of the relevant platforms
|
||||
@@ -785,4 +793,4 @@ class build_ext(Command):
|
||||
ldversion = get_config_var('LDVERSION')
|
||||
return ext.libraries + ['python' + ldversion]
|
||||
|
||||
return ext.libraries + py37compat.pythonlib()
|
||||
return ext.libraries
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
Implements the Distutils 'build_py' command."""
|
||||
|
||||
import os
|
||||
import importlib.util
|
||||
import sys
|
||||
import glob
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsOptionError, DistutilsFileError
|
||||
from ..errors import DistutilsFileError, DistutilsOptionError
|
||||
from ..util import convert_path
|
||||
from distutils._log import log
|
||||
|
||||
|
||||
class build_py(Command):
|
||||
@@ -38,7 +38,7 @@ class build_py(Command):
|
||||
self.package = None
|
||||
self.package_data = None
|
||||
self.package_dir = None
|
||||
self.compile = 0
|
||||
self.compile = False
|
||||
self.optimize = 0
|
||||
self.force = None
|
||||
|
||||
@@ -95,7 +95,7 @@ class build_py(Command):
|
||||
self.build_packages()
|
||||
self.build_package_data()
|
||||
|
||||
self.byte_compile(self.get_outputs(include_bytecode=0))
|
||||
self.byte_compile(self.get_outputs(include_bytecode=False))
|
||||
|
||||
def get_data_files(self):
|
||||
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
|
||||
@@ -129,14 +129,14 @@ class build_py(Command):
|
||||
os.path.join(glob.escape(src_dir), convert_path(pattern))
|
||||
)
|
||||
# Files that match more than one pattern are only added once
|
||||
files.extend(
|
||||
[fn for fn in filelist if fn not in files and os.path.isfile(fn)]
|
||||
)
|
||||
files.extend([
|
||||
fn for fn in filelist if fn not in files and os.path.isfile(fn)
|
||||
])
|
||||
return files
|
||||
|
||||
def build_package_data(self):
|
||||
"""Copy data files into build directory"""
|
||||
for package, src_dir, build_dir, filenames in self.data_files:
|
||||
for _package, src_dir, build_dir, filenames in self.data_files:
|
||||
for filename in filenames:
|
||||
target = os.path.join(build_dir, filename)
|
||||
self.mkpath(os.path.dirname(target))
|
||||
@@ -191,12 +191,12 @@ class build_py(Command):
|
||||
if package_dir != "":
|
||||
if not os.path.exists(package_dir):
|
||||
raise DistutilsFileError(
|
||||
"package directory '%s' does not exist" % package_dir
|
||||
f"package directory '{package_dir}' does not exist"
|
||||
)
|
||||
if not os.path.isdir(package_dir):
|
||||
raise DistutilsFileError(
|
||||
"supposed package directory '%s' exists, "
|
||||
"but is not a directory" % package_dir
|
||||
f"supposed package directory '{package_dir}' exists, "
|
||||
"but is not a directory"
|
||||
)
|
||||
|
||||
# Directories without __init__.py are namespace packages (PEP 420).
|
||||
@@ -228,7 +228,7 @@ class build_py(Command):
|
||||
module = os.path.splitext(os.path.basename(f))[0]
|
||||
modules.append((package, module, f))
|
||||
else:
|
||||
self.debug_print("excluding %s" % setup_script)
|
||||
self.debug_print(f"excluding {setup_script}")
|
||||
return modules
|
||||
|
||||
def find_modules(self):
|
||||
@@ -264,7 +264,7 @@ class build_py(Command):
|
||||
(package_dir, checked) = packages[package]
|
||||
except KeyError:
|
||||
package_dir = self.get_package_dir(package)
|
||||
checked = 0
|
||||
checked = False
|
||||
|
||||
if not checked:
|
||||
init_py = self.check_package(package, package_dir)
|
||||
@@ -306,10 +306,10 @@ class build_py(Command):
|
||||
outfile_path = [build_dir] + list(package) + [module + ".py"]
|
||||
return os.path.join(*outfile_path)
|
||||
|
||||
def get_outputs(self, include_bytecode=1):
|
||||
def get_outputs(self, include_bytecode=True):
|
||||
modules = self.find_all_modules()
|
||||
outputs = []
|
||||
for package, module, module_file in modules:
|
||||
for package, module, _module_file in modules:
|
||||
package = package.split('.')
|
||||
filename = self.get_module_outfile(self.build_lib, package, module)
|
||||
outputs.append(filename)
|
||||
@@ -347,7 +347,7 @@ class build_py(Command):
|
||||
outfile = self.get_module_outfile(self.build_lib, package, module)
|
||||
dir = os.path.dirname(outfile)
|
||||
self.mkpath(dir)
|
||||
return self.copy_file(module_file, outfile, preserve_mode=0)
|
||||
return self.copy_file(module_file, outfile, preserve_mode=False)
|
||||
|
||||
def build_modules(self):
|
||||
modules = self.find_modules()
|
||||
|
||||
@@ -4,13 +4,14 @@ Implements the Distutils 'build_scripts' command."""
|
||||
|
||||
import os
|
||||
import re
|
||||
from stat import ST_MODE
|
||||
from distutils import sysconfig
|
||||
from ..core import Command
|
||||
from ..dep_util import newer
|
||||
from ..util import convert_path
|
||||
from distutils._log import log
|
||||
import tokenize
|
||||
from distutils import sysconfig
|
||||
from distutils._log import log
|
||||
from stat import ST_MODE
|
||||
|
||||
from .._modified import newer
|
||||
from ..core import Command
|
||||
from ..util import convert_path
|
||||
|
||||
shebang_pattern = re.compile('^#!.*python[0-9.]*([ \t].*)?$')
|
||||
"""
|
||||
@@ -95,7 +96,7 @@ class build_scripts(Command):
|
||||
else:
|
||||
first_line = f.readline()
|
||||
if not first_line:
|
||||
self.warn("%s is an empty file (skipping)" % script)
|
||||
self.warn(f"{script} is an empty file (skipping)")
|
||||
return
|
||||
|
||||
shebang_match = shebang_pattern.match(first_line)
|
||||
@@ -109,8 +110,7 @@ class build_scripts(Command):
|
||||
else:
|
||||
executable = os.path.join(
|
||||
sysconfig.get_config_var("BINDIR"),
|
||||
"python%s%s"
|
||||
% (
|
||||
"python{}{}".format(
|
||||
sysconfig.get_config_var("VERSION"),
|
||||
sysconfig.get_config_var("EXE"),
|
||||
),
|
||||
@@ -156,9 +156,7 @@ class build_scripts(Command):
|
||||
try:
|
||||
shebang.encode('utf-8')
|
||||
except UnicodeEncodeError:
|
||||
raise ValueError(
|
||||
"The shebang ({!r}) is not encodable " "to utf-8".format(shebang)
|
||||
)
|
||||
raise ValueError(f"The shebang ({shebang!r}) is not encodable to utf-8")
|
||||
|
||||
# If the script is encoded to a custom encoding (use a
|
||||
# #coding:xxx cookie), the shebang has to be encodable to
|
||||
@@ -167,6 +165,6 @@ class build_scripts(Command):
|
||||
shebang.encode(encoding)
|
||||
except UnicodeEncodeError:
|
||||
raise ValueError(
|
||||
"The shebang ({!r}) is not encodable "
|
||||
"to the script encoding ({})".format(shebang, encoding)
|
||||
f"The shebang ({shebang!r}) is not encodable "
|
||||
f"to the script encoding ({encoding})"
|
||||
)
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
|
||||
Implements the Distutils 'check' command.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsSetupError
|
||||
|
||||
with contextlib.suppress(ImportError):
|
||||
import docutils.utils
|
||||
import docutils.parsers.rst
|
||||
import docutils.frontend
|
||||
import docutils.nodes
|
||||
import docutils.parsers.rst
|
||||
import docutils.utils
|
||||
|
||||
class SilentReporter(docutils.utils.Reporter):
|
||||
def __init__(
|
||||
@@ -20,7 +21,7 @@ with contextlib.suppress(ImportError):
|
||||
report_level,
|
||||
halt_level,
|
||||
stream=None,
|
||||
debug=0,
|
||||
debug=False,
|
||||
encoding='ascii',
|
||||
error_handler='replace',
|
||||
):
|
||||
@@ -32,7 +33,7 @@ with contextlib.suppress(ImportError):
|
||||
def system_message(self, level, message, *children, **kwargs):
|
||||
self.messages.append((level, message, children, kwargs))
|
||||
return docutils.nodes.system_message(
|
||||
message, level=level, type=self.levels[level], *children, **kwargs
|
||||
message, *children, level=level, type=self.levels[level], **kwargs
|
||||
)
|
||||
|
||||
|
||||
@@ -57,9 +58,9 @@ class check(Command):
|
||||
|
||||
def initialize_options(self):
|
||||
"""Sets default values for options."""
|
||||
self.restructuredtext = 0
|
||||
self.restructuredtext = False
|
||||
self.metadata = 1
|
||||
self.strict = 0
|
||||
self.strict = False
|
||||
self._warnings = 0
|
||||
|
||||
def finalize_options(self):
|
||||
@@ -99,13 +100,12 @@ class check(Command):
|
||||
"""
|
||||
metadata = self.distribution.metadata
|
||||
|
||||
missing = []
|
||||
for attr in 'name', 'version':
|
||||
if not getattr(metadata, attr, None):
|
||||
missing.append(attr)
|
||||
missing = [
|
||||
attr for attr in ('name', 'version') if not getattr(metadata, attr, None)
|
||||
]
|
||||
|
||||
if missing:
|
||||
self.warn("missing required meta-data: %s" % ', '.join(missing))
|
||||
self.warn("missing required meta-data: {}".format(', '.join(missing)))
|
||||
|
||||
def check_restructuredtext(self):
|
||||
"""Checks if the long string fields are reST-compliant."""
|
||||
@@ -115,7 +115,7 @@ class check(Command):
|
||||
if line is None:
|
||||
warning = warning[1]
|
||||
else:
|
||||
warning = '{} (line {})'.format(warning[1], line)
|
||||
warning = f'{warning[1]} (line {line})'
|
||||
self.warn(warning)
|
||||
|
||||
def _check_rst_data(self, data):
|
||||
@@ -144,8 +144,11 @@ class check(Command):
|
||||
try:
|
||||
parser.parse(data, document)
|
||||
except AttributeError as e:
|
||||
reporter.messages.append(
|
||||
(-1, 'Could not finish the parsing: %s.' % e, '', {})
|
||||
)
|
||||
reporter.messages.append((
|
||||
-1,
|
||||
f'Could not finish the parsing: {e}.',
|
||||
'',
|
||||
{},
|
||||
))
|
||||
|
||||
return reporter.messages
|
||||
|
||||
@@ -5,25 +5,26 @@ Implements the Distutils 'clean' command."""
|
||||
# contributed by Bastian Kleineidam <calvin@cs.uni-sb.de>, added 2000-03-18
|
||||
|
||||
import os
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..dir_util import remove_tree
|
||||
from distutils._log import log
|
||||
|
||||
|
||||
class clean(Command):
|
||||
description = "clean up temporary files from 'build' command"
|
||||
user_options = [
|
||||
('build-base=', 'b', "base build directory (default: 'build.build-base')"),
|
||||
('build-base=', 'b', "base build directory [default: 'build.build-base']"),
|
||||
(
|
||||
'build-lib=',
|
||||
None,
|
||||
"build directory for all modules (default: 'build.build-lib')",
|
||||
"build directory for all modules [default: 'build.build-lib']",
|
||||
),
|
||||
('build-temp=', 't', "temporary build directory (default: 'build.build-temp')"),
|
||||
('build-temp=', 't', "temporary build directory [default: 'build.build-temp']"),
|
||||
(
|
||||
'build-scripts=',
|
||||
None,
|
||||
"build directory for scripts (default: 'build.build-scripts')",
|
||||
"build directory for scripts [default: 'build.build-scripts']",
|
||||
),
|
||||
('bdist-base=', None, "temporary directory for built distributions"),
|
||||
('all', 'a', "remove all build output, not just temporary by-products"),
|
||||
|
||||
@@ -9,13 +9,17 @@ configure-like tasks: "try to compile this C code", or "figure out where
|
||||
this header file lives".
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
from collections.abc import Sequence
|
||||
from distutils._log import log
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsExecError
|
||||
from ..sysconfig import customize_compiler
|
||||
from distutils._log import log
|
||||
|
||||
LANG_EXT = {"c": ".c", "c++": ".cxx"}
|
||||
|
||||
@@ -90,7 +94,7 @@ class config(Command):
|
||||
|
||||
if not isinstance(self.compiler, CCompiler):
|
||||
self.compiler = new_compiler(
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=1
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=True
|
||||
)
|
||||
customize_compiler(self.compiler)
|
||||
if self.include_dirs:
|
||||
@@ -102,10 +106,10 @@ class config(Command):
|
||||
|
||||
def _gen_temp_sourcefile(self, body, headers, lang):
|
||||
filename = "_configtest" + LANG_EXT[lang]
|
||||
with open(filename, "w") as file:
|
||||
with open(filename, "w", encoding='utf-8') as file:
|
||||
if headers:
|
||||
for header in headers:
|
||||
file.write("#include <%s>\n" % header)
|
||||
file.write(f"#include <{header}>\n")
|
||||
file.write("\n")
|
||||
file.write(body)
|
||||
if body[-1] != "\n":
|
||||
@@ -122,7 +126,7 @@ class config(Command):
|
||||
def _compile(self, body, headers, include_dirs, lang):
|
||||
src = self._gen_temp_sourcefile(body, headers, lang)
|
||||
if self.dump_source:
|
||||
dump_file(src, "compiling '%s':" % src)
|
||||
dump_file(src, f"compiling '{src}':")
|
||||
(obj,) = self.compiler.object_filenames([src])
|
||||
self.temp_files.extend([src, obj])
|
||||
self.compiler.compile([src], include_dirs=include_dirs)
|
||||
@@ -199,15 +203,8 @@ class config(Command):
|
||||
if isinstance(pattern, str):
|
||||
pattern = re.compile(pattern)
|
||||
|
||||
with open(out) as file:
|
||||
match = False
|
||||
while True:
|
||||
line = file.readline()
|
||||
if line == '':
|
||||
break
|
||||
if pattern.search(line):
|
||||
match = True
|
||||
break
|
||||
with open(out, encoding='utf-8') as file:
|
||||
match = any(pattern.search(line) for line in file)
|
||||
|
||||
self._clean()
|
||||
return match
|
||||
@@ -295,8 +292,8 @@ class config(Command):
|
||||
include_dirs=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
decl=0,
|
||||
call=0,
|
||||
decl=False,
|
||||
call=False,
|
||||
):
|
||||
"""Determine if function 'func' is available by constructing a
|
||||
source file that refers to 'func', and compiles and links it.
|
||||
@@ -314,12 +311,12 @@ class config(Command):
|
||||
self._check_compiler()
|
||||
body = []
|
||||
if decl:
|
||||
body.append("int %s ();" % func)
|
||||
body.append(f"int {func} ();")
|
||||
body.append("int main () {")
|
||||
if call:
|
||||
body.append(" %s();" % func)
|
||||
body.append(f" {func}();")
|
||||
else:
|
||||
body.append(" %s;" % func)
|
||||
body.append(f" {func};")
|
||||
body.append("}")
|
||||
body = "\n".join(body) + "\n"
|
||||
|
||||
@@ -331,7 +328,7 @@ class config(Command):
|
||||
library_dirs=None,
|
||||
headers=None,
|
||||
include_dirs=None,
|
||||
other_libraries=[],
|
||||
other_libraries: Sequence[str] = [],
|
||||
):
|
||||
"""Determine if 'library' is available to be linked against,
|
||||
without actually checking that any particular symbols are provided
|
||||
@@ -346,7 +343,7 @@ class config(Command):
|
||||
"int main (void) { }",
|
||||
headers,
|
||||
include_dirs,
|
||||
[library] + other_libraries,
|
||||
[library] + list(other_libraries),
|
||||
library_dirs,
|
||||
)
|
||||
|
||||
@@ -369,8 +366,4 @@ def dump_file(filename, head=None):
|
||||
log.info('%s', filename)
|
||||
else:
|
||||
log.info(head)
|
||||
file = open(filename)
|
||||
try:
|
||||
log.info(file.read())
|
||||
finally:
|
||||
file.close()
|
||||
log.info(pathlib.Path(filename).read_text(encoding='utf-8'))
|
||||
|
||||
@@ -2,25 +2,23 @@
|
||||
|
||||
Implements the Distutils 'install' command."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import contextlib
|
||||
import sysconfig
|
||||
import itertools
|
||||
|
||||
import os
|
||||
import sys
|
||||
import sysconfig
|
||||
from distutils._log import log
|
||||
from site import USER_BASE, USER_SITE
|
||||
|
||||
import jaraco.collections
|
||||
|
||||
from ..core import Command
|
||||
from ..debug import DEBUG
|
||||
from ..sysconfig import get_config_vars
|
||||
from ..file_util import write_file
|
||||
from ..util import convert_path, subst_vars, change_root
|
||||
from ..util import get_platform
|
||||
from ..errors import DistutilsOptionError, DistutilsPlatformError
|
||||
from ..file_util import write_file
|
||||
from ..sysconfig import get_config_vars
|
||||
from ..util import change_root, convert_path, get_platform, subst_vars
|
||||
from . import _framework_compat as fw
|
||||
from .. import _collections
|
||||
|
||||
from site import USER_BASE
|
||||
from site import USER_SITE
|
||||
|
||||
HAS_USER_SITE = True
|
||||
|
||||
@@ -196,8 +194,7 @@ class install(Command):
|
||||
(
|
||||
'install-platbase=',
|
||||
None,
|
||||
"base installation directory for platform-specific files "
|
||||
+ "(instead of --exec-prefix or --home)",
|
||||
"base installation directory for platform-specific files (instead of --exec-prefix or --home)",
|
||||
),
|
||||
('root=', None, "install everything relative to this alternate root directory"),
|
||||
# Or, explicitly set the installation scheme
|
||||
@@ -214,8 +211,7 @@ class install(Command):
|
||||
(
|
||||
'install-lib=',
|
||||
None,
|
||||
"installation directory for all module distributions "
|
||||
+ "(overrides --install-purelib and --install-platlib)",
|
||||
"installation directory for all module distributions (overrides --install-purelib and --install-platlib)",
|
||||
),
|
||||
('install-headers=', None, "installation directory for C/C++ headers"),
|
||||
('install-scripts=', None, "installation directory for Python scripts"),
|
||||
@@ -245,9 +241,11 @@ class install(Command):
|
||||
boolean_options = ['compile', 'force', 'skip-build']
|
||||
|
||||
if HAS_USER_SITE:
|
||||
user_options.append(
|
||||
('user', None, "install in user site-package '%s'" % USER_SITE)
|
||||
)
|
||||
user_options.append((
|
||||
'user',
|
||||
None,
|
||||
f"install in user site-package '{USER_SITE}'",
|
||||
))
|
||||
boolean_options.append('user')
|
||||
|
||||
negative_opt = {'no-compile': 'compile'}
|
||||
@@ -259,7 +257,7 @@ class install(Command):
|
||||
self.prefix = None
|
||||
self.exec_prefix = None
|
||||
self.home = None
|
||||
self.user = 0
|
||||
self.user = False
|
||||
|
||||
# These select only the installation base; it's up to the user to
|
||||
# specify the installation scheme (currently, that means supplying
|
||||
@@ -294,7 +292,7 @@ class install(Command):
|
||||
# 'install_path_file' is always true unless some outsider meddles
|
||||
# with it.
|
||||
self.extra_path = None
|
||||
self.install_path_file = 1
|
||||
self.install_path_file = True
|
||||
|
||||
# 'force' forces installation, even if target files are not
|
||||
# out-of-date. 'skip_build' skips running the "build" command,
|
||||
@@ -302,9 +300,9 @@ class install(Command):
|
||||
# a user option, it's just there so the bdist_* commands can turn
|
||||
# it off) determines whether we warn about installing to a
|
||||
# directory not in sys.path.
|
||||
self.force = 0
|
||||
self.skip_build = 0
|
||||
self.warn_dir = 1
|
||||
self.force = False
|
||||
self.skip_build = False
|
||||
self.warn_dir = True
|
||||
|
||||
# These are only here as a conduit from the 'build' command to the
|
||||
# 'install_*' commands that do the real work. ('build_base' isn't
|
||||
@@ -349,8 +347,7 @@ class install(Command):
|
||||
self.install_base or self.install_platbase
|
||||
):
|
||||
raise DistutilsOptionError(
|
||||
"must supply either prefix/exec-prefix/home or "
|
||||
+ "install-base/install-platbase -- not both"
|
||||
"must supply either prefix/exec-prefix/home or install-base/install-platbase -- not both"
|
||||
)
|
||||
|
||||
if self.home and (self.prefix or self.exec_prefix):
|
||||
@@ -432,9 +429,12 @@ class install(Command):
|
||||
local_vars['userbase'] = self.install_userbase
|
||||
local_vars['usersite'] = self.install_usersite
|
||||
|
||||
self.config_vars = _collections.DictStack(
|
||||
[fw.vars(), compat_vars, sysconfig.get_config_vars(), local_vars]
|
||||
)
|
||||
self.config_vars = jaraco.collections.DictStack([
|
||||
fw.vars(),
|
||||
compat_vars,
|
||||
sysconfig.get_config_vars(),
|
||||
local_vars,
|
||||
])
|
||||
|
||||
self.expand_basedirs()
|
||||
|
||||
@@ -598,7 +598,7 @@ class install(Command):
|
||||
self.select_scheme(os.name)
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know how to install stuff on '%s'" % os.name
|
||||
f"I don't know how to install stuff on '{os.name}'"
|
||||
)
|
||||
|
||||
def select_scheme(self, name):
|
||||
@@ -620,16 +620,14 @@ class install(Command):
|
||||
|
||||
def expand_dirs(self):
|
||||
"""Calls `os.path.expanduser` on install dirs."""
|
||||
self._expand_attrs(
|
||||
[
|
||||
'install_purelib',
|
||||
'install_platlib',
|
||||
'install_lib',
|
||||
'install_headers',
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
]
|
||||
)
|
||||
self._expand_attrs([
|
||||
'install_purelib',
|
||||
'install_platlib',
|
||||
'install_lib',
|
||||
'install_headers',
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
])
|
||||
|
||||
def convert_paths(self, *names):
|
||||
"""Call `convert_path` over `names`."""
|
||||
@@ -683,9 +681,9 @@ class install(Command):
|
||||
if not self.user:
|
||||
return
|
||||
home = convert_path(os.path.expanduser("~"))
|
||||
for name, path in self.config_vars.items():
|
||||
for path in self.config_vars.values():
|
||||
if str(path).startswith(home) and not os.path.isdir(path):
|
||||
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
||||
self.debug_print(f"os.makedirs('{path}', 0o700)")
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
# -- Command execution methods -------------------------------------
|
||||
@@ -701,7 +699,7 @@ class install(Command):
|
||||
# internally, and not to sys.path, so we don't check the platform
|
||||
# matches what we are running.
|
||||
if self.warn_dir and build_plat != get_platform():
|
||||
raise DistutilsPlatformError("Can't install when " "cross-compiling")
|
||||
raise DistutilsPlatformError("Can't install when cross-compiling")
|
||||
|
||||
# Run all sub-commands (at least those that need to be run)
|
||||
for cmd_name in self.get_sub_commands():
|
||||
@@ -720,7 +718,7 @@ class install(Command):
|
||||
self.execute(
|
||||
write_file,
|
||||
(self.record, outputs),
|
||||
"writing list of installed files to '%s'" % self.record,
|
||||
f"writing list of installed files to '{self.record}'",
|
||||
)
|
||||
|
||||
sys_path = map(os.path.normpath, sys.path)
|
||||
@@ -745,10 +743,10 @@ class install(Command):
|
||||
filename = os.path.join(self.install_libbase, self.path_file + ".pth")
|
||||
if self.install_path_file:
|
||||
self.execute(
|
||||
write_file, (filename, [self.extra_dirs]), "creating %s" % filename
|
||||
write_file, (filename, [self.extra_dirs]), f"creating {filename}"
|
||||
)
|
||||
else:
|
||||
self.warn("path file '%s' not created" % filename)
|
||||
self.warn(f"path file '{filename}' not created")
|
||||
|
||||
# -- Reporting methods ---------------------------------------------
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@ platform-independent data files."""
|
||||
|
||||
# contributed by Bastian Kleineidam
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import os
|
||||
from typing import Iterable
|
||||
|
||||
from ..core import Command
|
||||
from ..util import change_root, convert_path
|
||||
|
||||
@@ -18,7 +23,7 @@ class install_data(Command):
|
||||
'install-dir=',
|
||||
'd',
|
||||
"base directory for installing data files "
|
||||
"(default: installation base dir)",
|
||||
"[default: installation base dir]",
|
||||
),
|
||||
('root=', None, "install everything relative to this alternate root directory"),
|
||||
('force', 'f', "force installation (overwrite existing files)"),
|
||||
@@ -30,9 +35,9 @@ class install_data(Command):
|
||||
self.install_dir = None
|
||||
self.outfiles = []
|
||||
self.root = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.data_files = self.distribution.data_files
|
||||
self.warn_dir = 1
|
||||
self.warn_dir = True
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options(
|
||||
@@ -45,36 +50,42 @@ class install_data(Command):
|
||||
def run(self):
|
||||
self.mkpath(self.install_dir)
|
||||
for f in self.data_files:
|
||||
if isinstance(f, str):
|
||||
# it's a simple file, so copy it
|
||||
f = convert_path(f)
|
||||
if self.warn_dir:
|
||||
self.warn(
|
||||
"setup script did not provide a directory for "
|
||||
"'%s' -- installing right in '%s'" % (f, self.install_dir)
|
||||
)
|
||||
(out, _) = self.copy_file(f, self.install_dir)
|
||||
self.outfiles.append(out)
|
||||
else:
|
||||
# it's a tuple with path to install to and a list of files
|
||||
dir = convert_path(f[0])
|
||||
if not os.path.isabs(dir):
|
||||
dir = os.path.join(self.install_dir, dir)
|
||||
elif self.root:
|
||||
dir = change_root(self.root, dir)
|
||||
self.mkpath(dir)
|
||||
self._copy(f)
|
||||
|
||||
if f[1] == []:
|
||||
# If there are no files listed, the user must be
|
||||
# trying to create an empty directory, so add the
|
||||
# directory to the list of output files.
|
||||
self.outfiles.append(dir)
|
||||
else:
|
||||
# Copy files, adding them to the list of output files.
|
||||
for data in f[1]:
|
||||
data = convert_path(data)
|
||||
(out, _) = self.copy_file(data, dir)
|
||||
self.outfiles.append(out)
|
||||
@functools.singledispatchmethod
|
||||
def _copy(self, f: tuple[str | os.PathLike, Iterable[str | os.PathLike]]):
|
||||
# it's a tuple with path to install to and a list of files
|
||||
dir = convert_path(f[0])
|
||||
if not os.path.isabs(dir):
|
||||
dir = os.path.join(self.install_dir, dir)
|
||||
elif self.root:
|
||||
dir = change_root(self.root, dir)
|
||||
self.mkpath(dir)
|
||||
|
||||
if f[1] == []:
|
||||
# If there are no files listed, the user must be
|
||||
# trying to create an empty directory, so add the
|
||||
# directory to the list of output files.
|
||||
self.outfiles.append(dir)
|
||||
else:
|
||||
# Copy files, adding them to the list of output files.
|
||||
for data in f[1]:
|
||||
data = convert_path(data)
|
||||
(out, _) = self.copy_file(data, dir)
|
||||
self.outfiles.append(out)
|
||||
|
||||
@_copy.register(str)
|
||||
@_copy.register(os.PathLike)
|
||||
def _(self, f: str | os.PathLike):
|
||||
# it's a simple file, so copy it
|
||||
f = convert_path(f)
|
||||
if self.warn_dir:
|
||||
self.warn(
|
||||
"setup script did not provide a directory for "
|
||||
f"'{f}' -- installing right in '{self.install_dir}'"
|
||||
)
|
||||
(out, _) = self.copy_file(f, self.install_dir)
|
||||
self.outfiles.append(out)
|
||||
|
||||
def get_inputs(self):
|
||||
return self.data_files or []
|
||||
|
||||
@@ -6,12 +6,12 @@ a package's PKG-INFO metadata.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import sys
|
||||
|
||||
from ..cmd import Command
|
||||
from .. import dir_util
|
||||
from .._log import log
|
||||
from ..cmd import Command
|
||||
|
||||
|
||||
class install_egg_info(Command):
|
||||
|
||||
@@ -19,7 +19,7 @@ class install_headers(Command):
|
||||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.outfiles = []
|
||||
|
||||
def finalize_options(self):
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
Implements the Distutils 'install_lib' command
|
||||
(install all Python modules)."""
|
||||
|
||||
import os
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ..core import Command
|
||||
from ..errors import DistutilsOptionError
|
||||
|
||||
|
||||
# Extension for Python source files.
|
||||
PYTHON_SOURCE_EXTENSION = ".py"
|
||||
|
||||
@@ -55,7 +54,7 @@ class install_lib(Command):
|
||||
# let the 'install' command dictate our installation directory
|
||||
self.install_dir = None
|
||||
self.build_dir = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.compile = None
|
||||
self.optimize = None
|
||||
self.skip_build = None
|
||||
@@ -82,9 +81,9 @@ class install_lib(Command):
|
||||
if not isinstance(self.optimize, int):
|
||||
try:
|
||||
self.optimize = int(self.optimize)
|
||||
if self.optimize not in (0, 1, 2):
|
||||
raise AssertionError
|
||||
except (ValueError, AssertionError):
|
||||
except ValueError:
|
||||
pass
|
||||
if self.optimize not in (0, 1, 2):
|
||||
raise DistutilsOptionError("optimize must be 0, 1, or 2")
|
||||
|
||||
def run(self):
|
||||
@@ -115,7 +114,7 @@ class install_lib(Command):
|
||||
outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
||||
else:
|
||||
self.warn(
|
||||
"'%s' does not exist -- no Python modules to install" % self.build_dir
|
||||
f"'{self.build_dir}' does not exist -- no Python modules to install"
|
||||
)
|
||||
return
|
||||
return outfiles
|
||||
@@ -162,9 +161,7 @@ class install_lib(Command):
|
||||
build_dir = getattr(build_cmd, cmd_option)
|
||||
|
||||
prefix_len = len(build_dir) + len(os.sep)
|
||||
outputs = []
|
||||
for file in build_files:
|
||||
outputs.append(os.path.join(output_dir, file[prefix_len:]))
|
||||
outputs = [os.path.join(output_dir, file[prefix_len:]) for file in build_files]
|
||||
|
||||
return outputs
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ Python scripts."""
|
||||
# contributed by Bastian Kleineidam
|
||||
|
||||
import os
|
||||
from ..core import Command
|
||||
from distutils._log import log
|
||||
from stat import ST_MODE
|
||||
|
||||
from ..core import Command
|
||||
|
||||
|
||||
class install_scripts(Command):
|
||||
description = "install scripts (Python or otherwise)"
|
||||
@@ -25,7 +26,7 @@ class install_scripts(Command):
|
||||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
self.force = 0
|
||||
self.force = False
|
||||
self.build_dir = None
|
||||
self.skip_build = None
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import sys
|
||||
|
||||
|
||||
def _pythonlib_compat():
|
||||
"""
|
||||
On Python 3.7 and earlier, distutils would include the Python
|
||||
library. See pypa/distutils#9.
|
||||
"""
|
||||
from distutils import sysconfig
|
||||
|
||||
if not sysconfig.get_config_var('Py_ENABLED_SHARED'):
|
||||
return
|
||||
|
||||
yield 'python{}.{}{}'.format(
|
||||
sys.hexversion >> 24,
|
||||
(sys.hexversion >> 16) & 0xFF,
|
||||
sysconfig.get_config_var('ABIFLAGS'),
|
||||
)
|
||||
|
||||
|
||||
def compose(f1, f2):
|
||||
return lambda *args, **kwargs: f1(f2(*args, **kwargs))
|
||||
|
||||
|
||||
pythonlib = (
|
||||
compose(list, _pythonlib_compat)
|
||||
if sys.version_info < (3, 8)
|
||||
and sys.platform != 'darwin'
|
||||
and sys.platform[:3] != 'aix'
|
||||
else list
|
||||
)
|
||||
@@ -1,320 +0,0 @@
|
||||
"""distutils.command.register
|
||||
|
||||
Implements the Distutils 'register' command (register with the repository).
|
||||
"""
|
||||
|
||||
# created 2002/10/21, Richard Jones
|
||||
|
||||
import getpass
|
||||
import io
|
||||
import logging
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from warnings import warn
|
||||
|
||||
from ..core import PyPIRCCommand
|
||||
from distutils._log import log
|
||||
|
||||
|
||||
class register(PyPIRCCommand):
|
||||
description = "register the distribution with the Python package index"
|
||||
user_options = PyPIRCCommand.user_options + [
|
||||
('list-classifiers', None, 'list the valid Trove classifiers'),
|
||||
(
|
||||
'strict',
|
||||
None,
|
||||
'Will stop the registering if the meta-data are not fully compliant',
|
||||
),
|
||||
]
|
||||
boolean_options = PyPIRCCommand.boolean_options + [
|
||||
'verify',
|
||||
'list-classifiers',
|
||||
'strict',
|
||||
]
|
||||
|
||||
sub_commands = [('check', lambda self: True)]
|
||||
|
||||
def initialize_options(self):
|
||||
PyPIRCCommand.initialize_options(self)
|
||||
self.list_classifiers = 0
|
||||
self.strict = 0
|
||||
|
||||
def finalize_options(self):
|
||||
PyPIRCCommand.finalize_options(self)
|
||||
# setting options for the `check` subcommand
|
||||
check_options = {
|
||||
'strict': ('register', self.strict),
|
||||
'restructuredtext': ('register', 1),
|
||||
}
|
||||
self.distribution.command_options['check'] = check_options
|
||||
|
||||
def run(self):
|
||||
self.finalize_options()
|
||||
self._set_config()
|
||||
|
||||
# Run sub commands
|
||||
for cmd_name in self.get_sub_commands():
|
||||
self.run_command(cmd_name)
|
||||
|
||||
if self.dry_run:
|
||||
self.verify_metadata()
|
||||
elif self.list_classifiers:
|
||||
self.classifiers()
|
||||
else:
|
||||
self.send_metadata()
|
||||
|
||||
def check_metadata(self):
|
||||
"""Deprecated API."""
|
||||
warn(
|
||||
"distutils.command.register.check_metadata is deprecated; "
|
||||
"use the check command instead",
|
||||
DeprecationWarning,
|
||||
)
|
||||
check = self.distribution.get_command_obj('check')
|
||||
check.ensure_finalized()
|
||||
check.strict = self.strict
|
||||
check.restructuredtext = 1
|
||||
check.run()
|
||||
|
||||
def _set_config(self):
|
||||
'''Reads the configuration file and set attributes.'''
|
||||
config = self._read_pypirc()
|
||||
if config != {}:
|
||||
self.username = config['username']
|
||||
self.password = config['password']
|
||||
self.repository = config['repository']
|
||||
self.realm = config['realm']
|
||||
self.has_config = True
|
||||
else:
|
||||
if self.repository not in ('pypi', self.DEFAULT_REPOSITORY):
|
||||
raise ValueError('%s not found in .pypirc' % self.repository)
|
||||
if self.repository == 'pypi':
|
||||
self.repository = self.DEFAULT_REPOSITORY
|
||||
self.has_config = False
|
||||
|
||||
def classifiers(self):
|
||||
'''Fetch the list of classifiers from the server.'''
|
||||
url = self.repository + '?:action=list_classifiers'
|
||||
response = urllib.request.urlopen(url)
|
||||
log.info(self._read_pypi_response(response))
|
||||
|
||||
def verify_metadata(self):
|
||||
'''Send the metadata to the package index server to be checked.'''
|
||||
# send the info to the server and report the result
|
||||
(code, result) = self.post_to_server(self.build_post_data('verify'))
|
||||
log.info('Server response (%s): %s', code, result)
|
||||
|
||||
def send_metadata(self): # noqa: C901
|
||||
'''Send the metadata to the package index server.
|
||||
|
||||
Well, do the following:
|
||||
1. figure who the user is, and then
|
||||
2. send the data as a Basic auth'ed POST.
|
||||
|
||||
First we try to read the username/password from $HOME/.pypirc,
|
||||
which is a ConfigParser-formatted file with a section
|
||||
[distutils] containing username and password entries (both
|
||||
in clear text). Eg:
|
||||
|
||||
[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
|
||||
[pypi]
|
||||
username: fred
|
||||
password: sekrit
|
||||
|
||||
Otherwise, to figure who the user is, we offer the user three
|
||||
choices:
|
||||
|
||||
1. use existing login,
|
||||
2. register as a new user, or
|
||||
3. set the password to a random string and email the user.
|
||||
|
||||
'''
|
||||
# see if we can short-cut and get the username/password from the
|
||||
# config
|
||||
if self.has_config:
|
||||
choice = '1'
|
||||
username = self.username
|
||||
password = self.password
|
||||
else:
|
||||
choice = 'x'
|
||||
username = password = ''
|
||||
|
||||
# get the user's login info
|
||||
choices = '1 2 3 4'.split()
|
||||
while choice not in choices:
|
||||
self.announce(
|
||||
'''\
|
||||
We need to know who you are, so please choose either:
|
||||
1. use your existing login,
|
||||
2. register as a new user,
|
||||
3. have the server generate a new password for you (and email it to you), or
|
||||
4. quit
|
||||
Your selection [default 1]: ''',
|
||||
logging.INFO,
|
||||
)
|
||||
choice = input()
|
||||
if not choice:
|
||||
choice = '1'
|
||||
elif choice not in choices:
|
||||
print('Please choose one of the four options!')
|
||||
|
||||
if choice == '1':
|
||||
# get the username and password
|
||||
while not username:
|
||||
username = input('Username: ')
|
||||
while not password:
|
||||
password = getpass.getpass('Password: ')
|
||||
|
||||
# set up the authentication
|
||||
auth = urllib.request.HTTPPasswordMgr()
|
||||
host = urllib.parse.urlparse(self.repository)[1]
|
||||
auth.add_password(self.realm, host, username, password)
|
||||
# send the info to the server and report the result
|
||||
code, result = self.post_to_server(self.build_post_data('submit'), auth)
|
||||
self.announce('Server response ({}): {}'.format(code, result), logging.INFO)
|
||||
|
||||
# possibly save the login
|
||||
if code == 200:
|
||||
if self.has_config:
|
||||
# sharing the password in the distribution instance
|
||||
# so the upload command can reuse it
|
||||
self.distribution.password = password
|
||||
else:
|
||||
self.announce(
|
||||
(
|
||||
'I can store your PyPI login so future '
|
||||
'submissions will be faster.'
|
||||
),
|
||||
logging.INFO,
|
||||
)
|
||||
self.announce(
|
||||
'(the login will be stored in %s)' % self._get_rc_file(),
|
||||
logging.INFO,
|
||||
)
|
||||
choice = 'X'
|
||||
while choice.lower() not in 'yn':
|
||||
choice = input('Save your login (y/N)?')
|
||||
if not choice:
|
||||
choice = 'n'
|
||||
if choice.lower() == 'y':
|
||||
self._store_pypirc(username, password)
|
||||
|
||||
elif choice == '2':
|
||||
data = {':action': 'user'}
|
||||
data['name'] = data['password'] = data['email'] = ''
|
||||
data['confirm'] = None
|
||||
while not data['name']:
|
||||
data['name'] = input('Username: ')
|
||||
while data['password'] != data['confirm']:
|
||||
while not data['password']:
|
||||
data['password'] = getpass.getpass('Password: ')
|
||||
while not data['confirm']:
|
||||
data['confirm'] = getpass.getpass(' Confirm: ')
|
||||
if data['password'] != data['confirm']:
|
||||
data['password'] = ''
|
||||
data['confirm'] = None
|
||||
print("Password and confirm don't match!")
|
||||
while not data['email']:
|
||||
data['email'] = input(' EMail: ')
|
||||
code, result = self.post_to_server(data)
|
||||
if code != 200:
|
||||
log.info('Server response (%s): %s', code, result)
|
||||
else:
|
||||
log.info('You will receive an email shortly.')
|
||||
log.info('Follow the instructions in it to ' 'complete registration.')
|
||||
elif choice == '3':
|
||||
data = {':action': 'password_reset'}
|
||||
data['email'] = ''
|
||||
while not data['email']:
|
||||
data['email'] = input('Your email address: ')
|
||||
code, result = self.post_to_server(data)
|
||||
log.info('Server response (%s): %s', code, result)
|
||||
|
||||
def build_post_data(self, action):
|
||||
# figure the data to send - the metadata plus some additional
|
||||
# information used by the package server
|
||||
meta = self.distribution.metadata
|
||||
data = {
|
||||
':action': action,
|
||||
'metadata_version': '1.0',
|
||||
'name': meta.get_name(),
|
||||
'version': meta.get_version(),
|
||||
'summary': meta.get_description(),
|
||||
'home_page': meta.get_url(),
|
||||
'author': meta.get_contact(),
|
||||
'author_email': meta.get_contact_email(),
|
||||
'license': meta.get_licence(),
|
||||
'description': meta.get_long_description(),
|
||||
'keywords': meta.get_keywords(),
|
||||
'platform': meta.get_platforms(),
|
||||
'classifiers': meta.get_classifiers(),
|
||||
'download_url': meta.get_download_url(),
|
||||
# PEP 314
|
||||
'provides': meta.get_provides(),
|
||||
'requires': meta.get_requires(),
|
||||
'obsoletes': meta.get_obsoletes(),
|
||||
}
|
||||
if data['provides'] or data['requires'] or data['obsoletes']:
|
||||
data['metadata_version'] = '1.1'
|
||||
return data
|
||||
|
||||
def post_to_server(self, data, auth=None): # noqa: C901
|
||||
'''Post a query to the server, and return a string response.'''
|
||||
if 'name' in data:
|
||||
self.announce(
|
||||
'Registering {} to {}'.format(data['name'], self.repository),
|
||||
logging.INFO,
|
||||
)
|
||||
# Build up the MIME payload for the urllib2 POST data
|
||||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = '\n--' + boundary
|
||||
end_boundary = sep_boundary + '--'
|
||||
body = io.StringIO()
|
||||
for key, value in data.items():
|
||||
# handle multiple entries for the same name
|
||||
if type(value) not in (type([]), type(())):
|
||||
value = [value]
|
||||
for value in value:
|
||||
value = str(value)
|
||||
body.write(sep_boundary)
|
||||
body.write('\nContent-Disposition: form-data; name="%s"' % key)
|
||||
body.write("\n\n")
|
||||
body.write(value)
|
||||
if value and value[-1] == '\r':
|
||||
body.write('\n') # write an extra newline (lurve Macs)
|
||||
body.write(end_boundary)
|
||||
body.write("\n")
|
||||
body = body.getvalue().encode("utf-8")
|
||||
|
||||
# build the Request
|
||||
headers = {
|
||||
'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'
|
||||
% boundary,
|
||||
'Content-length': str(len(body)),
|
||||
}
|
||||
req = urllib.request.Request(self.repository, body, headers)
|
||||
|
||||
# handle HTTP and include the Basic Auth handler
|
||||
opener = urllib.request.build_opener(
|
||||
urllib.request.HTTPBasicAuthHandler(password_mgr=auth)
|
||||
)
|
||||
data = ''
|
||||
try:
|
||||
result = opener.open(req)
|
||||
except urllib.error.HTTPError as e:
|
||||
if self.show_response:
|
||||
data = e.fp.read()
|
||||
result = e.code, e.msg
|
||||
except urllib.error.URLError as e:
|
||||
result = 500, str(e)
|
||||
else:
|
||||
if self.show_response:
|
||||
data = self._read_pypi_response(result)
|
||||
result = 200, 'OK'
|
||||
if self.show_response:
|
||||
msg = '\n'.join(('-' * 75, data, '-' * 75))
|
||||
self.announce(msg, logging.INFO)
|
||||
return result
|
||||
@@ -4,31 +4,29 @@ Implements the Distutils 'sdist' command (create a source distribution)."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from distutils import archive_util, dir_util, file_util
|
||||
from distutils._log import log
|
||||
from glob import glob
|
||||
from warnings import warn
|
||||
from itertools import filterfalse
|
||||
|
||||
from ..core import Command
|
||||
from distutils import dir_util
|
||||
from distutils import file_util
|
||||
from distutils import archive_util
|
||||
from ..text_file import TextFile
|
||||
from ..filelist import FileList
|
||||
from distutils._log import log
|
||||
from ..util import convert_path
|
||||
from ..errors import DistutilsOptionError, DistutilsTemplateError
|
||||
from ..filelist import FileList
|
||||
from ..text_file import TextFile
|
||||
from ..util import convert_path
|
||||
|
||||
|
||||
def show_formats():
|
||||
"""Print all possible values for the 'formats' option (used by
|
||||
the "--help-formats" command-line option).
|
||||
"""
|
||||
from ..fancy_getopt import FancyGetopt
|
||||
from ..archive_util import ARCHIVE_FORMATS
|
||||
from ..fancy_getopt import FancyGetopt
|
||||
|
||||
formats = []
|
||||
for format in ARCHIVE_FORMATS.keys():
|
||||
formats.append(("formats=" + format, None, ARCHIVE_FORMATS[format][2]))
|
||||
formats.sort()
|
||||
formats = sorted(
|
||||
("formats=" + format, None, ARCHIVE_FORMATS[format][2])
|
||||
for format in ARCHIVE_FORMATS.keys()
|
||||
)
|
||||
FancyGetopt(formats).print_help("List of available source distribution formats:")
|
||||
|
||||
|
||||
@@ -62,7 +60,7 @@ class sdist(Command):
|
||||
(
|
||||
'manifest-only',
|
||||
'o',
|
||||
"just regenerate the manifest and then stop " "(implies --force-manifest)",
|
||||
"just regenerate the manifest and then stop (implies --force-manifest)",
|
||||
),
|
||||
(
|
||||
'force-manifest',
|
||||
@@ -79,7 +77,7 @@ class sdist(Command):
|
||||
(
|
||||
'dist-dir=',
|
||||
'd',
|
||||
"directory to put the source distribution archive(s) in " "[default: dist]",
|
||||
"directory to put the source distribution archive(s) in [default: dist]",
|
||||
),
|
||||
(
|
||||
'metadata-check',
|
||||
@@ -126,14 +124,14 @@ class sdist(Command):
|
||||
|
||||
# 'use_defaults': if true, we will include the default file set
|
||||
# in the manifest
|
||||
self.use_defaults = 1
|
||||
self.prune = 1
|
||||
self.use_defaults = True
|
||||
self.prune = True
|
||||
|
||||
self.manifest_only = 0
|
||||
self.force_manifest = 0
|
||||
self.manifest_only = False
|
||||
self.force_manifest = False
|
||||
|
||||
self.formats = ['gztar']
|
||||
self.keep_temp = 0
|
||||
self.keep_temp = False
|
||||
self.dist_dir = None
|
||||
|
||||
self.archive_files = None
|
||||
@@ -151,7 +149,7 @@ class sdist(Command):
|
||||
|
||||
bad_format = archive_util.check_archive_formats(self.formats)
|
||||
if bad_format:
|
||||
raise DistutilsOptionError("unknown archive format '%s'" % bad_format)
|
||||
raise DistutilsOptionError(f"unknown archive format '{bad_format}'")
|
||||
|
||||
if self.dist_dir is None:
|
||||
self.dist_dir = "dist"
|
||||
@@ -178,17 +176,6 @@ class sdist(Command):
|
||||
# or zipfile, or whatever.
|
||||
self.make_distribution()
|
||||
|
||||
def check_metadata(self):
|
||||
"""Deprecated API."""
|
||||
warn(
|
||||
"distutils.command.sdist.check_metadata is deprecated, \
|
||||
use the check command instead",
|
||||
PendingDeprecationWarning,
|
||||
)
|
||||
check = self.distribution.get_command_obj('check')
|
||||
check.ensure_finalized()
|
||||
check.run()
|
||||
|
||||
def get_file_list(self):
|
||||
"""Figure out the list of files to include in the source
|
||||
distribution, and put it in 'self.filelist'. This might involve
|
||||
@@ -289,7 +276,7 @@ class sdist(Command):
|
||||
if self._cs_path_exists(fn):
|
||||
self.filelist.append(fn)
|
||||
else:
|
||||
self.warn("standard file '%s' not found" % fn)
|
||||
self.warn(f"standard file '{fn}' not found")
|
||||
|
||||
def _add_defaults_optional(self):
|
||||
optional = ['tests/test*.py', 'test/test*.py', 'setup.cfg']
|
||||
@@ -309,7 +296,7 @@ class sdist(Command):
|
||||
|
||||
# getting package_data files
|
||||
# (computed in build_py.data_files by build_py.finalize_options)
|
||||
for pkg, src_dir, build_dir, filenames in build_py.data_files:
|
||||
for _pkg, src_dir, _build_dir, filenames in build_py.data_files:
|
||||
for filename in filenames:
|
||||
self.filelist.append(os.path.join(src_dir, filename))
|
||||
|
||||
@@ -354,12 +341,12 @@ class sdist(Command):
|
||||
log.info("reading manifest template '%s'", self.template)
|
||||
template = TextFile(
|
||||
self.template,
|
||||
strip_comments=1,
|
||||
skip_blanks=1,
|
||||
join_lines=1,
|
||||
lstrip_ws=1,
|
||||
rstrip_ws=1,
|
||||
collapse_join=1,
|
||||
strip_comments=True,
|
||||
skip_blanks=True,
|
||||
join_lines=True,
|
||||
lstrip_ws=True,
|
||||
rstrip_ws=True,
|
||||
collapse_join=True,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -392,7 +379,7 @@ class sdist(Command):
|
||||
build = self.get_finalized_command('build')
|
||||
base_dir = self.distribution.get_fullname()
|
||||
|
||||
self.filelist.exclude_pattern(None, prefix=build.build_base)
|
||||
self.filelist.exclude_pattern(None, prefix=os.fspath(build.build_base))
|
||||
self.filelist.exclude_pattern(None, prefix=base_dir)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
@@ -402,7 +389,7 @@ class sdist(Command):
|
||||
|
||||
vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', '_darcs']
|
||||
vcs_ptrn = r'(^|{})({})({}).*'.format(seps, '|'.join(vcs_dirs), seps)
|
||||
self.filelist.exclude_pattern(vcs_ptrn, is_regex=1)
|
||||
self.filelist.exclude_pattern(vcs_ptrn, is_regex=True)
|
||||
|
||||
def write_manifest(self):
|
||||
"""Write the file list in 'self.filelist' (presumably as filled in
|
||||
@@ -411,8 +398,7 @@ class sdist(Command):
|
||||
"""
|
||||
if self._manifest_is_not_generated():
|
||||
log.info(
|
||||
"not writing to manually maintained "
|
||||
"manifest file '%s'" % self.manifest
|
||||
f"not writing to manually maintained manifest file '{self.manifest}'"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -421,7 +407,7 @@ class sdist(Command):
|
||||
self.execute(
|
||||
file_util.write_file,
|
||||
(self.manifest, content),
|
||||
"writing manifest file '%s'" % self.manifest,
|
||||
f"writing manifest file '{self.manifest}'",
|
||||
)
|
||||
|
||||
def _manifest_is_not_generated(self):
|
||||
@@ -429,11 +415,8 @@ class sdist(Command):
|
||||
if not os.path.isfile(self.manifest):
|
||||
return False
|
||||
|
||||
fp = open(self.manifest)
|
||||
try:
|
||||
first_line = fp.readline()
|
||||
finally:
|
||||
fp.close()
|
||||
with open(self.manifest, encoding='utf-8') as fp:
|
||||
first_line = next(fp)
|
||||
return first_line != '# file GENERATED by distutils, do NOT edit\n'
|
||||
|
||||
def read_manifest(self):
|
||||
@@ -442,13 +425,11 @@ class sdist(Command):
|
||||
distribution.
|
||||
"""
|
||||
log.info("reading manifest file '%s'", self.manifest)
|
||||
with open(self.manifest) as manifest:
|
||||
for line in manifest:
|
||||
with open(self.manifest, encoding='utf-8') as lines:
|
||||
self.filelist.extend(
|
||||
# ignore comments and blank lines
|
||||
line = line.strip()
|
||||
if line.startswith('#') or not line:
|
||||
continue
|
||||
self.filelist.append(line)
|
||||
filter(None, filterfalse(is_comment, map(str.strip, lines)))
|
||||
)
|
||||
|
||||
def make_release_tree(self, base_dir, files):
|
||||
"""Create the directory tree that will become the source
|
||||
@@ -474,10 +455,10 @@ class sdist(Command):
|
||||
|
||||
if hasattr(os, 'link'): # can make hard links on this system
|
||||
link = 'hard'
|
||||
msg = "making hard links in %s..." % base_dir
|
||||
msg = f"making hard links in {base_dir}..."
|
||||
else: # nope, have to copy
|
||||
link = None
|
||||
msg = "copying files to %s..." % base_dir
|
||||
msg = f"copying files to {base_dir}..."
|
||||
|
||||
if not files:
|
||||
log.warning("no files to distribute -- empty manifest?")
|
||||
@@ -528,3 +509,7 @@ class sdist(Command):
|
||||
was run, or None if the command hasn't run yet.
|
||||
"""
|
||||
return self.archive_files
|
||||
|
||||
|
||||
def is_comment(line):
|
||||
return line.startswith('#')
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
"""
|
||||
distutils.command.upload
|
||||
|
||||
Implements the Distutils 'upload' subcommand (upload package to a package
|
||||
index).
|
||||
"""
|
||||
|
||||
import os
|
||||
import io
|
||||
import hashlib
|
||||
import logging
|
||||
from base64 import standard_b64encode
|
||||
from urllib.request import urlopen, Request, HTTPError
|
||||
from urllib.parse import urlparse
|
||||
from ..errors import DistutilsError, DistutilsOptionError
|
||||
from ..core import PyPIRCCommand
|
||||
from ..spawn import spawn
|
||||
|
||||
|
||||
# PyPI Warehouse supports MD5, SHA256, and Blake2 (blake2-256)
|
||||
# https://bugs.python.org/issue40698
|
||||
_FILE_CONTENT_DIGESTS = {
|
||||
"md5_digest": getattr(hashlib, "md5", None),
|
||||
"sha256_digest": getattr(hashlib, "sha256", None),
|
||||
"blake2_256_digest": getattr(hashlib, "blake2b", None),
|
||||
}
|
||||
|
||||
|
||||
class upload(PyPIRCCommand):
|
||||
description = "upload binary package to PyPI"
|
||||
|
||||
user_options = PyPIRCCommand.user_options + [
|
||||
('sign', 's', 'sign files to upload using gpg'),
|
||||
('identity=', 'i', 'GPG identity used to sign files'),
|
||||
]
|
||||
|
||||
boolean_options = PyPIRCCommand.boolean_options + ['sign']
|
||||
|
||||
def initialize_options(self):
|
||||
PyPIRCCommand.initialize_options(self)
|
||||
self.username = ''
|
||||
self.password = ''
|
||||
self.show_response = 0
|
||||
self.sign = False
|
||||
self.identity = None
|
||||
|
||||
def finalize_options(self):
|
||||
PyPIRCCommand.finalize_options(self)
|
||||
if self.identity and not self.sign:
|
||||
raise DistutilsOptionError("Must use --sign for --identity to have meaning")
|
||||
config = self._read_pypirc()
|
||||
if config != {}:
|
||||
self.username = config['username']
|
||||
self.password = config['password']
|
||||
self.repository = config['repository']
|
||||
self.realm = config['realm']
|
||||
|
||||
# getting the password from the distribution
|
||||
# if previously set by the register command
|
||||
if not self.password and self.distribution.password:
|
||||
self.password = self.distribution.password
|
||||
|
||||
def run(self):
|
||||
if not self.distribution.dist_files:
|
||||
msg = (
|
||||
"Must create and upload files in one command "
|
||||
"(e.g. setup.py sdist upload)"
|
||||
)
|
||||
raise DistutilsOptionError(msg)
|
||||
for command, pyversion, filename in self.distribution.dist_files:
|
||||
self.upload_file(command, pyversion, filename)
|
||||
|
||||
def upload_file(self, command, pyversion, filename): # noqa: C901
|
||||
# Makes sure the repository URL is compliant
|
||||
schema, netloc, url, params, query, fragments = urlparse(self.repository)
|
||||
if params or query or fragments:
|
||||
raise AssertionError("Incompatible url %s" % self.repository)
|
||||
|
||||
if schema not in ('http', 'https'):
|
||||
raise AssertionError("unsupported schema " + schema)
|
||||
|
||||
# Sign if requested
|
||||
if self.sign:
|
||||
gpg_args = ["gpg", "--detach-sign", "-a", filename]
|
||||
if self.identity:
|
||||
gpg_args[2:2] = ["--local-user", self.identity]
|
||||
spawn(gpg_args, dry_run=self.dry_run)
|
||||
|
||||
# Fill in the data - send all the meta-data in case we need to
|
||||
# register a new release
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
content = f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
meta = self.distribution.metadata
|
||||
data = {
|
||||
# action
|
||||
':action': 'file_upload',
|
||||
'protocol_version': '1',
|
||||
# identify release
|
||||
'name': meta.get_name(),
|
||||
'version': meta.get_version(),
|
||||
# file content
|
||||
'content': (os.path.basename(filename), content),
|
||||
'filetype': command,
|
||||
'pyversion': pyversion,
|
||||
# additional meta-data
|
||||
'metadata_version': '1.0',
|
||||
'summary': meta.get_description(),
|
||||
'home_page': meta.get_url(),
|
||||
'author': meta.get_contact(),
|
||||
'author_email': meta.get_contact_email(),
|
||||
'license': meta.get_licence(),
|
||||
'description': meta.get_long_description(),
|
||||
'keywords': meta.get_keywords(),
|
||||
'platform': meta.get_platforms(),
|
||||
'classifiers': meta.get_classifiers(),
|
||||
'download_url': meta.get_download_url(),
|
||||
# PEP 314
|
||||
'provides': meta.get_provides(),
|
||||
'requires': meta.get_requires(),
|
||||
'obsoletes': meta.get_obsoletes(),
|
||||
}
|
||||
|
||||
data['comment'] = ''
|
||||
|
||||
# file content digests
|
||||
for digest_name, digest_cons in _FILE_CONTENT_DIGESTS.items():
|
||||
if digest_cons is None:
|
||||
continue
|
||||
try:
|
||||
data[digest_name] = digest_cons(content).hexdigest()
|
||||
except ValueError:
|
||||
# hash digest not available or blocked by security policy
|
||||
pass
|
||||
|
||||
if self.sign:
|
||||
with open(filename + ".asc", "rb") as f:
|
||||
data['gpg_signature'] = (os.path.basename(filename) + ".asc", f.read())
|
||||
|
||||
# set up the authentication
|
||||
user_pass = (self.username + ":" + self.password).encode('ascii')
|
||||
# The exact encoding of the authentication string is debated.
|
||||
# Anyway PyPI only accepts ascii for both username or password.
|
||||
auth = "Basic " + standard_b64encode(user_pass).decode('ascii')
|
||||
|
||||
# Build up the MIME payload for the POST data
|
||||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = b'\r\n--' + boundary.encode('ascii')
|
||||
end_boundary = sep_boundary + b'--\r\n'
|
||||
body = io.BytesIO()
|
||||
for key, value in data.items():
|
||||
title = '\r\nContent-Disposition: form-data; name="%s"' % key
|
||||
# handle multiple entries for the same name
|
||||
if not isinstance(value, list):
|
||||
value = [value]
|
||||
for value in value:
|
||||
if type(value) is tuple:
|
||||
title += '; filename="%s"' % value[0]
|
||||
value = value[1]
|
||||
else:
|
||||
value = str(value).encode('utf-8')
|
||||
body.write(sep_boundary)
|
||||
body.write(title.encode('utf-8'))
|
||||
body.write(b"\r\n\r\n")
|
||||
body.write(value)
|
||||
body.write(end_boundary)
|
||||
body = body.getvalue()
|
||||
|
||||
msg = "Submitting {} to {}".format(filename, self.repository)
|
||||
self.announce(msg, logging.INFO)
|
||||
|
||||
# build the Request
|
||||
headers = {
|
||||
'Content-type': 'multipart/form-data; boundary=%s' % boundary,
|
||||
'Content-length': str(len(body)),
|
||||
'Authorization': auth,
|
||||
}
|
||||
|
||||
request = Request(self.repository, data=body, headers=headers)
|
||||
# send the data
|
||||
try:
|
||||
result = urlopen(request)
|
||||
status = result.getcode()
|
||||
reason = result.msg
|
||||
except HTTPError as e:
|
||||
status = e.code
|
||||
reason = e.msg
|
||||
except OSError as e:
|
||||
self.announce(str(e), logging.ERROR)
|
||||
raise
|
||||
|
||||
if status == 200:
|
||||
self.announce(
|
||||
'Server response ({}): {}'.format(status, reason), logging.INFO
|
||||
)
|
||||
if self.show_response:
|
||||
text = self._read_pypi_response(result)
|
||||
msg = '\n'.join(('-' * 75, text, '-' * 75))
|
||||
self.announce(msg, logging.INFO)
|
||||
else:
|
||||
msg = 'Upload failed ({}): {}'.format(status, reason)
|
||||
self.announce(msg, logging.ERROR)
|
||||
raise DistutilsError(msg)
|
||||
Reference in New Issue
Block a user