mysqlx-connector-python/cpydist/bdist.py (142 lines of code) (raw):
# Copyright (c) 2020, 2024, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0, as
# published by the Free Software Foundation.
#
# This program is designed to work with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms,
# as designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an
# additional permission to link the program and your derivative works
# with the separately licensed software that they have either included with
# the program or referenced in the documentation.
#
# Without limiting anything contained in the foregoing, this file,
# which is part of MySQL Connector/Python, is also subject to the
# Universal FOSS Exception, version 1.0, a copy of which can be found at
# http://oss.oracle.com/licenses/universal-foss-exception.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""Implements the Distutils command 'bdist'.
Creates a binary distribution.
"""
import logging
import os
import shutil
from pathlib import Path
from sysconfig import get_platform, get_python_version
try:
from setuptools.logging import set_threshold
except ImportError:
set_threshold = None
from . import COMMON_USER_OPTIONS, EDITION, LOGGER, VERSION_TEXT, Command
from .utils import add_docs, write_info_bin, write_info_src
class DistBinary(Command):
"""Create a generic binary distribution.
DistBinary is meant to replace distutils.bdist.
"""
description = "create a built (binary) distribution"
user_options = COMMON_USER_OPTIONS + [
("bdist-base=", "b", "temporary directory for creating built distributions"),
(
"plat-name=",
"p",
"platform name to embed in generated filenames "
"(default: %s)" % get_platform(),
),
(
"bdist-dir=",
"d",
"temporary directory for creating the distribution",
),
(
"dist-dir=",
"d",
"directory to put final built distributions in " "[default: dist]",
),
(
"owner=",
"u",
"Owner name used when creating a tar file" " [default: current user]",
),
(
"group=",
"g",
"Group name used when creating a tar file" " [default: current group]",
),
]
boolean_options = ["debug", "byte-code-only", "keep-temp"]
log = LOGGER
def initialize_options(self):
"""Initialize the options."""
self.bdist_dir = None
self.bdist_base = None
self.dist_dir = None
self.plat_name = None
self.skip_build = 0
self.group = None
self.owner = None
self.byte_code_only = False
self.label = None
self.edition = EDITION
self.debug = False
self.keep_temp = False
def finalize_options(self):
"""Finalize the options."""
if self.plat_name is None:
self.plat_name = self.get_finalized_command("build").plat_name
if self.bdist_base is None:
build_base = self.get_finalized_command("build").build_base
self.bdist_base = os.path.join(build_base, f"bdist.{self.plat_name}")
if self.dist_dir is None:
self.dist_dir = "dist"
if self.bdist_dir is None:
self.bdist_dir = os.path.join(self.dist_dir, f"bdist.{self.plat_name}")
if self.debug:
self.log.setLevel(logging.DEBUG)
if set_threshold:
# Set setuptools logging level to DEBUG
set_threshold(1)
def _get_fullname():
label = f"-{self.label}" if self.label else ""
python_version = f"-py{get_python_version()}" if self.byte_code_only else ""
name = self.distribution.get_name()
version = self.distribution.get_version()
edition = self.edition or ""
return f"{name}{label}-{version}{edition}{python_version}"
self.distribution.get_fullname = _get_fullname
def _remove_sources(self):
"""Remove Python source files from the build directory."""
for base, _, files in os.walk(self.bdist_dir):
for filename in files:
if filename.endswith(".py"):
filepath = os.path.join(base, filename)
self.log.info("Removing source '%s'", filepath)
os.unlink(filepath)
def _copy_from_pycache(self, start_dir):
"""Copy .py files from __pycache__."""
for base, _, files in os.walk(start_dir):
for filename in files:
if filename.endswith(".pyc"):
filepath = os.path.join(base, filename)
new_name = f"{filename.split('.')[0]}.pyc"
os.rename(filepath, os.path.join(base, "..", new_name))
for base, _, files in os.walk(start_dir):
if base.endswith("__pycache__"):
os.rmdir(base)
def run(self):
"""Run the command."""
self.log.info("Installing library code to %s", self.bdist_dir)
self.log.info("Generating INFO_SRC and INFO_BIN files")
write_info_src(VERSION_TEXT)
write_info_bin()
dist_name = self.distribution.get_fullname()
self.dist_target = os.path.join(self.dist_dir, dist_name)
self.log.info("Distribution will be available as '%s'", self.dist_target)
# build command: just to get the build_base
cmdbuild = self.get_finalized_command("build")
self.build_base = cmdbuild.build_base
# install command
install = self.reinitialize_command("install_lib", reinit_subcommands=1)
install.compile = False
install.warn_dir = 0
install.install_dir = self.bdist_dir
self.log.info("Installing to %s", self.bdist_dir)
self.run_command("install_lib")
# install_egg_info command
cmd_egginfo = self.get_finalized_command("install_egg_info")
cmd_egginfo.install_dir = self.bdist_dir
self.run_command("install_egg_info")
installed_files = install.get_outputs()
# compile and remove sources
if self.byte_code_only:
install.compile = True
install.byte_compile(installed_files)
self._remove_sources()
if get_python_version().startswith("3"):
self.log.info("Copying byte code from __pycache__")
self._copy_from_pycache(os.path.join(self.bdist_dir, "mysqlx"))
# create distribution
info_files = [
("README.txt", "README.txt"),
("LICENSE.txt", "LICENSE.txt"),
("README.rst", "README.rst"),
("CONTRIBUTING.md", "CONTRIBUTING.md"),
("SECURITY.md", "SECURITY.md"),
("docs/INFO_SRC", "INFO_SRC"),
("docs/INFO_BIN", "INFO_BIN"),
]
shutil.copytree(self.bdist_dir, self.dist_target, dirs_exist_ok=True)
Path(self.dist_target).mkdir(parents=True, exist_ok=True)
for src, dst in info_files:
if dst is None:
shutil.copyfile(src, self.dist_target)
else:
shutil.copyfile(src, os.path.join(self.dist_target, dst))
add_docs(os.path.join(self.dist_target, "docs"))
if not self.keep_temp:
shutil.rmtree(self.build_base)