VirtualBox

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

Last change on this file was 103326, checked in by vboxsync, 4 months ago

Installer/vboxapisetup.py: Use os.path.exist() rather than searching the listdir() output when searching for a module. listdir may barf on 2.6 if applied to .zip files (not that it is necessarily relevant). bugref:10579

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 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
153## @todo r=bird: This is supposed to be publicly visible?
154def findModulePathHelper(sModule = 'vboxapi', asDirs = None):
155 """
156 Helper function for findModulePath.
157
158 Returns the path found, or None if not found.
159 """
160 if asDirs is None:
161 asDirs = sys.path;
162 for sPath in asDirs:
163 if g_fVerbose:
164 print('Searching for "%s" in "%s" ...' % (sModule, sPath))
165 try: print(os.listdir(sPath));
166 except: pass;
167 sCandiate = os.path.join(sPath, sModule);
168 if os.path.exists(sCandiate):
169 return sCandiate;
170 return None
171
172## @todo r=bird: This is supposed to be publicly visible?
173def findModulePath(sModule = 'vboxapi'):
174 """
175 Finds a module in the system path.
176
177 Returns the path found, or None if not found.
178 """
179 sPath = findModulePathHelper(sModule)
180 if not sPath:
181 try:
182 import site # Might not available everywhere.
183 sPath = findModulePathHelper(sModule, site.getsitepackages())
184 except:
185 pass
186 return sPath
187
188try:
189 from distutils.command.install import install # Only for < Python 3.12.
190except:
191 pass
192
193class VBoxSetupInstallClass(install):
194 """
195 Class which overrides the "install" command of the setup so that we can
196 run post-install actions.
197 """
198
199 def run(self):
200 def _post_install():
201 if findModulePath():
202 testVBoxAPI()
203 atexit.register(_post_install)
204 install.run(self)
205
206def main():
207 """
208 Main function for the setup script.
209 """
210
211 print("Installing VirtualBox bindings for Python %d.%d ..." % (sys.version_info.major, sys.version_info.minor))
212
213 # Deprecation warning for older Python stuff (< Python 3.x).
214 if sys.version_info.major < 3:
215 print("\nWarning: Running VirtualBox with Python %d.%d is marked as being deprecated.\n"
216 "Please upgrade your Python installation to avoid breakage.\n"
217 % (sys.version_info.major, sys.version_info.minor,))
218
219 sVBoxInstallPath = os.environ.get("VBOX_MSI_INSTALL_PATH", None)
220 if sVBoxInstallPath is None:
221 sVBoxInstallPath = os.environ.get('VBOX_INSTALL_PATH', None)
222 if sVBoxInstallPath is None:
223 print("No VBOX_INSTALL_PATH defined, exiting")
224 return 1
225
226 sVBoxVersion = os.environ.get("VBOX_VERSION", None)
227 if sVBoxVersion is None:
228 # Should we use VBox version for binding module versioning?
229 sVBoxVersion = "1.0"
230
231 if g_fVerbose:
232 print("VirtualBox installation directory is: %s" % (sVBoxInstallPath))
233
234 if platform.system() == 'Windows':
235 cleanupWinComCache()
236
237 # Make sure that we always are in the directory where this script resides.
238 # Otherwise installing packages below won't work.
239 sCurDir = os.path.dirname(os.path.abspath(__file__))
240 if g_fVerbose:
241 print("Current directory is: %s" % (sCurDir))
242 try:
243 os.chdir(sCurDir)
244 except OSError as exc:
245 print("Changing to current directory failed: %s" % (exc))
246
247 # Darwin: Patched before installation. Modifying bundle is not allowed, breaks signing and upsets gatekeeper.
248 if platform.system() != 'Darwin':
249 # @todo r=andy This *will* break the script if VirtualBox installation files will be moved.
250 # Better would be patching the *installed* module instead of the original module.
251 sVBoxSdkPath = os.path.join(sVBoxInstallPath, "sdk")
252 fRc = patchWith(os.path.join(sCurDir, 'src', 'vboxapi', '__init__.py'), sVBoxInstallPath, sVBoxSdkPath)
253 if not fRc:
254 return 1
255
256 try:
257 #
258 # Detect which installation method is being used.
259 #
260 # This is a bit messy due the fact that we want to support a broad range of older and newer
261 # Python versions, along with distributions which maintain their own Python packages (e.g. newer Ubuntus).
262 #
263 fInvokeSetupTools = False
264 if sys.version_info >= (3, 12): # Since Python 3.12 there are no distutils anymore. See PEP632.
265 try:
266 from setuptools import setup
267 except ImportError:
268 print("ERROR: setuptools package not installed, can't continue. Exiting.")
269 return 1
270 setup(cmdclass = { "install": VBoxSetupInstallClass, })
271 else:
272 try:
273 from distutils.core import setup # pylint: disable=deprecated-module
274 fInvokeSetupTools = True
275 except ImportError:
276 print("ERROR: distutils.core package not installed/available, can't continue. Exiting.")
277 return 1
278
279 if fInvokeSetupTools:
280 if g_fVerbose:
281 print("Invoking setuptools directly ...")
282 setupTool = setup(name='vboxapi',
283 version=sVBoxVersion,
284 description='Python interface to VirtualBox',
285 author='Oracle Corp.',
286 author_email='vbox-dev@virtualbox.org',
287 url='https://www.virtualbox.org',
288 package_dir={'': 'src'},
289 packages=['vboxapi'])
290 if setupTool:
291 sPathInstalled = setupTool.command_obj['install'].install_lib
292 if sPathInstalled not in sys.path:
293 print("");
294 print("WARNING: Installation path is not in current module search path!")
295 print(" This might happen on OSes / distributions which only maintain ")
296 print(" packages by 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 testVBoxAPI() # Testing the VBox API does not affect the exit code.
307
308 except RuntimeError as exc:
309 print("ERROR: Installation of VirtualBox Python bindings failed: %s" % (exc,))
310 return 1
311
312 return 0
313
314if __name__ == '__main__':
315 sys.exit(main())
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use