VirtualBox

source: vbox/trunk/src/VBox/Installer/common/vboxapisetup.py@ 103325

Last change on this file since 103325 was 103325, checked in by vboxsync, 15 months ago

Installer/vboxapisetup*.py: Some pylint nits. Removed some unnecessary newline escaping and such. bugref:10579

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1"""
2Copyright (C) 2009-2023 Oracle and/or its affiliates.
3
4This file is part of VirtualBox base platform packages, as
5available from https://www.virtualbox.org.
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation, in version 3 of the
10License.
11
12This program is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, see <https://www.gnu.org/licenses>.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
23in the VirtualBox distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28
29SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
30"""
31
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
60 import shutil
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 _:
90 pass
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 _:
107 pass
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', asDirs = None):
154 """
155 Helper function for findModulePath.
156
157 Returns the path found, or None if not found.
158 """
159 if asDirs is None:
160 asDirs = sys.path;
161 for sPath in asDirs:
162 if g_fVerbose:
163 print('Searching for "%s" in path "%s" ...' % (sModule, sPath))
164 ## @todo r=bird: WOW. We read the directory and then look for a filename in the returned list?!? Case sensitively.
165 ## What about:
166 ## if g_fVerbose: # drop this
167 ## print(os.listdir(sPath));
168 ## sCandiate = os.path.join(sPath, sModule);
169 ## if os.path.exists(sCandiate):
170 ## return sCandiate;
171 if os.path.isdir(sPath):
172 asDirEntries = os.listdir(sPath)
173 if g_fVerbose:
174 print(asDirEntries)
175 if sModule in asDirEntries:
176 return os.path.join(sPath, sModule)
177 return None
178
179def findModulePath(sModule = 'vboxapi'):
180 """
181 Finds a module in the system path.
182
183 Returns the path found, or None if not found.
184 """
185 sPath = findModulePathHelper(sModule)
186 if not sPath:
187 try:
188 import site # Might not available everywhere.
189 sPath = findModulePathHelper(sModule, site.getsitepackages())
190 except:
191 pass
192 return sPath
193
194try:
195 from distutils.command.install import install # Only for < Python 3.12.
196except:
197 pass
198
199class VBoxSetupInstallClass(install):
200 """
201 Class which overrides the "install" command of the setup so that we can
202 run post-install actions.
203 """
204
205 def run(self):
206 def _post_install():
207 if findModulePath():
208 testVBoxAPI()
209 atexit.register(_post_install)
210 install.run(self)
211
212def main():
213 """
214 Main function for the setup script.
215 """
216
217 print("Installing VirtualBox bindings for Python %d.%d ..." % (sys.version_info.major, sys.version_info.minor))
218
219 # Deprecation warning for older Python stuff (< Python 3.x).
220 if sys.version_info.major < 3:
221 print("\nWarning: Running VirtualBox with Python %d.%d is marked as being deprecated.\n"
222 "Please upgrade your Python installation to avoid breakage.\n"
223 % (sys.version_info.major, sys.version_info.minor,))
224
225 sVBoxInstallPath = os.environ.get("VBOX_MSI_INSTALL_PATH", None)
226 if sVBoxInstallPath is None:
227 sVBoxInstallPath = os.environ.get('VBOX_INSTALL_PATH', None)
228 if sVBoxInstallPath is None:
229 print("No VBOX_INSTALL_PATH defined, exiting")
230 return 1
231
232 sVBoxVersion = os.environ.get("VBOX_VERSION", None)
233 if sVBoxVersion is None:
234 # Should we use VBox version for binding module versioning?
235 sVBoxVersion = "1.0"
236
237 if g_fVerbose:
238 print("VirtualBox installation directory is: %s" % (sVBoxInstallPath))
239
240 if platform.system() == 'Windows':
241 cleanupWinComCache()
242
243 # Make sure that we always are in the directory where this script resides.
244 # Otherwise installing packages below won't work.
245 sCurDir = os.path.dirname(os.path.abspath(__file__))
246 if g_fVerbose:
247 print("Current directory is: %s" % (sCurDir))
248 try:
249 os.chdir(sCurDir)
250 except OSError as exc:
251 print("Changing to current directory failed: %s" % (exc))
252
253 # Darwin: Patched before installation. Modifying bundle is not allowed, breaks signing and upsets gatekeeper.
254 if platform.system() != 'Darwin':
255 # @todo r=andy This *will* break the script if VirtualBox installation files will be moved.
256 # Better would be patching the *installed* module instead of the original module.
257 sVBoxSdkPath = os.path.join(sVBoxInstallPath, "sdk")
258 fRc = patchWith(os.path.join(sCurDir, 'src', 'vboxapi', '__init__.py'), sVBoxInstallPath, sVBoxSdkPath)
259 if not fRc:
260 return 1
261
262 try:
263 #
264 # Detect which installation method is being used.
265 #
266 # This is a bit messy due the fact that we want to support a broad range of older and newer
267 # Python versions, along with distributions which maintain their own Python packages (e.g. newer Ubuntus).
268 #
269 fInvokeSetupTools = False
270 if sys.version_info >= (3, 12): # Since Python 3.12 there are no distutils anymore. See PEP632.
271 try:
272 from setuptools import setup
273 except ImportError:
274 print("ERROR: setuptools package not installed, can't continue. Exiting.")
275 return 1
276 setup(cmdclass = { "install": VBoxSetupInstallClass, })
277 else:
278 try:
279 from distutils.core import setup # pylint: disable=deprecated-module
280 fInvokeSetupTools = True
281 except ImportError:
282 print("ERROR: distutils.core package not installed/available, can't continue. Exiting.")
283 return 1
284
285 if fInvokeSetupTools:
286 if g_fVerbose:
287 print("Invoking setuptools directly ...")
288 setupTool = setup(name='vboxapi',
289 version=sVBoxVersion,
290 description='Python interface to VirtualBox',
291 author='Oracle Corp.',
292 author_email='vbox-dev@virtualbox.org',
293 url='https://www.virtualbox.org',
294 package_dir={'': 'src'},
295 packages=['vboxapi'])
296 if setupTool:
297 sPathInstalled = setupTool.command_obj['install'].install_lib
298 if sPathInstalled not in sys.path:
299 print("");
300 print("WARNING: Installation path is not in current module search path!")
301 print(" This might happen on OSes / distributions which only maintain ")
302 print(" packages by a vendor-specific method.")
303 print("Hints:")
304 print("- Check how the distribution handles user-installable Python packages.")
305 print("- Using setuptools directly might be deprecated on the distribution.")
306 print("- Using \"pip install ./vboxapi\" within a virtual environment (virtualenv)")
307 print(" might fix this.\n")
308 sys.path.append(sPathInstalled)
309
310 print("Installed to: %s" % (sPathInstalled))
311
312 testVBoxAPI() # Testing the VBox API does not affect the exit code.
313
314 except RuntimeError as exc:
315 print("ERROR: Installation of VirtualBox Python bindings failed: %s" % (exc,))
316 return 1
317
318 return 0
319
320if __name__ == '__main__':
321 sys.exit(main())
Note: See TracBrowser for help on using the repository browser.

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