# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import time import struct try: import importlib try: PY_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER SOURCE_SUFFIXES = importlib.machinery.SOURCE_SUFFIXES BYTECODE_SUFFIXES = importlib.machinery.BYTECODE_SUFFIXES except Exception: raise ImportError() except ImportError: import imp PY_MAGIC_NUMBER = imp.get_magic() SOURCE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_SOURCE] BYTECODE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_COMPILED] from pysmi.searcher.base import AbstractSearcher from pysmi.searcher.pyfile import PyFileSearcher from pysmi.compat import decode from pysmi import debug from pysmi import error class PyPackageSearcher(AbstractSearcher): """Figures out if given Python module (source or bytecode) exists in given Python package. Python package must be importable. """ def __init__(self, package): """Create an instance of *PyPackageSearcher* bound to specific Python package. Args: package (str): name of the Python package to look up Python modules at. """ self._package = package self.__loader = None def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._package) @staticmethod def _parseDosTime(dosdate, dostime): t = (((dosdate >> 9) & 0x7f) + 1980, # year ((dosdate >> 5) & 0x0f), # month dosdate & 0x1f, # mday (dostime >> 11) & 0x1f, # hour (dostime >> 5) & 0x3f, # min (dostime & 0x1f) * 2, # sec -1, # wday -1, # yday -1) # dst return time.mktime(t) def fileExists(self, mibname, mtime, rebuild=False): if rebuild: debug.logger & debug.flagSearcher and debug.logger('pretend %s is very old' % mibname) return mibname = decode(mibname) try: p = __import__(self._package, globals(), locals(), ['__init__']) if hasattr(p, '__loader__') and hasattr(p.__loader__, '_files'): self.__loader = p.__loader__ self._package = self._package.replace('.', os.sep) debug.logger & debug.flagSearcher and debug.logger( '%s is an importable egg at %s' % (self._package, os.path.split(p.__file__)[0])) elif hasattr(p, '__file__'): debug.logger & debug.flagSearcher and debug.logger( '%s is not an egg, trying it as a package directory' % self._package) return PyFileSearcher(os.path.split(p.__file__)[0]).fileExists(mibname, mtime, rebuild=rebuild) else: raise error.PySmiFileNotFoundError('%s is neither importable nor a file' % self._package, searcher=self) except ImportError: raise error.PySmiFileNotFoundError('%s is not importable, trying as a path' % self._package, searcher=self) for pySfx in BYTECODE_SUFFIXES: f = os.path.join(self._package, mibname.upper()) + pySfx if f not in self.__loader._files: debug.logger & debug.flagSearcher and debug.logger('%s is not in %s' % (f, self._package)) continue pyData = self.__loader.get_data(f) if pyData[:4] == PY_MAGIC_NUMBER: pyData = pyData[4:] pyTime = struct.unpack('= mtime: raise error.PySmiFileNotModifiedError() else: raise error.PySmiFileNotFoundError('older file %s exists' % mibname, searcher=self) else: debug.logger & debug.flagSearcher and debug.logger('bad magic in %s' % f) continue for pySfx in SOURCE_SUFFIXES: f = os.path.join(self._package, mibname.upper()) + pySfx if f not in self.__loader._files: debug.logger & debug.flagSearcher and debug.logger('%s is not in %s' % (f, self._package)) continue pyTime = self._parseDosTime( self.__loader._files[f][6], self.__loader._files[f][5] ) debug.logger & debug.flagSearcher and debug.logger( 'found %s, mtime %s' % (f, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(pyTime)))) if pyTime >= mtime: raise error.PySmiFileNotModifiedError() else: raise error.PySmiFileNotFoundError('older file %s exists' % mibname, searcher=self) raise error.PySmiFileNotFoundError('no file %s found' % mibname, searcher=self)