You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
5.1 KiB
140 lines
5.1 KiB
#
|
|
# This file is part of pysmi software.
|
|
#
|
|
# Copyright (c) 2015-2019, Ilya Etingof <etingof@gmail.com>
|
|
# 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('<L', pyData[:4])[0]
|
|
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)
|
|
|
|
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)
|