summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/deprecated/distutils/apiref.rst37
-rw-r--r--docs/deprecated/distutils/builtdist.rst95
-rw-r--r--docs/deprecated/distutils/commandref.rst1
-rw-r--r--docs/deprecated/distutils/introduction.rst11
-rw-r--r--setuptools/_distutils/ccompiler.py24
-rw-r--r--setuptools/_distutils/command/__init__.py1
-rw-r--r--setuptools/_distutils/command/bdist.py2
-rw-r--r--setuptools/_distutils/command/bdist_msi.py1114
-rw-r--r--setuptools/_distutils/command/bdist_wininst.py418
-rw-r--r--setuptools/_distutils/cygwinccompiler.py41
-rw-r--r--setuptools/_distutils/tests/test_bdist.py18
-rw-r--r--setuptools/_distutils/tests/test_bdist_msi.py20
-rw-r--r--setuptools/_distutils/tests/test_bdist_wininst.py27
13 files changed, 27 insertions, 1782 deletions
diff --git a/docs/deprecated/distutils/apiref.rst b/docs/deprecated/distutils/apiref.rst
index f00ed74c..278471a2 100644
--- a/docs/deprecated/distutils/apiref.rst
+++ b/docs/deprecated/distutils/apiref.rst
@@ -1845,30 +1845,6 @@ Subclasses of :class:`Command` must define the following methods.
:synopsis: Build a "dumb" installer - a simple archive of files
-.. % todo
-
-
-:mod:`distutils.command.bdist_msi` --- Build a Microsoft Installer binary package
-=================================================================================
-
-.. module:: distutils.command.bdist_msi
- :synopsis: Build a binary distribution as a Windows MSI file
-
-.. class:: bdist_msi
-
-.. deprecated:: 3.9
- Use bdist_wheel (wheel packages) instead.
-
- Builds a `Windows Installer`_ (.msi) binary package.
-
- .. _Windows Installer: https://msdn.microsoft.com/en-us/library/cc185688(VS.85).aspx
-
- In most cases, the ``bdist_msi`` installer is a better choice than the
- ``bdist_wininst`` installer, because it provides better support for
- Win64 platforms, allows administrators to perform non-interactive
- installations, and allows installation through group policies.
-
-
:mod:`distutils.command.bdist_rpm` --- Build a binary distribution as a Redhat RPM and SRPM
===========================================================================================
@@ -1879,19 +1855,6 @@ Subclasses of :class:`Command` must define the following methods.
.. % todo
-:mod:`distutils.command.bdist_wininst` --- Build a Windows installer
-====================================================================
-
-.. module:: distutils.command.bdist_wininst
- :synopsis: Build a Windows installer
-
-.. deprecated:: 3.8
- Use bdist_wheel (wheel packages) instead.
-
-
-.. % todo
-
-
:mod:`distutils.command.sdist` --- Build a source distribution
==============================================================
diff --git a/docs/deprecated/distutils/builtdist.rst b/docs/deprecated/distutils/builtdist.rst
index e032c03e..052a5850 100644
--- a/docs/deprecated/distutils/builtdist.rst
+++ b/docs/deprecated/distutils/builtdist.rst
@@ -96,11 +96,6 @@ The available formats for built distributions are:
+-------------+------------------------------+---------+
| ``sdux`` | HP-UX :program:`swinstall` | |
+-------------+------------------------------+---------+
-| ``wininst`` | self-extracting ZIP file for | \(4) |
-| | Windows | |
-+-------------+------------------------------+---------+
-| ``msi`` | Microsoft Installer. | |
-+-------------+------------------------------+---------+
.. versionchanged:: 3.5
Added support for the ``xztar`` format.
@@ -141,16 +136,6 @@ generated by each, are:
+--------------------------+-------------------------------------+
| :command:`bdist_rpm` | rpm, srpm |
+--------------------------+-------------------------------------+
-| :command:`bdist_wininst` | wininst |
-+--------------------------+-------------------------------------+
-| :command:`bdist_msi` | msi |
-+--------------------------+-------------------------------------+
-
-.. note::
- bdist_wininst is deprecated since Python 3.8.
-
-.. note::
- bdist_msi is deprecated since Python 3.9.
The following sections give details on the individual :command:`bdist_\*`
commands.
@@ -191,7 +176,7 @@ easily specify multiple formats in one run. If you need to do both, you can
explicitly specify multiple :command:`bdist_\*` commands and their options::
python setup.py bdist_rpm --packager="John Doe <jdoe@example.org>" \
- bdist_wininst --target-version="2.0"
+ bdist_dumb --dumb-option=foo
Creating RPM packages is driven by a :file:`.spec` file, much as using the
Distutils is driven by the setup script. To make your life easier, the
@@ -298,62 +283,6 @@ file winds up deep in the "build tree," in a temporary directory created by
.. % \command{bdist\_rpm} command with one that writes whatever else you want
.. % to the \file{.spec} file.)
-
-.. _creating-wininst:
-
-Creating Windows Installers
-===========================
-
-.. warning::
- bdist_wininst is deprecated since Python 3.8.
-
-.. warning::
- bdist_msi is deprecated since Python 3.9.
-
-Executable installers are the natural format for binary distributions on
-Windows. They display a nice graphical user interface, display some information
-about the module distribution to be installed taken from the metadata in the
-setup script, let the user select a few options, and start or cancel the
-installation.
-
-Since the metadata is taken from the setup script, creating Windows installers
-is usually as easy as running::
-
- python setup.py bdist_wininst
-
-or the :command:`bdist` command with the :option:`!--formats` option::
-
- python setup.py bdist --formats=wininst
-
-If you have a pure module distribution (only containing pure Python modules and
-packages), the resulting installer will be version independent and have a name
-like :file:`foo-1.0.win32.exe`. Note that creating ``wininst`` binary
-distributions in only supported on Windows systems.
-
-If you have a non-pure distribution, the extensions can only be created on a
-Windows platform, and will be Python version dependent. The installer filename
-will reflect this and now has the form :file:`foo-1.0.win32-py2.0.exe`. You
-have to create a separate installer for every Python version you want to
-support.
-
-The installer will try to compile pure modules into :term:`bytecode` after installation
-on the target system in normal and optimizing mode. If you don't want this to
-happen for some reason, you can run the :command:`bdist_wininst` command with
-the :option:`!--no-target-compile` and/or the :option:`!--no-target-optimize`
-option.
-
-By default the installer will display the cool "Python Powered" logo when it is
-run, but you can also supply your own 152x261 bitmap which must be a Windows
-:file:`.bmp` file with the :option:`!--bitmap` option.
-
-The installer will also display a large title on the desktop background window
-when it is run, which is constructed from the name of your distribution and the
-version number. This can be changed to another text by using the
-:option:`!--title` option.
-
-The installer file will be written to the "distribution directory" --- normally
-:file:`dist/`, but customizable with the :option:`!--dist-dir` option.
-
.. _cross-compile-windows:
Cross-compiling on Windows
@@ -370,12 +299,7 @@ For example, on a 32bit version of Windows, you could execute::
python setup.py build --plat-name=win-amd64
-to build a 64bit version of your extension. The Windows Installers also
-support this option, so the command::
-
- python setup.py build --plat-name=win-amd64 bdist_wininst
-
-would create a 64bit installation executable on your 32bit version of Windows.
+to build a 64bit version of your extension.
To cross-compile, you must download the Python source code and cross-compile
Python itself for the platform you are targeting - it is not possible from a
@@ -462,18 +386,3 @@ built-in functions in the installation script.
and *iconindex* is the index of the icon in the file *iconpath*. Again, for
details consult the Microsoft documentation for the :class:`IShellLink`
interface.
-
-
-Vista User Access Control (UAC)
-===============================
-
-Starting with Python 2.6, bdist_wininst supports a :option:`!--user-access-control`
-option. The default is 'none' (meaning no UAC handling is done), and other
-valid values are 'auto' (meaning prompt for UAC elevation if Python was
-installed for all users) and 'force' (meaning always prompt for elevation).
-
-.. note::
- bdist_wininst is deprecated since Python 3.8.
-
-.. note::
- bdist_msi is deprecated since Python 3.9.
diff --git a/docs/deprecated/distutils/commandref.rst b/docs/deprecated/distutils/commandref.rst
index 0f6fe2ab..3e247e68 100644
--- a/docs/deprecated/distutils/commandref.rst
+++ b/docs/deprecated/distutils/commandref.rst
@@ -101,6 +101,5 @@ anything except backslash or colon.
.. % \subsection{\protect\command{bdist}}
.. % \subsection{\protect\command{bdist\_dumb}}
.. % \subsection{\protect\command{bdist\_rpm}}
-.. % \subsection{\protect\command{bdist\_wininst}}
diff --git a/docs/deprecated/distutils/introduction.rst b/docs/deprecated/distutils/introduction.rst
index 7491b965..58a31283 100644
--- a/docs/deprecated/distutils/introduction.rst
+++ b/docs/deprecated/distutils/introduction.rst
@@ -112,17 +112,6 @@ the setup script. The difference is which Distutils *commands* they use: the
:command:`install` is more often for installers (although most developers will
want to install their own code occasionally).
-If you want to make things really easy for your users, you can create one or
-more built distributions for them. For instance, if you are running on a
-Windows machine, and want to make things easy for other Windows users, you can
-create an executable installer (the most appropriate type of built distribution
-for this platform) with the :command:`bdist_wininst` command. For example::
-
- python setup.py bdist_wininst
-
-will create an executable installer, :file:`foo-1.0.win32.exe`, in the current
-directory.
-
Other useful built distribution formats are RPM, implemented by the
:command:`bdist_rpm` command, Solaris :program:`pkgtool`
(:command:`bdist_pkgtool`), and HP-UX :program:`swinstall`
diff --git a/setuptools/_distutils/ccompiler.py b/setuptools/_distutils/ccompiler.py
index 3cf5761c..c8d3b24b 100644
--- a/setuptools/_distutils/ccompiler.py
+++ b/setuptools/_distutils/ccompiler.py
@@ -6,6 +6,8 @@ for the Distutils compiler abstraction model."""
import sys
import os
import re
+import warnings
+
from distutils.errors import (
CompileError,
LinkError,
@@ -925,8 +927,7 @@ int main (int argc, char **argv) {
obj_names = []
for src_name in source_filenames:
base, ext = os.path.splitext(src_name)
- base = os.path.splitdrive(base)[1] # Chop off the drive
- base = base[os.path.isabs(base) :] # If abs, chop off leading /
+ base = self._mangle_base(base)
if ext not in self.src_extensions:
raise UnknownFileError(
"unknown file type '{}' (from '{}')".format(ext, src_name)
@@ -936,6 +937,25 @@ int main (int argc, char **argv) {
obj_names.append(os.path.join(output_dir, base + self.obj_extension))
return obj_names
+ @staticmethod
+ def _mangle_base(base):
+ """
+ For unknown reasons, absolute paths are mangled.
+ """
+ # Chop off the drive
+ no_drive = os.path.splitdrive(base)[1]
+ # If abs, chop off leading /
+ rel = no_drive[os.path.isabs(no_drive) :]
+ if rel != base:
+ msg = (
+ f"Absolute path {base!r} is being replaced with a "
+ f"relative path {rel!r} for outputs. This behavior is "
+ "deprecated. If this behavior is desired, please "
+ "comment in pypa/distutils#169."
+ )
+ warnings.warn(msg, DeprecationWarning)
+ return rel
+
def shared_object_filename(self, basename, strip_dir=0, output_dir=''):
assert output_dir is not None
if strip_dir:
diff --git a/setuptools/_distutils/command/__init__.py b/setuptools/_distutils/command/__init__.py
index a40c1f94..028dcfa0 100644
--- a/setuptools/_distutils/command/__init__.py
+++ b/setuptools/_distutils/command/__init__.py
@@ -20,7 +20,6 @@ __all__ = [ # noqa: F822
'bdist',
'bdist_dumb',
'bdist_rpm',
- 'bdist_wininst',
'check',
'upload',
]
diff --git a/setuptools/_distutils/command/bdist.py b/setuptools/_distutils/command/bdist.py
index c9fdbf13..de37dae0 100644
--- a/setuptools/_distutils/command/bdist.py
+++ b/setuptools/_distutils/command/bdist.py
@@ -85,9 +85,7 @@ class bdist(Command):
'xztar': ('bdist_dumb', "xz'ed tar file"),
'ztar': ('bdist_dumb', "compressed tar file"),
'tar': ('bdist_dumb', "tar file"),
- 'wininst': ('bdist_wininst', "Windows executable installer"),
'zip': ('bdist_dumb', "ZIP file"),
- 'msi': ('bdist_msi', "Microsoft Installer"),
}
)
diff --git a/setuptools/_distutils/command/bdist_msi.py b/setuptools/_distutils/command/bdist_msi.py
deleted file mode 100644
index 57931c73..00000000
--- a/setuptools/_distutils/command/bdist_msi.py
+++ /dev/null
@@ -1,1114 +0,0 @@
-# Copyright (C) 2005, 2006 Martin von Löwis
-# Licensed to PSF under a Contributor Agreement.
-# The bdist_wininst command proper
-# based on bdist_wininst
-"""
-Implements the bdist_msi command.
-"""
-
-import os
-import sys
-import warnings
-from distutils.core import Command
-from distutils.dir_util import remove_tree
-from distutils.sysconfig import get_python_version
-from distutils.version import StrictVersion
-from distutils.errors import DistutilsOptionError
-from distutils.util import get_platform
-from distutils import log
-import msilib
-from msilib import schema, sequence, text
-from msilib import Directory, Feature, Dialog, add_data
-
-
-class PyDialog(Dialog):
- """Dialog class with a fixed layout: controls at the top, then a ruler,
- then a list of buttons: back, next, cancel. Optionally a bitmap at the
- left."""
-
- def __init__(self, *args, **kw):
- """Dialog(database, name, x, y, w, h, attributes, title, first,
- default, cancel, bitmap=true)"""
- super().__init__(*args)
- ruler = self.h - 36
- self.line("BottomLine", 0, ruler, self.w, 0)
-
- def title(self, title):
- "Set the title text of the dialog at the top."
- # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix,
- # text, in VerdanaBold10
- self.text("Title", 15, 10, 320, 60, 0x30003, r"{\VerdanaBold10}%s" % title)
-
- def back(self, title, next, name="Back", active=1):
- """Add a back button with a given title, the tab-next button,
- its name in the Control table, possibly initially disabled.
-
- Return the button, so that events can be associated"""
- if active:
- flags = 3 # Visible|Enabled
- else:
- flags = 1 # Visible
- return self.pushbutton(name, 180, self.h - 27, 56, 17, flags, title, next)
-
- def cancel(self, title, next, name="Cancel", active=1):
- """Add a cancel button with a given title, the tab-next button,
- its name in the Control table, possibly initially disabled.
-
- Return the button, so that events can be associated"""
- if active:
- flags = 3 # Visible|Enabled
- else:
- flags = 1 # Visible
- return self.pushbutton(name, 304, self.h - 27, 56, 17, flags, title, next)
-
- def next(self, title, next, name="Next", active=1):
- """Add a Next button with a given title, the tab-next button,
- its name in the Control table, possibly initially disabled.
-
- Return the button, so that events can be associated"""
- if active:
- flags = 3 # Visible|Enabled
- else:
- flags = 1 # Visible
- return self.pushbutton(name, 236, self.h - 27, 56, 17, flags, title, next)
-
- def xbutton(self, name, title, next, xpos):
- """Add a button with a given title, the tab-next button,
- its name in the Control table, giving its x position; the
- y-position is aligned with the other buttons.
-
- Return the button, so that events can be associated"""
- return self.pushbutton(
- name, int(self.w * xpos - 28), self.h - 27, 56, 17, 3, title, next
- )
-
-
-class bdist_msi(Command):
-
- description = "create a Microsoft Installer (.msi) binary distribution"
-
- user_options = [
- ('bdist-dir=', None, "temporary directory for creating the distribution"),
- (
- 'plat-name=',
- 'p',
- "platform name to embed in generated filenames "
- "(default: %s)" % get_platform(),
- ),
- (
- 'keep-temp',
- 'k',
- "keep the pseudo-installation tree around after "
- + "creating the distribution archive",
- ),
- (
- 'target-version=',
- None,
- "require a specific python version" + " on the target system",
- ),
- ('no-target-compile', 'c', "do not compile .py to .pyc on the target system"),
- (
- 'no-target-optimize',
- 'o',
- "do not compile .py to .pyo (optimized) " "on the target system",
- ),
- ('dist-dir=', 'd', "directory to put final built distributions in"),
- ('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
- (
- 'install-script=',
- None,
- "basename of installation script to be run after "
- "installation or before deinstallation",
- ),
- (
- 'pre-install-script=',
- None,
- "Fully qualified filename of a script to be run before "
- "any files are installed. This script need not be in the "
- "distribution",
- ),
- ]
-
- boolean_options = [
- 'keep-temp',
- 'no-target-compile',
- 'no-target-optimize',
- 'skip-build',
- ]
-
- all_versions = [
- '2.0',
- '2.1',
- '2.2',
- '2.3',
- '2.4',
- '2.5',
- '2.6',
- '2.7',
- '2.8',
- '2.9',
- '3.0',
- '3.1',
- '3.2',
- '3.3',
- '3.4',
- '3.5',
- '3.6',
- '3.7',
- '3.8',
- '3.9',
- ]
- other_version = 'X'
-
- def __init__(self, *args, **kw):
- super().__init__(*args, **kw)
- warnings.warn(
- "bdist_msi command is deprecated since Python 3.9, "
- "use bdist_wheel (wheel packages) instead",
- DeprecationWarning,
- 2,
- )
-
- def initialize_options(self):
- self.bdist_dir = None
- self.plat_name = None
- self.keep_temp = 0
- self.no_target_compile = 0
- self.no_target_optimize = 0
- self.target_version = None
- self.dist_dir = None
- self.skip_build = None
- self.install_script = None
- self.pre_install_script = None
- self.versions = None
-
- def finalize_options(self):
- self.set_undefined_options('bdist', ('skip_build', 'skip_build'))
-
- if self.bdist_dir is None:
- bdist_base = self.get_finalized_command('bdist').bdist_base
- self.bdist_dir = os.path.join(bdist_base, 'msi')
-
- short_version = get_python_version()
- if (not self.target_version) and self.distribution.has_ext_modules():
- self.target_version = short_version
-
- if self.target_version:
- self.versions = [self.target_version]
- if (
- not self.skip_build
- and self.distribution.has_ext_modules()
- and self.target_version != short_version
- ):
- raise DistutilsOptionError(
- "target version can only be %s, or the '--skip-build'"
- " option must be specified" % (short_version,)
- )
- else:
- self.versions = list(self.all_versions)
-
- self.set_undefined_options(
- 'bdist',
- ('dist_dir', 'dist_dir'),
- ('plat_name', 'plat_name'),
- )
-
- if self.pre_install_script:
- raise DistutilsOptionError(
- "the pre-install-script feature is not yet implemented"
- )
-
- if self.install_script:
- for script in self.distribution.scripts:
- if self.install_script == os.path.basename(script):
- break
- else:
- raise DistutilsOptionError(
- "install_script '%s' not found in scripts" % self.install_script
- )
- self.install_script_key = None
-
- def run(self): # noqa: C901
- if not self.skip_build:
- self.run_command('build')
-
- install = self.reinitialize_command('install', reinit_subcommands=1)
- install.prefix = self.bdist_dir
- install.skip_build = self.skip_build
- install.warn_dir = 0
-
- install_lib = self.reinitialize_command('install_lib')
- # we do not want to include pyc or pyo files
- install_lib.compile = 0
- install_lib.optimize = 0
-
- if self.distribution.has_ext_modules():
- # If we are building an installer for a Python version other
- # than the one we are currently running, then we need to ensure
- # our build_lib reflects the other Python version rather than ours.
- # Note that for target_version!=sys.version, we must have skipped the
- # build step, so there is no issue with enforcing the build of this
- # version.
- target_version = self.target_version
- if not target_version:
- assert self.skip_build, "Should have already checked this"
- target_version = '%d.%d' % sys.version_info[:2]
- plat_specifier = ".{}-{}".format(self.plat_name, target_version)
- build = self.get_finalized_command('build')
- build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier)
-
- log.info("installing to %s", self.bdist_dir)
- install.ensure_finalized()
-
- # avoid warning of 'install_lib' about installing
- # into a directory not in sys.path
- sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
-
- install.run()
-
- del sys.path[0]
-
- self.mkpath(self.dist_dir)
- fullname = self.distribution.get_fullname()
- installer_name = self.get_installer_filename(fullname)
- installer_name = os.path.abspath(installer_name)
- if os.path.exists(installer_name):
- os.unlink(installer_name)
-
- metadata = self.distribution.metadata
- author = metadata.author or metadata.maintainer
- version = metadata.get_version()
- # ProductVersion must be strictly numeric
- # XXX need to deal with prerelease versions
- sversion = "%d.%d.%d" % StrictVersion(version).version
- # Prefix ProductName with Python x.y, so that
- # it sorts together with the other Python packages
- # in Add-Remove-Programs (APR)
- fullname = self.distribution.get_fullname()
- if self.target_version:
- product_name = "Python {} {}".format(self.target_version, fullname)
- else:
- product_name = "Python %s" % (fullname)
- self.db = msilib.init_database(
- installer_name, schema, product_name, msilib.gen_uuid(), sversion, author
- )
- msilib.add_tables(self.db, sequence)
- props = [('DistVersion', version)]
- email = metadata.author_email or metadata.maintainer_email
- if email:
- props.append(("ARPCONTACT", email))
- if metadata.url:
- props.append(("ARPURLINFOABOUT", metadata.url))
- if props:
- add_data(self.db, 'Property', props)
-
- self.add_find_python()
- self.add_files()
- self.add_scripts()
- self.add_ui()
- self.db.Commit()
-
- if hasattr(self.distribution, 'dist_files'):
- tup = 'bdist_msi', self.target_version or 'any', fullname
- self.distribution.dist_files.append(tup)
-
- if not self.keep_temp:
- remove_tree(self.bdist_dir, dry_run=self.dry_run)
-
- def add_files(self): # noqa: C901
- db = self.db
- cab = msilib.CAB("distfiles")
- rootdir = os.path.abspath(self.bdist_dir)
-
- root = Directory(db, cab, None, rootdir, "TARGETDIR", "SourceDir")
- f = Feature(db, "Python", "Python", "Everything", 0, 1, directory="TARGETDIR")
-
- items = [(f, root, '')]
- for version in self.versions + [self.other_version]:
- target = "TARGETDIR" + version
- name = default = "Python" + version
- desc = "Everything"
- if version is self.other_version:
- title = "Python from another location"
- level = 2
- else:
- title = "Python %s from registry" % version
- level = 1
- f = Feature(db, name, title, desc, 1, level, directory=target)
- dir = Directory(db, cab, root, rootdir, target, default)
- items.append((f, dir, version))
- db.Commit()
-
- seen = {}
- for feature, dir, version in items:
- todo = [dir]
- while todo:
- dir = todo.pop()
- for file in os.listdir(dir.absolute):
- afile = os.path.join(dir.absolute, file)
- if os.path.isdir(afile):
- short = "{}|{}".format(dir.make_short(file), file)
- default = file + version
- newdir = Directory(db, cab, dir, file, default, short)
- todo.append(newdir)
- else:
- if not dir.component:
- dir.start_component(dir.logical, feature, 0)
- if afile not in seen:
- key = seen[afile] = dir.add_file(file)
- if file == self.install_script:
- if self.install_script_key:
- raise DistutilsOptionError(
- "Multiple files with name %s" % file
- )
- self.install_script_key = '[#%s]' % key
- else:
- key = seen[afile]
- add_data(
- self.db,
- "DuplicateFile",
- [
- (
- key + version,
- dir.component,
- key,
- None,
- dir.logical,
- )
- ],
- )
- db.Commit()
- cab.commit(db)
-
- def add_find_python(self):
- """Adds code to the installer to compute the location of Python.
-
- Properties PYTHON.MACHINE.X.Y and PYTHON.USER.X.Y will be set from the
- registry for each version of Python.
-
- Properties TARGETDIRX.Y will be set from PYTHON.USER.X.Y if defined,
- else from PYTHON.MACHINE.X.Y.
-
- Properties PYTHONX.Y will be set to TARGETDIRX.Y\\python.exe"""
-
- start = 402
- for ver in self.versions:
- install_path = r"SOFTWARE\Python\PythonCore\%s\InstallPath" % ver
- machine_reg = "python.machine." + ver
- user_reg = "python.user." + ver
- machine_prop = "PYTHON.MACHINE." + ver
- user_prop = "PYTHON.USER." + ver
- machine_action = "PythonFromMachine" + ver
- user_action = "PythonFromUser" + ver
- exe_action = "PythonExe" + ver
- target_dir_prop = "TARGETDIR" + ver
- exe_prop = "PYTHON" + ver
-
- # Type: msidbLocatorTypeRawValue + msidbLocatorType64bit
- Type = 2 + 16 * bool(msilib.Win64)
- add_data(
- self.db,
- "RegLocator",
- [
- (machine_reg, 2, install_path, None, Type),
- (user_reg, 1, install_path, None, Type),
- ],
- )
- add_data(
- self.db,
- "AppSearch",
- [(machine_prop, machine_reg), (user_prop, user_reg)],
- )
- add_data(
- self.db,
- "CustomAction",
- [
- (
- machine_action,
- 51 + 256,
- target_dir_prop,
- "[" + machine_prop + "]",
- ),
- (user_action, 51 + 256, target_dir_prop, "[" + user_prop + "]"),
- (
- exe_action,
- 51 + 256,
- exe_prop,
- "[" + target_dir_prop + "]\\python.exe",
- ),
- ],
- )
- add_data(
- self.db,
- "InstallExecuteSequence",
- [
- (machine_action, machine_prop, start),
- (user_action, user_prop, start + 1),
- (exe_action, None, start + 2),
- ],
- )
- add_data(
- self.db,
- "InstallUISequence",
- [
- (machine_action, machine_prop, start),
- (user_action, user_prop, start + 1),
- (exe_action, None, start + 2),
- ],
- )
- add_data(self.db, "Condition", [("Python" + ver, 0, "NOT TARGETDIR" + ver)])
- start += 4
- assert start < 500
-
- def add_scripts(self):
- if self.install_script:
- start = 6800
- for ver in self.versions + [self.other_version]:
- install_action = "install_script." + ver
- exe_prop = "PYTHON" + ver
- add_data(
- self.db,
- "CustomAction",
- [(install_action, 50, exe_prop, self.install_script_key)],
- )
- add_data(
- self.db,
- "InstallExecuteSequence",
- [(install_action, "&Python%s=3" % ver, start)],
- )
- start += 1
- # XXX pre-install scripts are currently refused in finalize_options()
- # but if this feature is completed, it will also need to add
- # entries for each version as the above code does
- if self.pre_install_script:
- scriptfn = os.path.join(self.bdist_dir, "preinstall.bat")
- with open(scriptfn, "w") as f:
- # The batch file will be executed with [PYTHON], so that %1
- # is the path to the Python interpreter; %0 will be the path
- # of the batch file.
- # rem ="""
- # %1 %0
- # exit
- # """
- # <actual script>
- f.write('rem ="""\n%1 %0\nexit\n"""\n')
- with open(self.pre_install_script) as fin:
- f.write(fin.read())
- add_data(self.db, "Binary", [("PreInstall", msilib.Binary(scriptfn))])
- add_data(self.db, "CustomAction", [("PreInstall", 2, "PreInstall", None)])
- add_data(
- self.db,
- "InstallExecuteSequence",
- [("PreInstall", "NOT Installed", 450)],
- )
-
- def add_ui(self):
- db = self.db
- x = y = 50
- w = 370
- h = 300
- title = "[ProductName] Setup"
-
- # see "Dialog Style Bits"
- modal = 3 # visible | modal
- modeless = 1 # visible
-
- # UI customization properties
- add_data(
- db,
- "Property",
- # See "DefaultUIFont Property"
- [
- ("DefaultUIFont", "DlgFont8"),
- # See "ErrorDialog Style Bit"
- ("ErrorDialog", "ErrorDlg"),
- ("Progress1", "Install"), # modified in maintenance type dlg
- ("Progress2", "installs"),
- ("MaintenanceForm_Action", "Repair"),
- # possible values: ALL, JUSTME
- ("WhichUsers", "ALL"),
- ],
- )
-
- # Fonts, see "TextStyle Table"
- add_data(
- db,
- "TextStyle",
- [
- ("DlgFont8", "Tahoma", 9, None, 0),
- ("DlgFontBold8", "Tahoma", 8, None, 1), # bold
- ("VerdanaBold10", "Verdana", 10, None, 1),
- ("VerdanaRed9", "Verdana", 9, 255, 0),
- ],
- )
-
- # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table"
- # Numbers indicate sequence; see sequence.py for how these action integrate
- add_data(
- db,
- "InstallUISequence",
- [
- ("PrepareDlg", "Not Privileged or Windows9x or Installed", 140),
- (
- "WhichUsersDlg",
- "Privileged and not Windows9x and not Installed",
- 141,
- ),
- # In the user interface, assume all-users installation if privileged.
- ("SelectFeaturesDlg", "Not Installed", 1230),
- # XXX no support for resume installations yet
- # ("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240),
- (
- "MaintenanceTypeDlg",
- "Installed AND NOT RESUME AND NOT Preselected",
- 1250,
- ),
- ("ProgressDlg", None, 1280),
- ],
- )
-
- add_data(db, 'ActionText', text.ActionText)
- add_data(db, 'UIText', text.UIText)
- #####################################################################
- # Standard dialogs: FatalError, UserExit, ExitDialog
- fatal = PyDialog(
- db, "FatalError", x, y, w, h, modal, title, "Finish", "Finish", "Finish"
- )
- fatal.title("[ProductName] Installer ended prematurely")
- fatal.back("< Back", "Finish", active=0)
- fatal.cancel("Cancel", "Back", active=0)
- fatal.text(
- "Description1",
- 15,
- 70,
- 320,
- 80,
- 0x30003,
- "[ProductName] setup ended prematurely because of an error. "
- "Your system has not been modified. To install this program "
- "at a later time, please run the installation again.",
- )
- fatal.text(
- "Description2",
- 15,
- 155,
- 320,
- 20,
- 0x30003,
- "Click the Finish button to exit the Installer.",
- )
- c = fatal.next("Finish", "Cancel", name="Finish")
- c.event("EndDialog", "Exit")
-
- user_exit = PyDialog(
- db, "UserExit", x, y, w, h, modal, title, "Finish", "Finish", "Finish"
- )
- user_exit.title("[ProductName] Installer was interrupted")
- user_exit.back("< Back", "Finish", active=0)
- user_exit.cancel("Cancel", "Back", active=0)
- user_exit.text(
- "Description1",
- 15,
- 70,
- 320,
- 80,
- 0x30003,
- "[ProductName] setup was interrupted. Your system has not been modified. "
- "To install this program at a later time, please run the installation "
- "again.",
- )
- user_exit.text(
- "Description2",
- 15,
- 155,
- 320,
- 20,
- 0x30003,
- "Click the Finish button to exit the Installer.",
- )
- c = user_exit.next("Finish", "Cancel", name="Finish")
- c.event("EndDialog", "Exit")
-
- exit_dialog = PyDialog(
- db, "ExitDialog", x, y, w, h, modal, title, "Finish", "Finish", "Finish"
- )
- exit_dialog.title("Completing the [ProductName] Installer")
- exit_dialog.back("< Back", "Finish", active=0)
- exit_dialog.cancel("Cancel", "Back", active=0)
- exit_dialog.text(
- "Description",
- 15,
- 235,
- 320,
- 20,
- 0x30003,
- "Click the Finish button to exit the Installer.",
- )
- c = exit_dialog.next("Finish", "Cancel", name="Finish")
- c.event("EndDialog", "Return")
-
- #####################################################################
- # Required dialog: FilesInUse, ErrorDlg
- inuse = PyDialog(
- db,
- "FilesInUse",
- x,
- y,
- w,
- h,
- 19, # KeepModeless|Modal|Visible
- title,
- "Retry",
- "Retry",
- "Retry",
- bitmap=False,
- )
- inuse.text("Title", 15, 6, 200, 15, 0x30003, r"{\DlgFontBold8}Files in Use")
- inuse.text(
- "Description",
- 20,
- 23,
- 280,
- 20,
- 0x30003,
- "Some files that need to be updated are currently in use.",
- )
- inuse.text(
- "Text",
- 20,
- 55,
- 330,
- 50,
- 3,
- "The following applications are using files that need to be updated by "
- "this "
- "setup. Close these applications and then click Retry to continue the "
- "installation or Cancel to exit it.",
- )
- inuse.control(
- "List",
- "ListBox",
- 20,
- 107,
- 330,
- 130,
- 7,
- "FileInUseProcess",
- None,
- None,
- None,
- )
- c = inuse.back("Exit", "Ignore", name="Exit")
- c.event("EndDialog", "Exit")
- c = inuse.next("Ignore", "Retry", name="Ignore")
- c.event("EndDialog", "Ignore")
- c = inuse.cancel("Retry", "Exit", name="Retry")
- c.event("EndDialog", "Retry")
-
- # See "Error Dialog". See "ICE20" for the required names of the controls.
- error = Dialog(
- db,
- "ErrorDlg",
- 50,
- 10,
- 330,
- 101,
- 65543, # Error|Minimize|Modal|Visible
- title,
- "ErrorText",
- None,
- None,
- )
- error.text("ErrorText", 50, 9, 280, 48, 3, "")
- error.pushbutton("N", 120, 72, 81, 21, 3, "No", None).event(
- "EndDialog", "ErrorNo"
- )
- error.pushbutton("Y", 240, 72, 81, 21, 3, "Yes", None).event(
- "EndDialog", "ErrorYes"
- )
- error.pushbutton("A", 0, 72, 81, 21, 3, "Abort", None).event(
- "EndDialog", "ErrorAbort"
- )
- error.pushbutton("C", 42, 72, 81, 21, 3, "Cancel", None).event(
- "EndDialog", "ErrorCancel"
- )
- error.pushbutton("I", 81, 72, 81, 21, 3, "Ignore", None).event(
- "EndDialog", "ErrorIgnore"
- )
- error.pushbutton("O", 159, 72, 81, 21, 3, "Ok", None).event(
- "EndDialog", "ErrorOk"
- )
- error.pushbutton("R", 198, 72, 81, 21, 3, "Retry", None).event(
- "EndDialog", "ErrorRetry"
- )
-
- #####################################################################
- # Global "Query Cancel" dialog
- cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, "No", "No", "No")
- cancel.text(
- "Text",
- 48,
- 15,
- 194,
- 30,
- 3,
- "Are you sure you want to cancel [ProductName] installation?",
- )
- # cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None,
- # "py.ico", None, None)
- c = cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
- c.event("EndDialog", "Exit")
-
- c = cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
- c.event("EndDialog", "Return")
-
- #####################################################################
- # Global "Wait for costing" dialog
- costing = Dialog(
- db,
- "WaitForCostingDlg",
- 50,
- 10,
- 260,
- 85,
- modal,
- title,
- "Return",
- "Return",
- "Return",
- )
- costing.text(
- "Text",
- 48,
- 15,
- 194,
- 30,
- 3,
- "Please wait while the installer finishes determining your disk space "
- "requirements.",
- )
- c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None)
- c.event("EndDialog", "Exit")
-
- #####################################################################
- # Preparation dialog: no user input except cancellation
- prep = PyDialog(
- db, "PrepareDlg", x, y, w, h, modeless, title, "Cancel", "Cancel", "Cancel"
- )
- prep.text(
- "Description",
- 15,
- 70,
- 320,
- 40,
- 0x30003,
- "Please wait while the Installer prepares to guide you through the "
- "installation.",
- )
- prep.title("Welcome to the [ProductName] Installer")
- c = prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...")
- c.mapping("ActionText", "Text")
- c = prep.text("ActionData", 15, 135, 320, 30, 0x30003, None)
- c.mapping("ActionData", "Text")
- prep.back("Back", None, active=0)
- prep.next("Next", None, active=0)
- c = prep.cancel("Cancel", None)
- c.event("SpawnDialog", "CancelDlg")
-
- #####################################################################
- # Feature (Python directory) selection
- seldlg = PyDialog(
- db, "SelectFeaturesDlg", x, y, w, h, modal, title, "Next", "Next", "Cancel"
- )
- seldlg.title("Select Python Installations")
-
- seldlg.text(
- "Hint",
- 15,
- 30,
- 300,
- 20,
- 3,
- "Select the Python locations where %s should be installed."
- % self.distribution.get_fullname(),
- )
-
- seldlg.back("< Back", None, active=0)
- c = seldlg.next("Next >", "Cancel")
- order = 1
- c.event("[TARGETDIR]", "[SourceDir]", ordering=order)
- for version in self.versions + [self.other_version]:
- order += 1
- c.event(
- "[TARGETDIR]",
- "[TARGETDIR%s]" % version,
- "FEATURE_SELECTED AND &Python%s=3" % version,
- ordering=order,
- )
- c.event("SpawnWaitDialog", "WaitForCostingDlg", ordering=order + 1)
- c.event("EndDialog", "Return", ordering=order + 2)
- c = seldlg.cancel("Cancel", "Features")
- c.event("SpawnDialog", "CancelDlg")
-
- c = seldlg.control(
- "Features",
- "SelectionTree",
- 15,
- 60,
- 300,
- 120,
- 3,
- "FEATURE",
- None,
- "PathEdit",
- None,
- )
- c.event("[FEATURE_SELECTED]", "1")
- ver = self.other_version
- install_other_cond = "FEATURE_SELECTED AND &Python%s=3" % ver
- dont_install_other_cond = "FEATURE_SELECTED AND &Python%s<>3" % ver
-
- c = seldlg.text(
- "Other", 15, 200, 300, 15, 3, "Provide an alternate Python location"
- )
- c.condition("Enable", install_other_cond)
- c.condition("Show", install_other_cond)
- c.condition("Disable", dont_install_other_cond)
- c.condition("Hide", dont_install_other_cond)
-
- c = seldlg.control(
- "PathEdit",
- "PathEdit",
- 15,
- 215,
- 300,
- 16,
- 1,
- "TARGETDIR" + ver,
- None,
- "Next",
- None,
- )
- c.condition("Enable", install_other_cond)
- c.condition("Show", install_other_cond)
- c.condition("Disable", dont_install_other_cond)
- c.condition("Hide", dont_install_other_cond)
-
- #####################################################################
- # Disk cost
- cost = PyDialog(
- db, "DiskCostDlg", x, y, w, h, modal, title, "OK", "OK", "OK", bitmap=False
- )
- cost.text(
- "Title", 15, 6, 200, 15, 0x30003, r"{\DlgFontBold8}Disk Space Requirements"
- )
- cost.text(
- "Description",
- 20,
- 20,
- 280,
- 20,
- 0x30003,
- "The disk space required for the installation of the selected features.",
- )
- cost.text(
- "Text",
- 20,
- 53,
- 330,
- 60,
- 3,
- "The highlighted volumes (if any) do not have enough disk space "
- "available for the currently selected features. You can either "
- "remove some files from the highlighted volumes, or choose to "
- "install less features onto local drive(s), or select different "
- "destination drive(s).",
- )
- cost.control(
- "VolumeList",
- "VolumeCostList",
- 20,
- 100,
- 330,
- 150,
- 393223,
- None,
- "{120}{70}{70}{70}{70}",
- None,
- None,
- )
- cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return")
-
- #####################################################################
- # WhichUsers Dialog. Only available on NT, and for privileged users.
- # This must be run before FindRelatedProducts, because that will
- # take into account whether the previous installation was per-user
- # or per-machine. We currently don't support going back to this
- # dialog after "Next" was selected; to support this, we would need to
- # find how to reset the ALLUSERS property, and how to re-run
- # FindRelatedProducts.
- # On Windows9x, the ALLUSERS property is ignored on the command line
- # and in the Property table, but installer fails according to the documentation
- # if a dialog attempts to set ALLUSERS.
- whichusers = PyDialog(
- db,
- "WhichUsersDlg",
- x,
- y,
- w,
- h,
- modal,
- title,
- "AdminInstall",
- "Next",
- "Cancel",
- )
- whichusers.title(
- "Select whether to install [ProductName] for all users of this computer."
- )
- # A radio group with two options: allusers, justme
- g = whichusers.radiogroup(
- "AdminInstall", 15, 60, 260, 50, 3, "WhichUsers", "", "Next"
- )
- g.add("ALL", 0, 5, 150, 20, "Install for all users")
- g.add("JUSTME", 0, 25, 150, 20, "Install just for me")
-
- whichusers.back("Back", None, active=0)
-
- c = whichusers.next("Next >", "Cancel")
- c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1)
- c.event("EndDialog", "Return", ordering=2)
-
- c = whichusers.cancel("Cancel", "AdminInstall")
- c.event("SpawnDialog", "CancelDlg")
-
- #####################################################################
- # Installation Progress dialog (modeless)
- progress = PyDialog(
- db,
- "ProgressDlg",
- x,
- y,
- w,
- h,
- modeless,
- title,
- "Cancel",
- "Cancel",
- "Cancel",
- bitmap=False,
- )
- progress.text(
- "Title",
- 20,
- 15,
- 200,
- 15,
- 0x30003,
- r"{\DlgFontBold8}[Progress1] [ProductName]",
- )
- progress.text(
- "Text",
- 35,
- 65,
- 300,
- 30,
- 3,
- "Please wait while the Installer [Progress2] [ProductName]. "
- "This may take several minutes.",
- )
- progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:")
-
- c = progress.text("ActionText", 70, 100, w - 70, 20, 3, "Pondering...")
- c.mapping("ActionText", "Text")
-
- # c=progress.text("ActionData", 35, 140, 300, 20, 3, None)
- # c.mapping("ActionData", "Text")
-
- c = progress.control(
- "ProgressBar",
- "ProgressBar",
- 35,
- 120,
- 300,
- 10,
- 65537,
- None,
- "Progress done",
- None,
- None,
- )
- c.mapping("SetProgress", "Progress")
-
- progress.back("< Back", "Next", active=False)
- progress.next("Next >", "Cancel", active=False)
- progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg")
-
- ###################################################################
- # Maintenance type: repair/uninstall
- maint = PyDialog(
- db, "MaintenanceTypeDlg", x, y, w, h, modal, title, "Next", "Next", "Cancel"
- )
- maint.title("Welcome to the [ProductName] Setup Wizard")
- maint.text(
- "BodyText",
- 15,
- 63,
- 330,
- 42,
- 3,
- "Select whether you want to repair or remove [ProductName].",
- )
- g = maint.radiogroup(
- "RepairRadioGroup",
- 15,
- 108,
- 330,
- 60,
- 3,
- "MaintenanceForm_Action",
- "",
- "Next",
- )
- # g.add("Change", 0, 0, 200, 17, "&Change [ProductName]")
- g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]")
- g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]")
-
- maint.back("< Back", None, active=False)
- c = maint.next("Finish", "Cancel")
- # Change installation: Change progress dialog to "Change", then ask
- # for feature selection
- # c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1)
- # c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2)
-
- # Reinstall: Change progress dialog to "Repair", then invoke reinstall
- # Also set list of reinstalled features to "ALL"
- c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5)
- c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6)
- c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7)
- c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8)
-
- # Uninstall: Change progress to "Remove", then invoke uninstall
- # Also set list of removed features to "ALL"
- c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11)
- c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12)
- c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13)
- c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14)
-
- # Close dialog when maintenance action scheduled
- c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20)
-
- maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg")
-
- def get_installer_filename(self, fullname):
- # Factored out to allow overriding in subclasses
- if self.target_version:
- base_name = "{}.{}-py{}.msi".format(
- fullname,
- self.plat_name,
- self.target_version,
- )
- else:
- base_name = "{}.{}.msi".format(fullname, self.plat_name)
- installer_name = os.path.join(self.dist_dir, base_name)
- return installer_name
diff --git a/setuptools/_distutils/command/bdist_wininst.py b/setuptools/_distutils/command/bdist_wininst.py
deleted file mode 100644
index 02bd7200..00000000
--- a/setuptools/_distutils/command/bdist_wininst.py
+++ /dev/null
@@ -1,418 +0,0 @@
-"""distutils.command.bdist_wininst
-
-Implements the Distutils 'bdist_wininst' command: create a windows installer
-exe-program."""
-
-import os
-import sys
-import warnings
-from distutils.core import Command
-from distutils.util import get_platform
-from distutils.dir_util import remove_tree
-from distutils.errors import DistutilsOptionError, DistutilsPlatformError
-from distutils.sysconfig import get_python_version
-from distutils import log
-
-
-class bdist_wininst(Command):
-
- description = "create an executable installer for MS Windows"
-
- user_options = [
- ('bdist-dir=', None, "temporary directory for creating the distribution"),
- (
- 'plat-name=',
- 'p',
- "platform name to embed in generated filenames "
- "(default: %s)" % get_platform(),
- ),
- (
- 'keep-temp',
- 'k',
- "keep the pseudo-installation tree around after "
- + "creating the distribution archive",
- ),
- (
- 'target-version=',
- None,
- "require a specific python version" + " on the target system",
- ),
- ('no-target-compile', 'c', "do not compile .py to .pyc on the target system"),
- (
- 'no-target-optimize',
- 'o',
- "do not compile .py to .pyo (optimized) " "on the target system",
- ),
- ('dist-dir=', 'd', "directory to put final built distributions in"),
- (
- 'bitmap=',
- 'b',
- "bitmap to use for the installer instead of python-powered logo",
- ),
- (
- 'title=',
- 't',
- "title to display on the installer background instead of default",
- ),
- ('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
- (
- 'install-script=',
- None,
- "basename of installation script to be run after "
- "installation or before deinstallation",
- ),
- (
- 'pre-install-script=',
- None,
- "Fully qualified filename of a script to be run before "
- "any files are installed. This script need not be in the "
- "distribution",
- ),
- (
- 'user-access-control=',
- None,
- "specify Vista's UAC handling - 'none'/default=no "
- "handling, 'auto'=use UAC if target Python installed for "
- "all users, 'force'=always use UAC",
- ),
- ]
-
- boolean_options = [
- 'keep-temp',
- 'no-target-compile',
- 'no-target-optimize',
- 'skip-build',
- ]
-
- # bpo-10945: bdist_wininst requires mbcs encoding only available on Windows
- _unsupported = sys.platform != "win32"
-
- def __init__(self, *args, **kw):
- super().__init__(*args, **kw)
- warnings.warn(
- "bdist_wininst command is deprecated since Python 3.8, "
- "use bdist_wheel (wheel packages) instead",
- DeprecationWarning,
- 2,
- )
-
- def initialize_options(self):
- self.bdist_dir = None
- self.plat_name = None
- self.keep_temp = 0
- self.no_target_compile = 0
- self.no_target_optimize = 0
- self.target_version = None
- self.dist_dir = None
- self.bitmap = None
- self.title = None
- self.skip_build = None
- self.install_script = None
- self.pre_install_script = None
- self.user_access_control = None
-
- def finalize_options(self):
- self.set_undefined_options('bdist', ('skip_build', 'skip_build'))
-
- if self.bdist_dir is None:
- if self.skip_build and self.plat_name:
- # If build is skipped and plat_name is overridden, bdist will
- # not see the correct 'plat_name' - so set that up manually.
- bdist = self.distribution.get_command_obj('bdist')
- bdist.plat_name = self.plat_name
- # next the command will be initialized using that name
- bdist_base = self.get_finalized_command('bdist').bdist_base
- self.bdist_dir = os.path.join(bdist_base, 'wininst')
-
- if not self.target_version:
- self.target_version = ""
-
- if not self.skip_build and self.distribution.has_ext_modules():
- short_version = get_python_version()
- if self.target_version and self.target_version != short_version:
- raise DistutilsOptionError(
- "target version can only be %s, or the '--skip-build'"
- " option must be specified" % (short_version,)
- )
- self.target_version = short_version
-
- self.set_undefined_options(
- 'bdist',
- ('dist_dir', 'dist_dir'),
- ('plat_name', 'plat_name'),
- )
-
- if self.install_script:
- for script in self.distribution.scripts:
- if self.install_script == os.path.basename(script):
- break
- else:
- raise DistutilsOptionError(
- "install_script '%s' not found in scripts" % self.install_script
- )
-
- def run(self):
- if sys.platform != "win32" and (
- self.distribution.has_ext_modules() or self.distribution.has_c_libraries()
- ):
- raise DistutilsPlatformError(
- "distribution contains extensions and/or C libraries; "
- "must be compiled on a Windows 32 platform"
- )
-
- if not self.skip_build:
- self.run_command('build')
-
- install = self.reinitialize_command('install', reinit_subcommands=1)
- install.root = self.bdist_dir
- install.skip_build = self.skip_build
- install.warn_dir = 0
- install.plat_name = self.plat_name
-
- install_lib = self.reinitialize_command('install_lib')
- # we do not want to include pyc or pyo files
- install_lib.compile = 0
- install_lib.optimize = 0
-
- if self.distribution.has_ext_modules():
- # If we are building an installer for a Python version other
- # than the one we are currently running, then we need to ensure
- # our build_lib reflects the other Python version rather than ours.
- # Note that for target_version!=sys.version, we must have skipped the
- # build step, so there is no issue with enforcing the build of this
- # version.
- target_version = self.target_version
- if not target_version:
- assert self.skip_build, "Should have already checked this"
- target_version = '%d.%d' % sys.version_info[:2]
- plat_specifier = ".{}-{}".format(self.plat_name, target_version)
- build = self.get_finalized_command('build')
- build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier)
-
- # Use a custom scheme for the zip-file, because we have to decide
- # at installation time which scheme to use.
- for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
- value = key.upper()
- if key == 'headers':
- value = value + '/Include/$dist_name'
- setattr(install, 'install_' + key, value)
-
- log.info("installing to %s", self.bdist_dir)
- install.ensure_finalized()
-
- # avoid warning of 'install_lib' about installing
- # into a directory not in sys.path
- sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
-
- install.run()
-
- del sys.path[0]
-
- # And make an archive relative to the root of the
- # pseudo-installation tree.
- from tempfile import mktemp
-
- archive_basename = mktemp()
- fullname = self.distribution.get_fullname()
- arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir)
- # create an exe containing the zip-file
- self.create_exe(arcname, fullname, self.bitmap)
- if self.distribution.has_ext_modules():
- pyversion = get_python_version()
- else:
- pyversion = 'any'
- self.distribution.dist_files.append(
- ('bdist_wininst', pyversion, self.get_installer_filename(fullname))
- )
- # remove the zip-file again
- log.debug("removing temporary file '%s'", arcname)
- os.remove(arcname)
-
- if not self.keep_temp:
- remove_tree(self.bdist_dir, dry_run=self.dry_run)
-
- def get_inidata(self):
- # Return data describing the installation.
- lines = []
- metadata = self.distribution.metadata
-
- # Write the [metadata] section.
- lines.append("[metadata]")
-
- # 'info' will be displayed in the installer's dialog box,
- # describing the items to be installed.
- info = (metadata.long_description or '') + '\n'
-
- # Escape newline characters
- def escape(s):
- return s.replace("\n", "\\n")
-
- for name in [
- "author",
- "author_email",
- "description",
- "maintainer",
- "maintainer_email",
- "name",
- "url",
- "version",
- ]:
- data = getattr(metadata, name, "")
- if data:
- info = info + ("\n {}: {}".format(name.capitalize(), escape(data)))
- lines.append("{}={}".format(name, escape(data)))
-
- # The [setup] section contains entries controlling
- # the installer runtime.
- lines.append("\n[Setup]")
- if self.install_script:
- lines.append("install_script=%s" % self.install_script)
- lines.append("info=%s" % escape(info))
- lines.append("target_compile=%d" % (not self.no_target_compile))
- lines.append("target_optimize=%d" % (not self.no_target_optimize))
- if self.target_version:
- lines.append("target_version=%s" % self.target_version)
- if self.user_access_control:
- lines.append("user_access_control=%s" % self.user_access_control)
-
- title = self.title or self.distribution.get_fullname()
- lines.append("title=%s" % escape(title))
- import time
- import distutils
-
- build_info = "Built {} with distutils-{}".format(
- time.ctime(time.time()),
- distutils.__version__,
- )
- lines.append("build_info=%s" % build_info)
- return "\n".join(lines)
-
- def create_exe(self, arcname, fullname, bitmap=None):
- import struct
-
- self.mkpath(self.dist_dir)
-
- cfgdata = self.get_inidata()
-
- installer_name = self.get_installer_filename(fullname)
- self.announce("creating %s" % installer_name)
-
- if bitmap:
- with open(bitmap, "rb") as f:
- bitmapdata = f.read()
- bitmaplen = len(bitmapdata)
- else:
- bitmaplen = 0
-
- with open(installer_name, "wb") as file:
- file.write(self.get_exe_bytes())
- if bitmap:
- file.write(bitmapdata)
-
- # Convert cfgdata from unicode to ascii, mbcs encoded
- if isinstance(cfgdata, str):
- cfgdata = cfgdata.encode("mbcs")
-
- # Append the pre-install script
- cfgdata = cfgdata + b"\0"
- if self.pre_install_script:
- # We need to normalize newlines, so we open in text mode and
- # convert back to bytes. "latin-1" simply avoids any possible
- # failures.
- with open(self.pre_install_script, encoding="latin-1") as script:
- script_data = script.read().encode("latin-1")
- cfgdata = cfgdata + script_data + b"\n\0"
- else:
- # empty pre-install script
- cfgdata = cfgdata + b"\0"
- file.write(cfgdata)
-
- # The 'magic number' 0x1234567B is used to make sure that the
- # binary layout of 'cfgdata' is what the wininst.exe binary
- # expects. If the layout changes, increment that number, make
- # the corresponding changes to the wininst.exe sources, and
- # recompile them.
- header = struct.pack(
- "<iii",
- 0x1234567B, # tag
- len(cfgdata), # length
- bitmaplen, # number of bytes in bitmap
- )
- file.write(header)
- with open(arcname, "rb") as f:
- file.write(f.read())
-
- def get_installer_filename(self, fullname):
- # Factored out to allow overriding in subclasses
- if self.target_version:
- # if we create an installer for a specific python version,
- # it's better to include this in the name
- installer_name = os.path.join(
- self.dist_dir,
- "{}.{}-py{}.exe".format(fullname, self.plat_name, self.target_version),
- )
- else:
- installer_name = os.path.join(
- self.dist_dir, "{}.{}.exe".format(fullname, self.plat_name)
- )
- return installer_name
-
- def get_exe_bytes(self): # noqa: C901
- # If a target-version other than the current version has been
- # specified, then using the MSVC version from *this* build is no good.
- # Without actually finding and executing the target version and parsing
- # its sys.version, we just hard-code our knowledge of old versions.
- # NOTE: Possible alternative is to allow "--target-version" to
- # specify a Python executable rather than a simple version string.
- # We can then execute this program to obtain any info we need, such
- # as the real sys.version string for the build.
- cur_version = get_python_version()
-
- # If the target version is *later* than us, then we assume they
- # use what we use
- # string compares seem wrong, but are what sysconfig.py itself uses
- if self.target_version and self.target_version < cur_version:
- if self.target_version < "2.4":
- bv = '6.0'
- elif self.target_version == "2.4":
- bv = '7.1'
- elif self.target_version == "2.5":
- bv = '8.0'
- elif self.target_version <= "3.2":
- bv = '9.0'
- elif self.target_version <= "3.4":
- bv = '10.0'
- else:
- bv = '14.0'
- else:
- # for current version - use authoritative check.
- try:
- from msvcrt import CRT_ASSEMBLY_VERSION
- except ImportError:
- # cross-building, so assume the latest version
- bv = '14.0'
- else:
- # as far as we know, CRT is binary compatible based on
- # the first field, so assume 'x.0' until proven otherwise
- major = CRT_ASSEMBLY_VERSION.partition('.')[0]
- bv = major + '.0'
-
- # wininst-x.y.exe is in the same directory as this file
- directory = os.path.dirname(__file__)
- # we must use a wininst-x.y.exe built with the same C compiler
- # used for python. XXX What about mingw, borland, and so on?
-
- # if plat_name starts with "win" but is not "win32"
- # we want to strip "win" and leave the rest (e.g. -amd64)
- # for all other cases, we don't want any suffix
- if self.plat_name != 'win32' and self.plat_name[:3] == 'win':
- sfix = self.plat_name[3:]
- else:
- sfix = ''
-
- filename = os.path.join(directory, "wininst-{}{}.exe".format(bv, sfix))
- f = open(filename, "rb")
- try:
- return f.read()
- finally:
- f.close()
diff --git a/setuptools/_distutils/cygwinccompiler.py b/setuptools/_distutils/cygwinccompiler.py
index 2c6dbae8..63910f2a 100644
--- a/setuptools/_distutils/cygwinccompiler.py
+++ b/setuptools/_distutils/cygwinccompiler.py
@@ -6,47 +6,6 @@ the Mingw32CCompiler class which handles the mingw32 port of GCC (same as
cygwin in no-cygwin mode).
"""
-# problems:
-#
-# * if you use a msvc compiled python version (1.5.2)
-# 1. you have to insert a __GNUC__ section in its config.h
-# 2. you have to generate an import library for its dll
-# - create a def-file for python??.dll
-# - create an import library using
-# dlltool --dllname python15.dll --def python15.def \
-# --output-lib libpython15.a
-#
-# see also http://starship.python.net/crew/kernr/mingw32/Notes.html
-#
-# * We put export_symbols in a def-file, and don't use
-# --export-all-symbols because it doesn't worked reliable in some
-# tested configurations. And because other windows compilers also
-# need their symbols specified this no serious problem.
-#
-# tested configurations:
-#
-# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works
-# (after patching python's config.h and for C++ some other include files)
-# see also http://starship.python.net/crew/kernr/mingw32/Notes.html
-# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works
-# (ld doesn't support -shared, so we use dllwrap)
-# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now
-# - its dllwrap doesn't work, there is a bug in binutils 2.10.90
-# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html
-# - using gcc -mdll instead dllwrap doesn't work without -static because
-# it tries to link against dlls instead their import libraries. (If
-# it finds the dll first.)
-# By specifying -static we force ld to link against the import libraries,
-# this is windows standard and there are normally not the necessary symbols
-# in the dlls.
-# *** only the version of June 2000 shows these problems
-# * cygwin gcc 3.2/ld 2.13.90 works
-# (ld supports -shared)
-# * mingw gcc 3.2/ld 2.13 works
-# (ld supports -shared)
-# * llvm-mingw with Clang 11 works
-# (lld supports -shared)
-
import os
import sys
import copy
diff --git a/setuptools/_distutils/tests/test_bdist.py b/setuptools/_distutils/tests/test_bdist.py
index 5b8774e5..af330a06 100644
--- a/setuptools/_distutils/tests/test_bdist.py
+++ b/setuptools/_distutils/tests/test_bdist.py
@@ -1,7 +1,4 @@
"""Tests for distutils.command.bdist."""
-import os
-import warnings
-
from distutils.command.bdist import bdist
from distutils.tests import support
@@ -12,18 +9,16 @@ class TestBuild(support.TempdirManager):
# we can set the format
dist = self.create_dist()[1]
cmd = bdist(dist)
- cmd.formats = ['msi']
+ cmd.formats = ['gztar']
cmd.ensure_finalized()
- assert cmd.formats == ['msi']
+ assert cmd.formats == ['gztar']
# what formats does bdist offer?
formats = [
'bztar',
'gztar',
- 'msi',
'rpm',
'tar',
- 'wininst',
'xztar',
'zip',
'ztar',
@@ -41,17 +36,10 @@ class TestBuild(support.TempdirManager):
names = [
'bdist_dumb',
- 'bdist_wininst',
] # bdist_rpm does not support --skip-build
- if os.name == 'nt':
- names.append('bdist_msi')
for name in names:
- with warnings.catch_warnings():
- warnings.filterwarnings(
- 'ignore', 'bdist_wininst command is deprecated', DeprecationWarning
- )
- subcmd = cmd.get_finalized_command(name)
+ subcmd = cmd.get_finalized_command(name)
if getattr(subcmd, '_unsupported', False):
# command is not supported on this build
continue
diff --git a/setuptools/_distutils/tests/test_bdist_msi.py b/setuptools/_distutils/tests/test_bdist_msi.py
deleted file mode 100644
index f36b3983..00000000
--- a/setuptools/_distutils/tests/test_bdist_msi.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Tests for distutils.command.bdist_msi."""
-import pytest
-
-from distutils.tests import support
-
-from .py38compat import check_warnings
-
-
-pytest.importorskip('msilib')
-
-
-class TestBDistMSI(support.TempdirManager, support.LoggingSilencer):
- def test_minimal(self):
- # minimal test XXX need more tests
- from distutils.command.bdist_msi import bdist_msi
-
- project_dir, dist = self.create_dist()
- with check_warnings(("", DeprecationWarning)):
- cmd = bdist_msi(dist)
- cmd.ensure_finalized()
diff --git a/setuptools/_distutils/tests/test_bdist_wininst.py b/setuptools/_distutils/tests/test_bdist_wininst.py
deleted file mode 100644
index c432d24b..00000000
--- a/setuptools/_distutils/tests/test_bdist_wininst.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Tests for distutils.command.bdist_wininst."""
-import pytest
-
-from .py38compat import check_warnings
-
-from distutils.command.bdist_wininst import bdist_wininst
-from distutils.tests import support
-
-
-@pytest.mark.skipif("platform.machine() == 'ARM64'")
-@pytest.mark.skipif("bdist_wininst._unsupported")
-class TestBuildWinInst(support.TempdirManager, support.LoggingSilencer):
- def test_get_exe_bytes(self):
-
- # issue5731: command was broken on non-windows platforms
- # this test makes sure it works now for every platform
- # let's create a command
- pkg_pth, dist = self.create_dist()
- with check_warnings(("", DeprecationWarning)):
- cmd = bdist_wininst(dist)
- cmd.ensure_finalized()
-
- # let's run the code that finds the right wininst*.exe file
- # and make sure it finds it and returns its content
- # no matter what platform we have
- exe_file = cmd.get_exe_bytes()
- assert len(exe_file) > 10