Module EDUtilsLibraryInstaller
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 """EDNA external libraries builder and installer, useful for PIL, numpy, scipy, Fabio, ... """
30
31 __contact__ = "Jerome.Kieffer@ESRF.eu"
32 __author__ = "Jerome Kieffer"
33 __license__ = "GPLv3+"
34 __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
35
36 import os, shutil, sys, zipfile, tarfile, urllib2, threading
37 from EDVerbose import EDVerbose
38 from EDUtilsPlatform import EDUtilsPlatform
39 from EDUtilsPath import EDUtilsPath
40
41 for strOneArg in sys.argv:
42 if strOneArg.lower() in ["-d", "--debug"]:
43 EDVerbose.setVerboseDebugOn()
46 """
47 This class helps to install to install an external library within EDNA
48 """
49 iMAX_DOWNLOAD_TIME = 60
50 - def __init__(self, _strLibraryDirectory, _strArchiveName=None, _strSourceDir=None):
51 """
52 Constructor of the class EDUtilsLibraryInstaller,
53
54 @param _strLibraryDirectory: the name of the directory where the library is, like "20090711-SciPy-0.7.1"
55 @type _strLibraryDirectory: python string
56 @param _strArchiveName: the name of the archive file. if None, the system will try to guess it, searching in _strLibraryDirectory for a tar.gz, tar.bz2 or a .zip
57 @type _strArchiveName: python string
58 @param _strSourceDir: the name of the directory where the setup.py file is, this could be guessed as well is None.
59 @type _strSourceDir: python string
60 """
61 self.__strLibraryDirectory = _strLibraryDirectory
62 self.__strArchiveName = _strArchiveName
63 self.__strSourceDir = _strSourceDir
64 self.__strDestinationDirectory = None
65 if os.environ.has_key("EDNA_HOME"):
66 self.__libraryPath = os.path.join(EDUtilsPath.EDNA_HOME, "libraries", self.__strLibraryDirectory)
67 else:
68 self.__libraryPath = os.path.dirname(os.path.abspath(sys.argv[0]))
69
70 @staticmethod
72 """
73 Checks that we are using at least python2.5 as zip and tarfiles modules are required to uncompress archive
74 even if those modules exists since python2.3 their API has changed in python2.5.
75 """
76 if sys.version_info < (2, 5):
77 raise ImportError, "Version of python too old, please use a python 2.5 or newer.\nCurrently you are using Python " + sys.version
78
79
80 - def dependency(self, _strLibraryName, _strLibraryDirectory, _tupleVersion=None, _strMethodToGetVersion=None):
81 """Tries to resolve a dependency on an external library like numpy
82
83 @param _strLibraryName: name of the library, "numpy" for example
84 @type _strLibraryName: Python string
85 @param _strLibraryDirectory: the name of the directory where the dependency library is, like "20090405-Numpy-1.3"
86 @type _strLibraryDirectory: Python string
87 @param _tupleVersion: the minimum version of the library to be installed.
88 @type: _tuplVersion: tuple of integer
89 @param _strMethodToGetVersion: for numpy it would be "version.version"
90 @type _strMethodToGetVersion: string
91 """
92 dictModulesBeforeImport = sys.modules.copy()
93 strDepLibPath = os.path.join(os.path.dirname(self.__libraryPath), _strLibraryDirectory, EDUtilsPlatform.architecture)
94 EDVerbose.DEBUG("LibInstaller.dependency: strDepLibPath=%s" % strDepLibPath)
95 try:
96 mylib = __import__(_strLibraryName)
97 except Exception:
98 if os.path.isdir(strDepLibPath)and (strDepLibPath not in sys.path):
99 sys.path.insert(1, strDepLibPath)
100 if os.environ.has_key("PYTHONPATH"):
101 os.environ["PYTHONPATH"] += os.pathsep + strDepLibPath
102 else:
103 os.environ["PYTHONPATH"] = strDepLibPath
104
105 else:
106 installLibrary(strDepLibPath)
107 mylib = __import__(_strLibraryName)
108
109 tupleVersionObt = None
110 if _strMethodToGetVersion is not None and _tupleVersion is not None:
111
112 try:
113 versionObt = eval("mylib.%s" % (_strMethodToGetVersion))
114 except Exception:
115 EDVerbose.WARNING("Unable to execute version %s.%s" % (_strLibraryName, _strMethodToGetVersion))
116 versionObt = None
117 if isinstance(versionObt, (unicode, str)):
118 try:
119 tupleVersionObt = tuple(map(int, versionObt.split(".")))
120 except Exception:
121 EDVerbose.WARNING("Unable to understand Version %s" % versionObt)
122 versionObt = None
123 elif isinstance(versionObt, tuple):
124 tupleVersionObt = versionObt
125 else:
126 del dictModulesBeforeImport
127
128 return
129 if tupleVersionObt is not None:
130 if tupleVersionObt < _tupleVersion:
131 EDVerbose.WARNING("Wrong library version: %s < %s" % (tupleVersionObt, _tupleVersion))
132 for oneModule in sys.modules.copy():
133 if oneModule not in dictModulesBeforeImport:
134 del sys.modules[ oneModule ]
135 if os.path.isdir(strDepLibPath):
136 sys.path.insert(1, strDepLibPath)
137 if "PYTHONPATH" in os.environ:
138 os.environ["PYTHONPATH"] = strDepLibPath + os.pathsep + os.environ["PYTHONPATH"]
139 else:
140 os.environ["PYTHONPATH"] = strDepLibPath
141
142 else:
143 installLibrary(strDepLibPath)
144 __import__(_strLibraryName)
145
146 del dictModulesBeforeImport
147
148
149
150 @staticmethod
152 """
153 Search in the LD_PRELOAD, LD_LIBRARY_PATH and subsequently in /etc/ld.so.conf & /etc/ld.so.conf.d/* for a library named
154
155 @param _strLibName: name of the file or library to look for
156 @type _strLibName: python string
157 @return: the name of the path where the library is (or None if it was not found
158 @rtype: string or None
159 """
160 strLibPath = None
161 listLib = []
162 if "LD_PRELOAD" in os.environ:
163 for oneLib in os.environ["LD_PRELOAD"].split(":"):
164 if oneLib not in listLib and os.path.isdir(oneLib):
165 listLib.append(oneLib)
166 if "LD_LIBRARY_PATH" in os.environ:
167 for oneLib in os.environ["LD_LIBRARY_PATH"].split(":"):
168 if oneLib not in listLib and os.path.isdir(oneLib):
169 listLib.append(oneLib)
170 if os.path.isdir("/etc/ld.so.conf"):
171 listLdSoConf = open("/etc/ld.so.conf").readlines()
172 listLdSoConf.reverse()
173 for oneLib in listLdSoConf:
174 oneLibS = oneLib.strip()
175 if oneLibS.startswith("include"):
176 includeDir = os.path.dirname(oneLibS.split()[1])
177 for strLdFile in os.listdir(includeDir):
178 confFile = os.path.join(includeDir, strLdFile)
179 for subdir in open(confFile).readlines():
180 subdirS = subdir.strip()
181 if subdirS not in listLib and os.path.isdir(oneLibS):
182 listLib.append(subdirS)
183 elif oneLibS not in listLib and os.path.isdir(oneLibS):
184 listLib.append(oneLibS)
185 for oneLib in ["/usr/local/lib", "/usr/lib", "/lib"]:
186 if os.path.isdir(oneLib) and oneLib not in listLib:
187 listLib.append(oneLib)
188
189
190 for oneLib in listLib:
191 for oneFile in os.listdir(oneLib):
192 if oneFile.startswith(_strLibName):
193 strLibPath = oneLib
194 return strLibPath
195 return strLibPath
196
197
199 """
200 Tries to guess the name of the archive from it's extension
201
202 @return: Name of the archive
203 @rtype: python string
204 """
205 if self.__strArchiveName == None:
206 for oneFile in os.listdir(self.__libraryPath):
207 if os.path.isfile(oneFile) and \
208 os.path.splitext(oneFile)[1].lower() in[".gz", ".bz2", ".zip", ".tgz", ".tbz", ".tbz2"]:
209 self.__strArchiveName = oneFile
210 return self.__strArchiveName
211
213 """
214 Uncompress the archived installer by using tar or zip
215 """
216 if self.__strArchiveName == None:
217 self.getArchiveName()
218 cwd = os.getcwd()
219 EDVerbose.DEBUG("Unzipping archive %s in directory %s." % (self.__strArchiveName, self.__libraryPath))
220
221 os.chdir(self.__libraryPath)
222 strArchiveNameLower = self.__strArchiveName.lower()
223 if strArchiveNameLower.endswith(".zip"):
224 zipped = zipfile.ZipFile(self.__strArchiveName)
225 if self.__strSourceDir == None:
226 self.__strSourceDir = os.path.dirname(zipped.filelist[0].filename)
227 if self.__strSourceDir == "":
228 self.__strSourceDir = zipped.filelist[0].filename
229 zipped.extractall()
230 zipped.close()
231 elif strArchiveNameLower.endswith(".tgz") or strArchiveNameLower.endswith(".tar.gz") \
232 or strArchiveNameLower.endswith(".tbz") or strArchiveNameLower.endswith(".tar.bz2") :
233 tar = tarfile.open(self.__strArchiveName)
234 if self.__strSourceDir == None:
235 self.__strSourceDir = os.path.dirname(tar.getmembers()[0].name)
236 if self.__strSourceDir == "":
237 self.__strSourceDir = tar.getmembers()[0].name
238 tar.extractall()
239 tar.close()
240 os.chdir(cwd)
241
242
244 """
245 Remove the source tree and clean up the installation directory to save some place
246 """
247 for root, dirs, files in os.walk(os.path.join(self.__libraryPath, self.__strSourceDir), topdown=False):
248 for name in files:
249 os.remove(os.path.join(root, name))
250 for name in dirs:
251 os.rmdir(os.path.join(root, name))
252 os.rmdir(os.path.join(self.__libraryPath, self.__strSourceDir))
253
254
256 """
257 Runs the setup.py to install the program within EDNA
258
259 @param _strOptions: options to be passed to setup.py (beside build)
260 @type _strOptions: python string
261 """
262 cwd = os.getcwd()
263 os.chdir(os.path.join(self.__libraryPath, self.__strSourceDir))
264 sys.path = [sys.path[0], os.path.join(self.__libraryPath, self.__strSourceDir)] + sys.path[1:]
265 EDVerbose.DEBUG("%s$ python setup.py build %s " % (os.getcwd(), _strOptions))
266 os.system("%s setup.py build %s 2>&1" % (sys.executable, _strOptions))
267 os.chdir(cwd)
268
269
271 """
272 Install/Move the source/build/prefix to the library directory
273 very specific to EDNA
274 @param _strPrefix: prefix of the path like "build/lib.linux-x86_64-2.5"
275 @type _strPrefix: string
276 @param _strStartSubDir: prefix of the path like "numpy/core/include/numpy"
277 @type _strStartSubDir: string
278 """
279 if _strStartSubDir is None:
280 if _strPrefix is None:
281 build = os.path.join(self.__libraryPath, _strPrefix)
282 else:
283 build = os.path.join(self.__libraryPath, self.__strSourceDir, _strPrefix)
284 dest = self.getDestinationDirectory()
285 else:
286 if _strPrefix is None:
287 build = os.path.join(self.__libraryPath, self.__strSourceDir, _strStartSubDir)
288 else:
289 build = os.path.join(self.__libraryPath, self.__strSourceDir, _strPrefix, _strStartSubDir)
290 dest = os.path.join(self.getDestinationDirectory(), _strStartSubDir)
291 EDVerbose.DEBUG("Installing python library from %s to %s" % (build, dest))
292 if os.path.isdir(build):
293 if os.path.isdir(dest):
294 EDVerbose.DEBUG("walking in %s" % build)
295 for dirpath, dirnames, filenames in os.walk(build):
296 EDVerbose.DEBUG("%s, %s, %s" % (dirpath, dirnames, filenames))
297 shortdir = dirpath[len(build) + 1:]
298 for oneDir in dirnames:
299 if not os.path.isdir(os.path.join(dest, shortdir, oneDir)):
300 os.makedirs(os.path.join(dest, shortdir, oneDir))
301 for oneFile in filenames:
302 target = os.path.join(shortdir, oneFile)
303
304 if not os.path.isfile(os.path.join(dest, target)):
305 shutil.move(os.path.join(build, target), os.path.join(dest, target))
306 else:
307 EDVerbose.DEBUG("mv %s to %s" % (build, dest))
308 shutil.move(build, dest)
309 else:
310 EDVerbose.ERROR("Error in installing the library: No %s" % build)
311
312
322
323
330
331
346
347
348 - def make(self, _strOptions=""):
349 """
350 Run the make program configure program to compile the library
351
352 @param _strOptions: options to be passed to make program
353 @type _strOptions: python string
354 """
355 cwd = os.getcwd()
356 EDVerbose.DEBUG("dir=" + os.path.join(self.__libraryPath, self.__strSourceDir))
357 os.chdir(os.path.join(self.__libraryPath, self.__strSourceDir))
358 EDVerbose.DEBUG("%s$ make %s" % (os.getcwd(), _strOptions))
359 strOutput = os.popen("make %s 2>&1" % (_strOptions)).read()
360 EDVerbose.DEBUG(strOutput)
361 os.chdir(cwd)
362
363
364 - def downloadLibrary(self, _strServer="http://www.edna-site.org/pub/libraries"):
365 """
366 Download the given library from edna-site by default or another server if provided.
367
368 @param _strServer: optionally, the name of the server
369 @type _strServer: python string
370 """
371 if not os.path.exists(self.__strArchiveName):
372 EDVerbose.screen("Trying to download library %s, timeout set to %d s" % (self.__strArchiveName, EDUtilsLibraryInstaller.iMAX_DOWNLOAD_TIME))
373 if os.environ.has_key("http_proxy"):
374 dictProxies = {'http': os.environ["http_proxy"]}
375 proxy_handler = urllib2.ProxyHandler(dictProxies)
376 opener = urllib2.build_opener(proxy_handler).open
377 else:
378 opener = urllib2.urlopen
379 strURL = "/".join((_strServer, self.__strArchiveName))
380
381 if sys.version > (2, 6):
382 data = opener(strURL, data=None, timeout=EDUtilsLibraryInstaller.iMAX_DOWNLOAD_TIME).read()
383 else:
384 timer = threading.Timer(EDUtilsLibraryInstaller.iMAX_DOWNLOAD_TIME + 1, timeoutDuringDownload)
385 timer.start()
386 data = opener(strURL, data=None).read()
387 timer.cancel()
388
389 try:
390 open(self.__strArchiveName, "wb").write(data)
391 except IOError:
392 raise IOError, "unable to write downloaded data to disk at " + self.__strArchiveName
393
394 if os.path.exists(self.__strArchiveName):
395 EDVerbose.screen("Library %s successfully downloaded." % self.__strArchiveName)
396 else:
397 raise RuntimeError, "Could not automatically download libraries %r! \n \
398 If you are behind a firewall, please set the environment variable http_proxy. \n \
399 Otherwise please try to download the images manually from \n \
400 http://www.edna-site.org/pub/libraries" % self.__strArchiveName
401
402
404 """
405 Getter for the distinationDirectory:
406
407 @return: /$EDNA_HOME/libraries/libName/lib.linux-x86_64-2.x
408 @rtype: string
409 """
410 if self.__strDestinationDirectory is None:
411 self.__strDestinationDirectory = os.path.join(self.__libraryPath, EDUtilsPlatform.architecture)
412 EDVerbose.DEBUG("Setting DestinationDirectory to %s" % self.__strDestinationDirectory)
413 if not os.path.isdir(self.__strDestinationDirectory):
414 os.makedirs(self.__strDestinationDirectory)
415 return self.__strDestinationDirectory
416
417
419 """
420 Getter for the source directory:
421
422 @return: /$EDNA_HOME/libraries/libName/myLib/
423 @rtype: string
424 """
425 return self.__strSourceDir
426
427
429 """
430 Getter for the Libary Path:
431
432 @return: ....
433 @rtype: string
434 """
435 return self.__strLibraryDirectory
436
437
438 @staticmethod
440 """
441 here only fro compatibility reason ... please use EDUtilsPlatform.architecture
442
443 @return lib.linux-i386-2.6
444 @rtype: string
445 """
446 return EDUtilsPlatform.architecture
447
450 """
451 Function called after a timeout in the download part ... just raise an Exception.
452 """
453 raise RuntimeError("Could not automatically download library ! \n \
454 If you are behind a firewall, please set the environment variable http_proxy. \n \
455 Otherwise please try to download the images manually from \n \
456 http://www.edna-site.org/pub/libraries")
457
460 """
461 Runs the EDNA library installer in the given directory (no dependencies inside the kernel)
462 @param _strPath: full path of the diresctory where the install script is
463 @type _strPath: string
464 """
465 EDVerbose.DEBUG("Building H5Py %s" % _strPath)
466 cwd = os.getcwd()
467 if _strPath in sys.path: sys.path.remove(_strPath)
468 os.chdir(os.path.dirname(_strPath))
469 os.system("%s install.py" % sys.executable)
470 os.chdir(cwd)
471 sys.path.insert(1, _strPath)
472