mysqlx-connector-python/cpydist/bdist_solaris.py (287 lines of code) (raw):

# Copyright (c) 2019, 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 for creating Solaris packages.""" import logging import os import platform import shutil import subprocess import tarfile import time from pathlib import Path try: from setuptools.errors import ExecError except ImportError: ExecError = Exception try: from setuptools.logging import set_threshold except ImportError: set_threshold = None from . import COMMON_USER_OPTIONS, VERSION_EXTRA, VERSION_TEXT, BaseCommand from .bdist import DistBinary as bdist from .utils import write_info_bin, write_info_src SOLARIS_PKGS = {"pure": os.path.join("cpydist", "data", "solaris")} PKGINFO = ( 'PKG="{pkg}"\n' 'NAME="MySQL Connector/Python {ver} {lic}, MySQL driver written in ' 'Python"\n' 'VERSION="{ver}"\n' 'ARCH="all"\n' 'CLASSES="none"\n' 'CATEGORY="application"\n' 'VENDOR="ORACLE Corporation"\n' 'PSTAMP="{tstamp}"\n' 'EMAIL="MySQL Release Engineering <mysql-build@oss.oracle.com>"\n' 'BASEDIR="/"\n' ) class DistSolaris(bdist, BaseCommand): """Create a Solaris distribution.""" platf_n = "-solaris" platf_v = platform.version().split(".")[0] platf_a = "sparc" if platform.processor() == "sparc" else "x86" description = "create a Solaris distribution" user_options = COMMON_USER_OPTIONS + [ ("dist-dir=", "d", "directory to put final built distributions in"), ( "platform=", "p", f"name of the platform in resulting file (default '{platf_n}')", ), ( "platform-version=", "v", f"version of the platform in resulting file (default '{platf_v}')", ), ( "platform-version=", "a", "architecture, i.e. 'sparc' or 'x86' in the resulting file " f"(default '{platf_a}')", ), ( "trans", "t", "transform the package into data stream (default 'False')", ), ] def initialize_options(self): """Initialize the options.""" bdist.initialize_options(self) BaseCommand.initialize_options(self) self.name = self.distribution.get_name() self.version = self.distribution.get_version() self.version_extra = f"-{VERSION_EXTRA}" if VERSION_EXTRA else "" self.keep_temp = None self.create_dmg = False self.dist_dir = None self.started_dir = os.getcwd() self.platform = self.platf_n self.platform_version = self.platf_v self.architecture = self.platf_a self.debug = False self.sun_pkg_name = f"{self.name}-{self.version}{self.version_extra}.pkg" self.dstroot = "dstroot" self.sign = False self.identity = "MySQL Connector/Python" self.trans = False def finalize_options(self): """Finalize the options.""" bdist.finalize_options(self) BaseCommand.finalize_options(self) self.set_undefined_options("bdist", ("dist_dir", "dist_dir")) if self.debug: self.log.setLevel(logging.DEBUG) if set_threshold: # Set setuptools logging level to DEBUG set_threshold(1) def _prepare_pkg_base(self, template_name, data_dir, root=""): """Create and populate the src base directory.""" self.log.info("-> _prepare_pkg_base()") self.log.info(" template_name: %s", template_name) self.log.info(" data_dir: %s", data_dir) self.log.info(" root: %s", root) # copy and create necessary files sun_dist_name = template_name.format(self.name, self.version) self.sun_pkg_name = f"{sun_dist_name}.pkg" self.log.info(" sun_pkg_name: %s", self.sun_pkg_name) sun_path = os.path.join(root, self.dstroot) self.log.info(" sun_path: %s", sun_path) cwd = os.path.join(os.getcwd()) self.log.info("Current directory: %s", cwd) copy_file_src_dst = [] # No special folder for GPL or commercial. Files inside the directory # will determine what it is. data_path = os.path.join( sun_path, "usr", "share", template_name.format(self.name, self.version), ) self.mkpath(data_path) lic = "(GPL)" sun_pkg_info = os.path.join(sun_path, "pkginfo") self.log.info("sun_pkg_info path: %s", sun_pkg_info) with open(sun_pkg_info, "w") as f_pkg_info: f_pkg_info.write( PKGINFO.format( ver=self.version, lic=lic, pkg=self.name, tstamp=time.ctime(), ) ) f_pkg_info.close() data_path = os.path.join( sun_path, "usr", "share", template_name.format(self.name, self.version), ) copy_file_src_dst += [ ( os.path.join(cwd, "README.txt"), os.path.join(data_path, "README.txt"), ), ( os.path.join(cwd, "LICENSE.txt"), os.path.join(data_path, "LICENSE.txt"), ), ( os.path.join(cwd, "CHANGES.txt"), os.path.join(data_path, "CHANGES.txt"), ), ( os.path.join(cwd, "docs", "INFO_SRC"), os.path.join(data_path, "INFO_SRC"), ), ( os.path.join(cwd, "docs", "INFO_BIN"), os.path.join(data_path, "INFO_BIN"), ), ( os.path.join(cwd, "README.rst"), os.path.join(data_path, "README.rst"), ), ( os.path.join(cwd, "CONTRIBUTING.md"), os.path.join(data_path, "CONTRIBUTING.md"), ), ( os.path.join(cwd, "SECURITY.md"), os.path.join(data_path, "SECURITY.md"), ), ] for src, dst in copy_file_src_dst: shutil.copyfile(src, dst) def _create_pkg(self, template_name, dmg=False, sign=False, root="", identity=""): """Create the Solaris package using the OS dependent commands.""" self.log.info("-> _create_pkg()") self.log.info("template_name: %s", template_name) self.log.info("identity: %s", identity) sun_dist_name = template_name.format(self.name, self.version) self.sun_pkg_name = f"{sun_dist_name}.pkg" sun_pkg_contents = os.path.join(self.sun_pkg_name, "Contents") self.log.info("sun_dist_name: %s", sun_dist_name) self.log.info("sun_pkg_name: %s", self.sun_pkg_name) self.log.info("sun_pkg_contents: %s", sun_pkg_contents) sun_path = os.path.join(root, self.dstroot) os.chdir(sun_path) self.log.info("Root directory for Prototype: %s", os.getcwd()) # Creating a Prototype file, this contains a table of contents of the # Package, that is suitable to be used for the package creation tool. self.log.info( f"Creating Prototype file on {self.dstroot} to describe files to install" ) prototype_path = "Prototype" proto_tmp = "Prototype_temp" with open(proto_tmp, "w") as f_out: cmd = ["pkgproto", "."] pkgp_p = subprocess.Popen(cmd, shell=False, stdout=f_out, stderr=f_out) res = pkgp_p.wait() if res != 0: self.log.error(f"pkgproto command failed with: {res}") raise ExecError(f"pkgproto command failed with: {res}") f_out.flush() # log Prototype contents self.log.info("/n>> Prototype_temp contents >>/n") with open(proto_tmp, "r") as f_in: self.log.info(f_in.readlines()) self.log.info("/n<< Prototype_temp contents end <</n") # Fix Prototype file, insert pkginfo and remove Prototype self.log.info("Fixing folder permissions on Prototype contents") with open(prototype_path, "w") as f_out: with open(proto_tmp, "r") as f_in: # Add pkginfo entry at beginning of the Prototype file f_out.write("i pkginfo\n") f_out.flush() for line in f_in: if line.startswith("f none Prototype"): continue elif line.startswith("f none pkginfo"): continue elif line.startswith("d"): tokeep = line.split(" ")[:-3] tokeep.extend(["?", "?", "?", "\n"]) f_out.write(" ".join(tokeep)) elif line.startswith("f"): tokeep = line.split(" ")[:-2] tokeep.extend(["root", "bin", "\n"]) f_out.write(" ".join(tokeep)) else: f_out.write(line) f_out.flush() # log Prototype contents self.log.info("/n>> Prototype contents >>/n") with open(prototype_path, "r") as f_in: self.log.info(f_in.readlines()) self.log.info("/n<< Prototype contents end <</n") # Create Solaris package running the package creation command pkgmk self.log.info("Creating package with pkgmk") self.log.info("Root directory for pkgmk: %s", os.getcwd()) self.spawn(["pkgmk", "-o", "-r", ".", "-d", "../", "-f", prototype_path]) os.chdir("../") if self.debug: self.log.info("current directory: %s", os.getcwd()) # gzip the package folder self.log.info("creating tarball") archive_name = f"{self.sun_pkg_name}.tar.gz" self.log.info("Creating tar archive '%s'", archive_name) with tarfile.open(archive_name, "w|gz") as tar: tar.add(self.name) if self.trans: self.log.info("Transforming package into data stream with pkgtrans") self.log.info("Current directory: %s", os.getcwd()) self.spawn( [ "pkgtrans", "-s", os.getcwd(), os.path.join(os.getcwd(), self.sun_pkg_name), self.name, ] ) for base, _, files in os.walk(os.getcwd()): for filename in files: if filename.endswith(".gz") or filename.endswith(".pkg"): new_name = filename.replace( f"{self.version}", f"{self.version}{self.version_extra}{self.platform}" f"{self.platform_version}-{self.architecture}", ) file_path = os.path.join(base, filename) file_dest = os.path.join(self.started_dir, self.dist_dir, new_name) shutil.copyfile(file_path, file_dest) break def run(self): """Run the command.""" self.mkpath(self.dist_dir) self.debug = self.verbose self.log.info("Generating INFO_SRC and INFO_BIN files") write_info_src(VERSION_TEXT) write_info_bin() cmd_build = self.get_finalized_command("build") build_base = os.path.abspath(cmd_build.build_base) metadata_name = self.distribution.metadata.name data_dir = SOLARIS_PKGS["pure"] sun_root = os.path.join(build_base, "sun_pure") cmd_install = self.reinitialize_command("install", reinit_subcommands=1) cmd_install.byte_code_only = self.byte_code_only cmd_install.compile = self.byte_code_only cmd_install.distribution.metadata.name = metadata_name cmd_install.with_mysql_capi = None cmd_install.root = os.path.join(sun_root, self.dstroot) cmd_install.ensure_finalized() cmd_install.run() template_name = ["{}"] if self.label: template_name.append(f"-{self.label}") template_name.append("-{}") self._prepare_pkg_base("".join(template_name), data_dir, root=sun_root) self._create_pkg( "".join(template_name), dmg=self.create_dmg, root=sun_root, sign=self.sign, identity=self.identity, ) os.chdir(self.started_dir) self.remove_temp()