VirtualBox

Changeset 103028 in vbox for trunk/src/VBox/Installer


Ignore:
Timestamp:
Jan 24, 2024 3:53:59 PM (12 months ago)
Author:
vboxsync
Message:

Main/Python: Big revamp to modernize our vboxapi Python package to now use a so-called src-layout, which also can be used with pip directly. Also added compatibility w/ Python 3.12 where distutils are not shipped anymore. We also now do have automatic linting for our code, which hopefully should improve quality in this area. Moved some Python-related files into an own sub folder so that it's more clear to which these belong to. The "sdk/installer" directories also have an own "python" sub directory where the stuff resides now. The Windows installer also uses "sdk/installer" instead of "sdk/install", to match the other platforms. bugref:10579

Location:
trunk/src/VBox/Installer
Files:
1 added
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/Config.kmk

    r102342 r103028  
    5656        sdk/bindings/xpcom/python/xpcom/server/policy.py
    5757 VBOXINST_SDK_INSTALLER_PYTHON_FILES = \
    58         sdk/installer/vboxapisetup.py \
    59         sdk/installer/vboxapi/__init__.py \
    60         sdk/installer/vboxapi/VirtualBox_constants.py
     58        sdk/installer/python/vboxapisetup.py \
     59        sdk/installer/python/vboxapi/__init__.py \
     60        sdk/installer/python/vboxapi/VirtualBox_constants.py
    6161endif
    6262
  • trunk/src/VBox/Installer/common/Config.kmk

    r102983 r103028  
    11# $Id$
    22## @file
    3 # kBuild Configuration file for VBoxShell.
     3# kBuild Configuration file for common installer parts.
    44#
    55
     
    2626#
    2727
    28 VBOX_VBOXSHELL_CONFIG_KMK_INCLUDED = 1
     28VBOX_INSTALLER_COMMON_CONFIG_KMK_INCLUDED = 1
    2929
    3030# Include the top-level configure file.
     
    3636# Globals
    3737#
    38 VBOX_PATH_VBOXSHELL_SRC := $(PATH_ROOT)/src/VBox/Frontends/VBoxShell
     38VBOX_PATH_INSTALLER_COMMON_SRC := $(PATH_ROOT)/src/VBox/Installer/common
    3939
    4040#
    4141# List of python sources that should be linted.
    4242#
    43 VBOX_VBOXSHELL_PYTHON_SOURCES    :=
    44 VBOX_VBOXSHELL_PYLINT_TARGETS    :=
     43VBOX_INSTALLER_COMMON_PYTHON_SOURCES :=
     44VBOX_INSTALLER_COMMON_PYLINT_TARGETS :=
    4545
    4646ifdef VBOX_WITH_PYLINT
     
    5151# Process python sources.
    5252#
    53 if1of ($(KBUILD_TARGET), win os2)
    54  VBOX_PYTHONPATH_VBOXSHELL = $(PYTHONPATH);$(VBOX_PATH_VBOXSHELL_SRC)
    55 else
    56  VBOX_PYTHONPATH_VBOXSHELL = $(PYTHONPATH):$(VBOX_PATH_VBOXSHELL_SRC)
    57 endif
     53VBOX_PYTHONPATH_INSTALLER_COMMON = $(PYTHONPATH):$(VBOX_PATH_INSTALLER_COMMON_SRC)
    5854BLDDIRS += $(PATH_TARGET)/pylint
    5955
    60 define def_vbox_vboxshell_py_check
     56define def_vbox_installer_common_py_check
    6157 $(eval name:=$(basename $(notdir $(py))))
    6258
     
    6662 ifdef VBOX_WITH_PYLINT
    6763        $(QUIET2)$(call MSG_L1,Subjecting $(py) to pylint...)
    68         $(QUIET)$(REDIRECT) -C "$(dir $(py))" -E LC_ALL=C -E PYTHONPATH="$(VBOX_PYTHONPATH_VBOXSHELL)" -- \
    69                 $(VBOX_PYLINT) --rcfile=$(VBOX_PATH_VBOXSHELL_SRC)/pylintrc $$(VBOX_PYLINT_FLAGS) $$($(py)_VBOX_PYLINT_FLAGS) ./$(notdir $(py))
     64        $(QUIET)$(REDIRECT) -C "$(dir $(py))" -E LC_ALL=C -E PYTHONPATH="$(VBOX_PYTHONPATH_INSTALLER_COMMON)" -- \
     65                $(VBOX_PYLINT) --rcfile=$(VBOX_PATH_INSTALLER_COMMON_SRC)/pylintrc $$(VBOX_PYLINT_FLAGS) $$($(py)_VBOX_PYLINT_FLAGS) ./$(notdir $(py))
    7066 endif
    7167        $(QUIET)$(APPEND) -t "$(PATH_TARGET)/pylint/$(name).o"
    7268 TESTING += $(name)-py-phony.o
    73  VBOX_VBOXSHELL_PYLINT_TARGETS    += $(PATH_TARGET)/pylint/$(name).o
    74 endef # def_vbox_vboxshell_py_check
     69 VBOX_INSTALLER_COMMON_PYLINT_TARGETS    += $(PATH_TARGET)/pylint/$(name).o
     70endef # def_vbox_installer_common_py_check
    7571
    7672
    77 define def_vbox_vboxshell_process_python_sources
     73define def_vbox_installer_common_process_python_sources
    7874 if $(words $(_SUB_MAKEFILE_STACK)) <= 0 || "$1" == "FORCE"
    79   $(foreach py, $(VBOX_VBOXSHELL_PYTHON_SOURCES), $(eval $(def_vbox_vboxshell_py_check)))
     75  $(foreach py, $(VBOX_INSTALLER_COMMON_PYTHON_SOURCES), $(eval $(def_vbox_installer_common_py_check)))
    8076 endif
    8177endef
  • trunk/src/VBox/Installer/common/Makefile.kmk

    r98429 r103028  
    3737ifdef VBOX_WITH_PYTHON
    3838
    39  INSTALLS += VBox-python-glue-installer
     39 INSTALLS += VBox-python-glue-vboxapisetup
    4040
    41  VBox-python-glue-installer_INST = $(INST_SDK)installer/
    42  VBox-python-glue-installer_MODE = a+r,u+w
    43  VBox-python-glue-installer_SOURCES = vboxapisetup.py
     41 VBox-python-glue-vboxapisetup_INST = $(INST_SDK)installer/python/vboxapi/
     42 VBox-python-glue-vboxapisetup_MODE = a+r,u+w
     43 VBox-python-glue-vboxapisetup_SOURCES = vboxapisetup.py=>setup.py
     44
     45 INSTALLS += VBox-python-glue-vboxapisetup-stub
     46
     47 VBox-python-glue-vboxapisetup-stub_INST = $(INST_SDK)installer/python/
     48 VBox-python-glue-vboxapisetup-stub_MODE = a+r,u+w
     49 VBox-python-glue-vboxapisetup-stub_SOURCES = vboxapisetup-stub.py=>vboxapisetup.py
     50
     51 #
     52 # Automatically lint common installer Python stuff.
     53 #
     54 if defined(VBOX_WITH_PYLINT) && !defined(VBOX_WITHOUT_AUTO_PYLINT)
     55  OTHERS      += $(PATH_TARGET)/pylintInstallerCommon.run
     56  OTHER_CLEAN += $(PATH_TARGET)/pylintInstallerCommon.run
     57  $(PATH_TARGET)/pylintInstallerCommon.run: \
     58        ${PATH_SUB_CURRENT}/vboxapisetup.py ${PATH_SUB_CURRENT}/vboxapisetup-stub.py
     59        $(QUIET)$(APPEND) -t "$@"
     60 endif
     61
     62 VBOX_INSTALLER_COMMON_PYTHON_SOURCES := $(wildcard $(PATH_SUB_CURRENT)/*.py)
     63
     64 $(evalcall def_vbox_installer_common_process_python_sources,FORCE)
    4465
    4566endif # VBOX_WITH_PYTHON
    4667
    4768include $(FILE_KBUILD_SUB_FOOTER)
    48 
  • trunk/src/VBox/Installer/common/vboxapisetup.py

    r102849 r103028  
    3030"""
    3131
    32 import os,sys
    33 from distutils.core import setup
    34 
    35 def cleanupComCache():
     32#
     33# For "modern" Python packages setuptools only is one of many ways
     34# for installing a package on a system and acts as a pure build backend now.
     35# Using a build backend is controlled by the accompanied pyproject.toml file.
     36#
     37# See: https://packaging.python.org/en/latest/discussions/setup-py-deprecated/#setup-py-deprecated
     38#
     39# PEP 518 [1] introduced pyproject.toml.
     40# PEP 632 [2], starting with Python 3.10, the distutils module is marked as being deprecated.
     41# Python 3.12 does not ship with distutils anymore, but we have to still support Python < 3.12.
     42#
     43# [1] https://peps.python.org/pep-0518/
     44# [2] https://peps.python.org/pep-0632/
     45
     46import atexit
     47import io
     48import os
     49import platform
     50import sys
     51
     52g_fVerbose = True
     53
     54def cleanupWinComCacheDir(sPath):
     55    """
     56    Cleans up a Windows COM cache directory by deleting it.
     57    """
     58    if not sPath:
     59        return
    3660    import shutil
    37     from distutils.sysconfig import get_python_lib
    38     comCache1 = os.path.join(get_python_lib(), 'win32com', 'gen_py')
    39     comCache2 = os.path.join(os.environ.get("TEMP", "c:\\tmp"), 'gen_py')
    40     print("Cleaning COM cache at",comCache1,"and",comCache2)
    41     shutil.rmtree(comCache1, True)
    42     shutil.rmtree(comCache2, True)
    43 
    44 def patchWith(file,install,sdk):
    45     newFile=file + ".new"
    46     install=install.replace("\\", "\\\\")
    47     try:
    48         os.remove(newFile)
    49     except:
     61    sDirCache = os.path.join(sPath, 'win32com', 'gen_py')
     62    print("Cleaning COM cache at '%s'" % (sDirCache))
     63    shutil.rmtree(sDirCache, True)
     64
     65def cleanupWinComCache():
     66    """
     67    Cleans up various Windows COM cache directories by deleting them.
     68    """
     69    if sys.version_info >= (3, 2): # Since Python 3.2 we use the site module.
     70        import site
     71        for sSiteDir in site.getsitepackages():
     72            cleanupWinComCacheDir(sSiteDir)
     73    else:
     74        from distutils.sysconfig import get_python_lib # pylint: disable=deprecated-module
     75        cleanupWinComCacheDir(get_python_lib())
     76
     77    # @todo r=andy Do still need/want this? Was there forever. Probably a leftover.
     78    sDirTemp = os.path.join(os.environ.get("TEMP", "c:\\tmp"), 'gen_py')
     79    cleanupWinComCacheDir(sDirTemp)
     80
     81def patchWith(sFile, sVBoxInstallPath, sVBoxSdkPath):
     82    """
     83    Patches a given file with the VirtualBox install path + SDK path.
     84    """
     85    sFileTemp = sFile + ".new"
     86    sVBoxInstallPath = sVBoxInstallPath.replace("\\", "\\\\")
     87    try:
     88        os.remove(sFileTemp)
     89    except Exception as _:
    5090        pass
    51     oldF = open(file, 'r')
    52     newF = open(newFile, 'w')
    53     for line in oldF:
    54         line = line.replace("%VBOX_INSTALL_PATH%", install)
    55         line = line.replace("%VBOX_SDK_PATH%", sdk)
    56         newF.write(line)
    57     newF.close()
    58     oldF.close()
    59     try:
    60         os.remove(file)
    61     except:
     91    # Note: We need io.open() to specify the file encoding on Python <= 2.7.
     92    try:
     93        with io.open(sFile, 'r', encoding='utf-8') as fileSrc:
     94            with io.open(sFileTemp, 'w', encoding='utf-8') as fileDst:
     95                for line in fileSrc:
     96                    line = line.replace("%VBOX_INSTALL_PATH%", sVBoxInstallPath)
     97                    line = line.replace("%VBOX_SDK_PATH%", sVBoxSdkPath)
     98                    fileDst.write(line)
     99                fileDst.close()
     100            fileSrc.close()
     101    except IOError as exc:
     102        print("ERROR: Opening VirtualBox Python source file '%s' failed: %s" % (sFile, exc))
     103        return False
     104    try:
     105        os.remove(sFile)
     106    except Exception as _:
    62107        pass
    63     os.rename(newFile, file)
    64 
    65 # See http://docs.python.org/distutils/index.html
    66 def main(argv):
    67     vboxDest = os.environ.get("VBOX_MSI_INSTALL_PATH", None)
    68     if vboxDest is None:
    69         vboxDest = os.environ.get('VBOX_INSTALL_PATH', None)
    70         if vboxDest is None:
    71             raise Exception("No VBOX_INSTALL_PATH defined, exiting")
    72 
    73     vboxVersion = os.environ.get("VBOX_VERSION", None)
    74     if vboxVersion is None:
     108    os.rename(sFileTemp, sFile)
     109    return True
     110
     111def testVBoxAPI():
     112    """
     113    Performs various VirtualBox API tests.
     114    """
     115
     116    # Give the user a hint where we gonna install stuff into.
     117    if  g_fVerbose \
     118    and sys.version_info.major >= 3:
     119        import site
     120        print("Global site packages directories are:")
     121        for sPath in site.getsitepackages():
     122            print("\t%s" % (sPath))
     123        print("User site packages directories are:")
     124        print("\t%s" % (site.getusersitepackages()))
     125        print("Module search path is:")
     126        for sPath in sys.path:
     127            print("\t%s" % (sPath))
     128
     129    #
     130    # Test using the just installed VBox API module by calling some (simpler) APIs
     131    # where now kernel drivers are other fancy stuff is needed.
     132    #
     133    try:
     134        from vboxapi import VirtualBoxManager
     135        oVBoxMgr = VirtualBoxManager()
     136        oVBox    = oVBoxMgr.getVirtualBox()
     137        oHost    = oVBox.host
     138        if oHost.architecture not in (oVBoxMgr.constants.PlatformArchitecture_x86, \
     139                                      oVBoxMgr.constants.PlatformArchitecture_ARM):
     140            raise Exception('Host platform invalid!')
     141        print("Testing VirtualBox Python bindings successful: Detected VirtualBox %s (%d)" % (oVBox.version, oHost.architecture))
     142        _ = oVBox.getMachines()
     143        oVBoxMgr.deinit()
     144        del oVBoxMgr
     145    except ImportError as exc:
     146        print("ERROR: Testing VirtualBox Python bindings failed: %s" % (exc))
     147        return False
     148
     149    print("Installation of VirtualBox Python bindings for Python %d.%d successful." \
     150          % (sys.version_info.major, sys.version_info.minor))
     151    return True
     152
     153def findModulePathHelper(sModule = 'vboxapi', aDir = sys.path):
     154    """
     155    Helper function for findModulePath.
     156
     157    Returns the path found, or None if not found.
     158    """
     159    for sPath in aDir:
     160        if g_fVerbose:
     161            print('Searching for "%s" in path "%s" ...' % (sModule, sPath))
     162        if os.path.isdir(sPath):
     163            aDirEntries = os.listdir(sPath)
     164            if g_fVerbose:
     165                print(aDirEntries)
     166            if sModule in aDirEntries:
     167                return os.path.join(sPath, sModule)
     168    return None
     169
     170def findModulePath(sModule = 'vboxapi'):
     171    """
     172    Finds a module in the system path.
     173
     174    Returns the path found, or None if not found.
     175    """
     176    sPath = findModulePathHelper(sModule)
     177    if not sPath:
     178        try:
     179            import site # Might not available everywhere.
     180            sPath = findModulePathHelper(sModule, site.getsitepackages())
     181        except:
     182            pass
     183    return sPath
     184
     185try:
     186    from distutils.command.install import install # Only for < Python 3.12.
     187except:
     188    pass
     189
     190class setupInstallClass(install):
     191    """
     192    Class which overrides the "install" command of the setup so that we can
     193    run post-install actions.
     194    """
     195
     196    def run(self):
     197        def _post_install():
     198            if findModulePath():
     199                testVBoxAPI()
     200        atexit.register(_post_install)
     201        install.run(self)
     202
     203def main():
     204    """
     205    Main function for the setup script.
     206    """
     207
     208    print("Installing VirtualBox bindings for Python %d.%d ..." % (sys.version_info.major, sys.version_info.minor))
     209
     210    # Deprecation warning for older Python stuff (< Python 3.x).
     211    if sys.version_info.major < 3:
     212        print("\nWarning: Running VirtualBox with Python %d.%d is marked as being deprecated.\n" \
     213              "Please upgrade your Python installation to avoid breakage.\n" \
     214              % (sys.version_info.major, sys.version_info.minor))
     215
     216    sVBoxInstallPath = os.environ.get("VBOX_MSI_INSTALL_PATH", None)
     217    if sVBoxInstallPath is None:
     218        sVBoxInstallPath = os.environ.get('VBOX_INSTALL_PATH', None)
     219        if sVBoxInstallPath is None:
     220            print("No VBOX_INSTALL_PATH defined, exiting")
     221            return 1
     222
     223    sVBoxVersion = os.environ.get("VBOX_VERSION", None)
     224    if sVBoxVersion is None:
    75225        # Should we use VBox version for binding module versioning?
    76         vboxVersion = "1.0"
    77 
    78     import platform
     226        sVBoxVersion = "1.0"
     227
     228    if g_fVerbose:
     229        print("VirtualBox installation directory is: %s" % (sVBoxInstallPath))
    79230
    80231    if platform.system() == 'Windows':
    81         cleanupComCache()
     232        cleanupWinComCache()
     233
     234    # Make sure that we always are in the directory where this script resides.
     235    # Otherwise installing packages below won't work.
     236    sCurDir = os.path.dirname(os.path.abspath(__file__))
     237    if g_fVerbose:
     238        print("Current directory is: %s" % (sCurDir))
     239    try:
     240        os.chdir(sCurDir)
     241    except OSError as exc:
     242        print("Changing to current directory failed: %s" % (exc))
    82243
    83244    # Darwin: Patched before installation. Modifying bundle is not allowed, breaks signing and upsets gatekeeper.
    84245    if platform.system() != 'Darwin':
    85         vboxSdkDest = os.path.join(vboxDest, "sdk")
    86         patchWith(os.path.join(os.path.dirname(sys.argv[0]), 'vboxapi', '__init__.py'), vboxDest, vboxSdkDest)
    87 
    88     setup(name='vboxapi',
    89           version=vboxVersion,
    90           description='Python interface to VirtualBox',
    91           author='Oracle Corp.',
    92           author_email='[email protected]',
    93           url='https://www.virtualbox.org',
    94           packages=['vboxapi']
    95           )
     246        # @todo r=andy This *will* break the script if VirtualBox installation files will be moved.
     247        #              Better would be patching the *installed* module instead of the original module.
     248        sVBoxSdkPath = os.path.join(sVBoxInstallPath, "sdk")
     249        fRc = patchWith(os.path.join(sCurDir, 'src', 'vboxapi', '__init__.py'), \
     250                        sVBoxInstallPath, sVBoxSdkPath)
     251        if not fRc:
     252            return 1
     253
     254    try:
     255        #
     256        # Detect which installation method is being used.
     257        #
     258        # This is a bit messy due the fact that we want to support a broad range of older and newer
     259        # Python versions, along with distributions which maintain their own Python packages (e.g. newer Ubuntus).
     260        #
     261        fInvokeSetupTools = False
     262        if sys.version_info >= (3, 12): # Since Python 3.12 there are no distutils anymore. See PEP632.
     263            try:
     264                from setuptools import setup
     265            except ImportError:
     266                print("ERROR: setuptools package not installed, can't continue. Exiting.")
     267                return 1
     268            setup(cmdclass={"install": setupInstallClass})
     269        else:
     270            if sys.version_info >= (3, 3): # Starting with Python 3.3 we use pyproject.toml by using setup().
     271                try:
     272                    from distutils.core import setup # pylint: disable=deprecated-module
     273                    setup(cmdclass={"install": setupInstallClass})
     274                except ImportError:
     275                    print("distutils[.core] package not installed/available, falling back to legacy setuptools ...")
     276                    fInvokeSetupTools = True # Invoke setuptools as a last resort.
     277            else: # Python 2.7.x + Python < 3.6 legacy cruft.
     278                fInvokeSetupTools = True
     279
     280            if fInvokeSetupTools:
     281                if g_fVerbose:
     282                    print("Invoking setuptools directly ...")
     283                setupTool = setup(name='vboxapi',
     284                            version=sVBoxVersion,
     285                            description='Python interface to VirtualBox',
     286                            author='Oracle Corp.',
     287                            author_email='[email protected]',
     288                            url='https://www.virtualbox.org',
     289                            package_dir={'': 'src'},
     290                            packages=['vboxapi'])
     291                if setupTool:
     292                    sPathInstalled = setupTool.command_obj['install'].install_lib
     293                    if sPathInstalled not in sys.path:
     294                        print("\nWARNING: Installation path is not in current module search path!")
     295                        print("         This might happen on OSes / distributions which only maintain packages by")
     296                        print("         a vendor-specific method.")
     297                        print("Hints:")
     298                        print("- Check how the distribution handles user-installable Python packages.")
     299                        print("- Using setuptools directly might be deprecated on the distribution.")
     300                        print("- Using \"pip install ./vboxapi\" within a virtual environment (virtualenv)")
     301                        print("  might fix this.\n")
     302                        sys.path.append(sPathInstalled)
     303
     304                print("Installed to: %s" % (sPathInstalled))
     305
     306    except RuntimeError as exc:
     307        print("ERROR: Installation of VirtualBox Python bindings failed: %s" % (exc))
     308        return 1
     309
     310    if  fInvokeSetupTools \
     311    and not testVBoxAPI():
     312        return 1
     313    return 0
    96314
    97315if __name__ == '__main__':
    98     main(sys.argv)
     316    sys.exit(main())
  • trunk/src/VBox/Installer/darwin/Makefile.kmk

    r101552 r103028  
    721721                        $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk \
    722722                        $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk/installer \
    723                         $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk/installer/vboxapi \
     723                        $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk/installer/python/vboxapi \
    724724                        $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk/bindings/ \
    725725                        $(VBOX_PATH_VBOX_APP_TMP)/Contents/MacOS/sdk/bindings/xpcom \
  • trunk/src/VBox/Installer/darwin/VirtualBox/postflight

    r98103 r103028  
    3434# Install the Python bindings
    3535#
     36## @todo r=andy Merge this code with linux/routines.sh!
     37#
    3638VBOX_INSTALL_PATH=/Applications/VirtualBox.app/Contents/MacOS
    37 PYTHON="python python2.3 python2.5 python2.6 python2.7"
    38 if [ -e "${VBOX_INSTALL_PATH}/sdk/installer/vboxapisetup.py" ]; then
    39     for p in $PYTHON; do
     39PYTHON_INSTALLER_PATH="$VBOX_INSTALL_PATH/sdk/installer/python"
     40PYTHON_BINARIES="\
     41    python2.7  \
     42    python2    \
     43    python3.3  \
     44    python3.4  \
     45    python3.5  \
     46    python3.6  \
     47    python3.7  \
     48    python3.8  \
     49    python3.9  \
     50    python3.10 \
     51    python3.11 \
     52    python3.12 \
     53    python3    \
     54    python"
     55
     56if [ -e "$PYTHON_INSTALLER_PATH/vboxapisetup.py" ]; then
     57    for PYTHON_BIN in $PYTHON_BINARIES; do
    4058        # Install the python bindings if python is in the path
    41         if [ "`\${p} -c 'print "test"' 2> /dev/null`" = "test" ]; then
    42                 echo  1>&2 "Python found: ${p}, installing bindings..."
    43                 # Pass install path via environment
    44                 export VBOX_INSTALL_PATH
    45                 /bin/sh -c "cd $VBOX_INSTALL_PATH/sdk/installer && ${p} vboxapisetup.py install"
    46                 /bin/sh -c "cd $VBOX_INSTALL_PATH/sdk/installer && ${p} vboxapisetup.py clean --all"
     59        if [ "`\${PYTHON_BIN} -c 'print "test"' 2> /dev/null`" = "test" ]; then
     60            echo  1>&2 "Python found: ${PYTHON_BIN}, installing bindings..."
     61            # Pass install path via environment
     62            export VBOX_INSTALL_PATH
     63            # Check if python has working distutils
     64            "$PYTHON_BIN" -c "from distutils.core import setup" > /dev/null 2>&1
     65            if test "$?" -ne 0; then
     66                echo 1>&2 "Python $PYTHON_VER does not have package 'distutils', checking for 'setuptools'..."
     67                # Since Python 3.12 there are no distutils anymore. See PEP632.
     68                "$PYTHON_BIN" -c "from setuptools import setup" > /dev/null 2>&1
     69                if test "$?" -ne 0; then
     70                    echo 1>&2 "Python $PYTHON_VER also does not have package 'setuptools'. Skipping installation."
     71                    return 0
     72                fi
     73                # When we reach here, we have to use 'pip' in order to install our bindings (Python >= 3.12).
     74                if test -x "`which pip 2>/dev/null`"; then
     75                    PYTHON_PIP_BIN=$(which pip)
     76                else
     77                    echo 1>&2 "Python package manager 'pip' not found. Skipping installation."
     78                fi
     79            fi
     80
     81            if [ -n "$PYTHON_PIP_BIN" ]; then
     82                # Note: We use '-v' to show verbose output of our setup.py script on error.
     83                $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_PIP_BIN} -v install ./vboxapi"
     84            else
     85                $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_BIN} vboxapisetup.py install"
     86                $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_BIN} vboxapisetup.py clean --all"
     87            fi
    4788        fi
    4889    done
  • trunk/src/VBox/Installer/linux/Makefile.kmk

    r101365 r103028  
    532532                $(if $(VBOX_WITH_PYTHON), \
    533533                        archive/sdk/installer \
    534                         archive/sdk/installer/vboxapi \
     534                        archive/sdk/installer/python/vboxapi \
    535535                        archive/sdk/bindings/xpcom/python/xpcom \
    536536                        archive/sdk/bindings/xpcom/python/xpcom/client \
  • trunk/src/VBox/Installer/linux/debian/rules

    r101364 r103028  
    309309        fi
    310310        export VBOX_INSTALL_PATH=/usr/lib/$(package) && \
    311             cd $(builddir)/bin/sdk/installer && \
     311            cd $(builddir)/bin/sdk/installer/python && \
    312312            $(PYTHON) ./vboxapisetup.py install --root $(prefix)
    313313        rm -rf $(prefix)/usr/lib/$(package)/sdk/installer
  • trunk/src/VBox/Installer/linux/deffiles

    r98103 r103028  
    511511    sdk/installer/build/lib/vboxapi/VirtualBox_constants.py
    512512    sdk/installer/build/lib/vboxapi/__init__.py
     513    sdk/installer/python/build/lib/vboxapi/VirtualBox_constants.py
     514    sdk/installer/python/build/lib/vboxapi/__init__.py
    513515    sdk/idl/ \
    514516    sdk/idl/nsIDebug.idl \
  • trunk/src/VBox/Installer/linux/routines.sh

    r102880 r103028  
    401401
    402402
    403 # install_python_bindings(pythonbin pythondesc)
     403# install_python_bindings(PYTHON_BIN PYTHON_VER)
    404404# failure: non fatal
     405#
     406## @todo r=andy Merge this code with darwin/VirtualBox/postflight!
    405407install_python_bindings()
    406408{
    407     pythonbin="$1"
    408     pythondesc="$2"
     409    PYTHON_BIN="$1"
     410    PYTHON_VER="$2"
    409411
    410412    # The python binary might not be there, so just exit silently
    411     if test -z "$pythonbin"; then
     413    if test -z "$PYTHON_BIN"; then
    412414        return 0
    413415    fi
    414416
    415     if test -z "$pythondesc"; then
     417    if test -z "$PYTHON_VER"; then
    416418        echo 1>&2 "missing argument to install_python_bindings"
    417419        return 1
    418420    fi
    419421
    420     echo 1>&2 "Python found: $pythonbin, installing bindings..."
    421 
    422     # check if python has working distutils
    423     "$pythonbin" -c "from distutils.core import setup" > /dev/null 2>&1
     422    echo 1>&2 "Python found: $PYTHON_BIN, installing bindings..."
     423
     424    # Check if python has working distutils
     425    "$PYTHON_BIN" -c "from distutils.core import setup" > /dev/null 2>&1
    424426    if test "$?" -ne 0; then
    425         echo 1>&2 "Skipped: $pythondesc install is unusable, missing package 'distutils'"
    426         return 0
    427     fi
     427        echo 1>&2 "Python $PYTHON_VER does not have package 'distutils', checking for 'setuptools'..."
     428        # Since Python 3.12 there are no distutils anymore. See PEP632.
     429        "$PYTHON_BIN" -c "from setuptools import setup" > /dev/null 2>&1
     430        if test "$?" -ne 0; then
     431            echo 1>&2 "Python $PYTHON_VER also does not have package 'setuptools'. Skipping installation."
     432            return 0
     433        fi
     434        # When we reach here, we have to use 'pip' in order to install our bindings (Python >= 3.12).
     435        if test -x "`which pip 2>/dev/null`"; then
     436            PYTHON_PIP_BIN=$(which pip)
     437        else
     438            echo 1>&2 "Python package manager 'pip' not found. Skipping installation."
     439        fi
     440    fi
     441
     442    PYTHON_INSTALLER_PATH="$VBOX_INSTALL_PATH/sdk/installer/python"
    428443
    429444    # Pass install path via environment
    430445    export VBOX_INSTALL_PATH
    431     $SHELL -c "cd $VBOX_INSTALL_PATH/sdk/installer && $pythonbin vboxapisetup.py install \
    432         --record $CONFIG_DIR/python-$CONFIG_FILES"
    433     cat $CONFIG_DIR/python-$CONFIG_FILES >> $CONFIG_DIR/$CONFIG_FILES
    434     rm -f $CONFIG_DIR/python-$CONFIG_FILES
     446
     447    if [ -n "$PYTHON_PIP_BIN" ]; then
     448        # Note: We use '-v' to show verbose output of our setup.py script on error.
     449        $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_PIP_BIN} -v install ./vboxapi"
     450    else
     451        $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_BIN} ./vboxapisetup.py install \
     452                   --record $CONFIG_DIR/python-$CONFIG_FILES"
     453        cat "$CONFIG_DIR/python-$CONFIG_FILES" >> "$CONFIG_DIR/$CONFIG_FILES"
     454        rm -f "$CONFIG_DIR/python-$CONFIG_FILES"
     455    fi
    435456
    436457    # Remove files created by Python API setup.
    437     rm -rf $VBOX_INSTALL_PATH/sdk/installer/build
    438 }
    439 
     458    rm -rf "$PYTHON_INSTALLER_PATH/build"
     459}
     460
     461## @todo r=andy Merge this code with darwin/VirtualBox/postflight!
    440462maybe_run_python_bindings_installer() {
    441463    VBOX_INSTALL_PATH="${1}"
     
    444466    # the VirtualBox API bindings. Needs to prevent double installs which waste
    445467    # quite a bit of time.
    446     PYTHONS=""
    447     for p in python2.6 python2.7 python2 python3.3 python3.4 python3.5 python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python; do
    448         if [ "`$p -c 'import sys
     468    PYTHON_VER_INSTALLED=""
     469    PYTHON_BINARIES="\
     470        python2.7 \
     471        python2   \
     472        python3.3 \
     473        python3.4 \
     474        python3.5 \
     475        python3.6 \
     476        python3.7 \
     477        python3.8 \
     478        python3.9 \
     479        python3.10 \
     480        python3.11 \
     481        python3.12 \
     482        python3 \
     483        python"
     484
     485    for PYTHON_BIN in $PYTHON_BINARIES; do
     486        if [ "`$PYTHON_BIN -c 'import sys
    449487if sys.version_info >= (2, 6) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
    450488    print(\"test\")' 2> /dev/null`" != "test" ]; then
     
    453491        # Get python major/minor version, and skip if it was already covered.
    454492        # Uses grep -F to avoid trouble with '.' matching any char.
    455         pyvers="`$p -c 'import sys
     493        PYTHON_VER="`$PYTHON_BIN -c 'import sys
    456494print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
    457         if echo "$PYTHONS" | grep -Fq ":$pyvers:"; then
     495        if echo "$PYTHON_VER_INSTALLED" | grep -Fq ":$PYTHON_VER:"; then
    458496            continue
    459497        fi
    460498        # Record which version will be installed. If it fails there is no point
    461499        # trying with different executable/symlink reporting the same version.
    462         PYTHONS="$PYTHONS:$pyvers:"
    463         install_python_bindings "$p" "Python $pyvers"
     500        PYTHON_VER_INSTALLED="$PYTHON_VER_INSTALLED:$PYTHON_VER:"
     501        install_python_bindings "$PYTHON_BIN" "$PYTHON_VER"
    464502    done
    465     if [ -z "$PYTHONS" ]; then
    466         echo 1>&2 "Python (2.6, 2.7 or 3.3 and later) unavailable, skipping bindings installation."
     503    if [ -z "$PYTHON_VER_INSTALLED" ]; then
     504        echo 1>&2 "Python (2.7 or 3.3 and later) unavailable, skipping bindings installation."
    467505        return 1
    468506    fi
     
    470508    return 0
    471509}
     510
  • trunk/src/VBox/Installer/linux/rpm/VirtualBox.tmpl.spec

    r102907 r103028  
    108108%if %{?with_python:1}%{!?with_python:0}
    109109(export VBOX_INSTALL_PATH=/usr/lib/virtualbox && \
    110   cd ./sdk/installer && \
     110  cd ./sdk/installer/python && \
    111111  %{vbox_python} ./vboxapisetup.py install --prefix %{_prefix} --root $RPM_BUILD_ROOT)
    112112%endif
  • trunk/src/VBox/Installer/solaris/vboxconfig.sh

    r102880 r103028  
    903903}
    904904
    905 # install_python_bindings(pythonbin pythondesc)
     905# install_python_bindings(PYTHON_BIN PYTHON_VER)
    906906# failure: non fatal
     907#
     908## @todo r=andy Merge this code with linux/routines.sh!
    907909install_python_bindings()
    908910{
    909     pythonbin="$1"
    910     pythondesc="$2"
     911    PYTHON_BIN="$1"
     912    PYTHON_VER="$2"
    911913
    912914    # The python binary might not be there, so just exit silently
    913     if test -z "$pythonbin"; then
     915    if test -z "$PYTHON_BIN"; then
    914916        return 0
    915917    fi
    916918
    917     if test -z "$pythondesc"; then
     919    if test -z "$PYTHON_VER"; then
    918920        errorprint "missing argument to install_python_bindings"
    919921        return 1
    920922    fi
    921923
    922     infoprint "Python found: $pythonbin, installing bindings..."
     924    infoprint "Python found: $PYTHON_BIN, installing bindings..."
    923925
    924926    # check if python has working distutils
    925     "$pythonbin" -c "from distutils.core import setup" > /dev/null 2>&1
     927    "$PYTHON_BIN" -c "from distutils.core import setup" > /dev/null 2>&1
    926928    if test "$?" -ne 0; then
    927         subprint "Skipped: $pythondesc install is unusable, missing package 'distutils'"
     929        subprint "Skipped: Python $PYTHON_VER does not have package 'distutils', skipping..."
    928930        return 0
    929931    fi
     932
     933    MY_PYTHON_INSTALLER_PATH="$VBOX_INSTALL_PATH/sdk/installer/python"
    930934
    931935    # Pass install path via environment
     
    933937    mkdir -p "$CONFIG_DIR"
    934938    rm -f "$CONFIG_DIR/python-$CONFIG_FILES"
    935     $SHELL -c "cd \"$VBOX_INSTALL_PATH\"/sdk/installer && \"$pythonbin\" ./vboxapisetup.py install \
     939
     940    $SHELL -c "cd ${MY_PYTHON_INSTALLER_PATH} && ${PYTHON_BIN} ./vboxapisetup.py install \
    936941        --record \"$CONFIG_DIR/python-$CONFIG_FILES\"" > /dev/null 2>&1
    937942    if test "$?" -eq 0; then
    938943        cat "$CONFIG_DIR/python-$CONFIG_FILES" >> "$CONFIG_DIR/$CONFIG_FILES"
    939944    else
    940         errorprint "Failed to install bindings for $pythondesc"
     945        errorprint "Failed to install bindings for Python $PYTHON_VER"
    941946    fi
    942947    rm "$CONFIG_DIR/python-$CONFIG_FILES"
    943948
    944949    # Remove files created by Python API setup.
    945     rm -rf $VBOX_INSTALL_PATH/sdk/installer/build
     950    rm -rf "$MY_PYTHON_INSTALLER_PATH/build"
     951    return 0
     952}
     953
     954## @todo r=andy Merge this code with linux/routines.sh!
     955maybe_run_python_bindings_installer() {
     956    MY_PYTHON_INSTALLER_PATH="$VBOX_INSTALL_PATH/sdk/installer/python"
     957
     958    if test -f "$MY_PYTHON_INSTALLER_PATH/vboxapisetup.py" || test -h "$MY_PYTHON_INSTALLER_PATH/vboxapisetup.py"; then
     959        # Install python bindings for non-remote installs
     960        if test "$REMOTEINST" -eq 0; then
     961            infoprint "Installing Python bindings..."
     962
     963            # Loop over all usual suspect Python executable names and try installing
     964            # the VirtualBox API bindings. Needs to prevent double installs which waste
     965            # quite a bit of time.
     966            PYTHON_VER_INSTALLED=""
     967            PYTHON_BINARIES="\
     968                python2.4  \
     969                python2.5  \
     970                python2.6  \
     971                python2.7  \
     972                python2    \
     973                python3.3  \
     974                python3.4  \
     975                python3.5  \
     976                python3.6  \
     977                python3.7  \
     978                python3.8  \
     979                python3.9  \
     980                python3.10 \
     981                python3.11 \
     982                python3    \
     983                python     \
     984                "
     985
     986            for PYTHON_BIN in $PYTHON_BINARIES; do
     987                if [ "`$PYTHON_BIN -c 'import sys
     988if sys.version_info >= (2, 6) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
     989print(\"test\")' 2> /dev/null`" != "test" ]; then
     990                    continue
     991                fi
     992                # Get python major/minor version, and skip if it was
     993                # already covered.  Uses grep -F to avoid trouble with '.'
     994                # matching any char.
     995                PYTHON_VER="`$PYTHON_BIN -c 'import sys
     996print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
     997                if echo "$PYTHON_VER_INSTALLED" | /usr/xpg4/bin/grep -Fq ":$PYTHON_VER:"; then
     998                    continue
     999                fi
     1000                # Record which version will be installed. If it fails there
     1001                # is no point trying with different executable/symlink
     1002                # reporting the same version.
     1003                PYTHON_VER_INSTALLED="$PYTHON_VER_INSTALLED:$PYTHON_VER:"
     1004                install_python_bindings "$PYTHON_BIN" "$PYTHON_VER"
     1005            done
     1006            if [ -z "$PYTHON_VER_INSTALLED" ]; then
     1007                warnprint "Python (2.4 to 2.7 or 3.3 and later) unavailable, skipping bindings installation."
     1008            fi
     1009        else
     1010            warnprint "Skipped installing Python bindings. Run, as root, 'vboxapisetup.py install' manually from the booted system."
     1011        fi
     1012    fi
     1013
    9461014    return 0
    9471015}
     
    13401408        fi
    13411409
    1342         if test -f "$VBOX_INSTALL_PATH/sdk/installer/vboxapisetup.py" || test -h "$VBOX_INSTALL_PATH/sdk/installer/vboxapisetup.py"; then
    1343             # Install python bindings for non-remote installs
    1344             if test "$REMOTEINST" -eq 0; then
    1345                 infoprint "Installing Python bindings..."
    1346 
    1347                 # Loop over all usual suspect Python executable names and try
    1348                 # installing the VirtualBox API bindings. Needs to prevent
    1349                 # double installs which waste quite a bit of time.
    1350                 PYTHONS=""
    1351                 for p in python2.4 python2.5 python2.6 python2.7 python2 python3.3 python3.4 python3.5 python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python; do
    1352                     if [ "`$p -c 'import sys
    1353 if sys.version_info >= (2, 4) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
    1354     print(\"test\")' 2> /dev/null`" != "test" ]; then
    1355                         continue
    1356                     fi
    1357                     # Get python major/minor version, and skip if it was
    1358                     # already covered.  Uses grep -F to avoid trouble with '.'
    1359                     # matching any char.
    1360                     pyvers="`$p -c 'import sys
    1361 print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
    1362                     if echo "$PYTHONS" | /usr/xpg4/bin/grep -Fq ":$pyvers:"; then
    1363                         continue
    1364                     fi
    1365                     # Record which version will be installed. If it fails there
    1366                     # is no point trying with different executable/symlink
    1367                     # reporting the same version.
    1368                     PYTHONS="$PYTHONS:$pyvers:"
    1369                     install_python_bindings "$p" "Python $pyvers"
    1370                 done
    1371                 if [ -z "$PYTHONS" ]; then
    1372                     warnprint "Python (2.4 to 2.7 or 3.3 and later) unavailable, skipping bindings installation."
    1373                 fi
    1374             else
    1375                 warnprint "Skipped installing Python bindings. Run, as root, 'vboxapisetup.py install' manually from the booted system."
    1376             fi
    1377         fi
    1378 
     1410        maybe_run_python_bindings_installer
    13791411        update_boot_archive
    13801412
  • trunk/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp

    r100687 r103028  
    608608     */
    609609    /* Get the VBox API setup string. */
    610     WCHAR wszVBoxSDKPath[RTPATH_MAX];
    611     rcWin = VBoxGetMsiProp(hModule, L"CustomActionData", wszVBoxSDKPath, RT_ELEMENTS(wszVBoxSDKPath));
     610    WCHAR wszVBoxPythonInstallerPath[RTPATH_MAX];
     611    rcWin = VBoxGetMsiProp(hModule, L"CustomActionData", wszVBoxPythonInstallerPath, RT_ELEMENTS(wszVBoxPythonInstallerPath));
    612612    if (rcWin == ERROR_SUCCESS)
    613613    {
    614614        /* Make sure our current working directory is the VBox installation path. */
    615         if (SetCurrentDirectoryW(wszVBoxSDKPath))
     615        if (SetCurrentDirectoryW(wszVBoxPythonInstallerPath))
    616616        {
    617617            /* Set required environment variables. */
    618             if (SetEnvironmentVariableW(L"VBOX_INSTALL_PATH", wszVBoxSDKPath))
    619             {
    620                 logStringF(hModule, "InstallPythonAPI: Invoking vboxapisetup.py in \"%ls\" ...", wszVBoxSDKPath);
     618            if (SetEnvironmentVariableW(L"VBOX_INSTALL_PATH", wszVBoxPythonInstallerPath)) /** @todo BUGBUG r=andy That can't be right! */
     619            {
     620                logStringF(hModule, "InstallPythonAPI: Invoking vboxapisetup.py in \"%ls\" ...", wszVBoxPythonInstallerPath);
    621621
    622622                rcWin = procRun(hModule, wszPythonExe, L"vboxapisetup.py install");
     
    650650        else
    651651            logStringF(hModule, "InstallPythonAPI: Could set working directory to \"%ls\": LastError=%u",
    652                        wszVBoxSDKPath, GetLastError());
     652                       wszVBoxPythonInstallerPath, GetLastError());
    653653    }
    654654    else
  • trunk/src/VBox/Installer/win/VBoxMergePython.wxi

    r98103 r103028  
    3333    <Component Id="cp_VBoxPyInst" Guid="C9A40306-5102-11DE-A7BA-C3C555D89593" Win64="$(var.Property_Win64)">
    3434         <File Id="file_vboxapisetup.py" Name="vboxapisetup.py"
    35                Source="$(env.PATH_OUT)\bin\sdk\installer\vboxapisetup.py"
     35               Source="$(env.PATH_OUT)\bin\sdk\installer\python\vboxapisetup.py"
    3636               DiskId="$(var.Property_DiskIdCommon)" />
    3737    </Component>
     
    3939        <Component Id="cp_VBoxPyMod" Guid="DF19CB76-5102-11DE-943B-13C755D89593" Win64="$(var.Property_Win64)">
    4040            <File Id="file___init__.py" Name="__init__.py"
    41                   Source="$(env.PATH_OUT)\bin\sdk\installer\vboxapi\__init__.py"
     41                  Source="$(env.PATH_OUT)\bin\sdk\installer\python\vboxapi\__init__.py"
    4242                  DiskId="$(var.Property_DiskIdCommon)" />
    4343            <File Id="file_VirtualBox_constants.py" Name="VirtualBox_constants.py"
    44                   Source="$(env.PATH_OUT)\bin\sdk\installer\vboxapi\VirtualBox_constants.py"
     44                  Source="$(env.PATH_OUT)\bin\sdk\installer\python\vboxapi\VirtualBox_constants.py"
    4545                  DiskId="$(var.Property_DiskIdCommon)" />
    4646        </Component>
  • trunk/src/VBox/Installer/win/VirtualBox.wxs

    r98103 r103028  
    384384                <Directory Id="dir_SDK" Name="sdk">
    385385<?if $(env.VBOX_WITH_PYTHON) = "yes" ?>
    386                     <Directory Id="dir_SDKInstall" Name="install">
    387     <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
    388                         <Merge Id="msm_VBoxPython" Language="!(loc.LANG)" SourceFile="$(var.Property_VBoxMergePython)" DiskId="1" />
    389     <?else ?>
    390                         <Directory Id="msm_VBoxPythonFolder" FileSource=".">
    391                             <?include VBoxMergePython.wxi ?>
     386                    <Directory Id="dir_SDKInstaller" Name="installer"> <!-- Note: For < VBox 7.1 this folder was called 'install'. -->
     387                        <Directory Id="dir_SDKInstallerPython" Name="python">
     388        <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
     389                            <Merge Id="msm_VBoxPython" Language="!(loc.LANG)" SourceFile="$(var.Property_VBoxMergePython)" DiskId="1" />
     390        <?else ?>
     391                            <Directory Id="msm_VBoxPythonFolder" FileSource=".">
     392                                <?include VBoxMergePython.wxi ?>
     393                            </Directory>
     394        <?endif ?>
    392395                        </Directory>
    393     <?endif ?>
    394396                    </Directory>
    395397<?endif ?>
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette