Ejemplo n.º 1
0
    def getData(self, mibname, zipBlob=None):
        debug.logger & debug.flagReader and debug.logger('looking for MIB %s at %s' % (mibname, self._name))

        if self._pendingError:
            raise self._pendingError

        if not self._members:
            raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self)

        for mibalias, mibfile in self.getMibVariants(mibname):

            debug.logger & debug.flagReader and debug.logger('trying MIB %s' % mibfile)

            try:
                refs = self._members[mibfile]

            except KeyError:
                continue

            mibData, mtime = self._readZipFile(refs)

            if not mibData:
                continue

            debug.logger & debug.flagReader and debug.logger(
                'source MIB %s, mtime %s, read from %s/%s' % (mibfile, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)), self._name, mibfile)
            )

            if len(mibData) == self.maxMibSize:
                raise IOError('MIB %s/%s too large' % (self._name, mibfile))

            return MibInfo(path='zip://%s/%s' % (self._name, mibfile),
                           file=mibfile, name=mibalias, mtime=mtime), decode(mibData)

        raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self)
Ejemplo n.º 2
0
    def genCode(self, ast, symbolTable, **kwargs):
        self.genRules['text'] = kwargs.get('genTexts', False)
        self._rows.clear()
        self._cols.clear()
        self._parentOids.clear()
        self._symsOrder = []
        self._postponedSyms.clear()
        self._importMap.clear()
        self._out = {}  # should be new object, do not use `clear` method
        self.moduleName[0], moduleOid, imports, declarations = ast

        out, importedModules = self.genImports(imports or {})

        for declr in declarations or []:
            if declr:
                clausetype = declr[0]
                classmode = clausetype == 'typeDeclaration'
                self.handlersTable[declr[0]](self, self.prepData(declr[1:], classmode), classmode)

        if self._postponedSyms:
            raise error.PySmiSemanticError('Unknown parents for symbols: %s' % ', '.join(self._postponedSyms))

        for sym in self._parentOids:
            if sym not in self._out and sym not in self._importMap:
                raise error.PySmiSemanticError('Unknown parent symbol: %s' % sym)

        self._out['_symtable_order'] = list(self._symsOrder)
        self._out['_symtable_cols'] = list(self._cols)
        self._out['_symtable_rows'] = list(self._rows)

        debug.logger & debug.flagCodegen and debug.logger(
            'canonical MIB name %s (%s), imported MIB(s) %s, Symbol table size %s symbols' % (
                self.moduleName[0], moduleOid, ','.join(importedModules) or '<none>', len(self._out)))

        return MibInfo(oid=None, name=self.moduleName[0], imported=tuple([x for x in importedModules])), self._out
Ejemplo n.º 3
0
    def getData(self, mibname):
        debug.logger & debug.flagReader and debug.logger('calling user callback %s for MIB %s' % (self._cbFun, mibname))

        res = self._cbFun(mibname, self._cbCtx)
        if res:
            return MibInfo(path='file:///dev/stdin', file='', name=mibname, mtime=time.time()), res

        raise error.PySmiReaderFileNotFoundError(mibname=mibname, reader=self)
Ejemplo n.º 4
0
    def getData(self, mibname):
        headers = {'Accept': 'text/plain'}
        if sys.version_info[:2] < (2, 6):
            conn = httplib.HTTPConnection(self._host, self._port)
        else:
            conn = httplib.HTTPConnection(self._host,
                                          self._port,
                                          timeout=self._timeout)

        mibname = decode(mibname)

        debug.logger & debug.flagReader and debug.logger(
            'looking for MIB %s' % mibname)

        for mibalias, mibfile in self.getMibVariants(mibname):
            location = self._locationTemplate.replace('@mib@', mibfile)
            debug.logger & debug.flagReader and debug.logger(
                'trying to fetch MIB from %s://%s:%s%s' %
                (self._schema, self._host, self._port, location))
            try:
                conn.request('GET', location, '', headers)
                response = conn.getresponse()
            except Exception:
                debug.logger & debug.flagReader and debug.logger(
                    'failed to fetch MIB from %s://%s:%s%s: %s' %
                    (self._schema, self._host, self._port, location,
                     sys.exc_info()[1]))
                continue

            debug.logger & debug.flagReader and debug.logger(
                'HTTP response %s' % response.status)

            if response.status == 200:
                try:
                    mtime = time.mktime(
                        time.strptime(response.getheader('Last-Modified'),
                                      "%a, %d %b %Y %H:%M:%S %Z"))
                except Exception:
                    debug.logger & debug.flagReader and debug.logger(
                        'malformed HTTP headers: %s' % sys.exc_info()[1])
                    mtime = time.time()

                debug.logger & debug.flagReader and debug.logger(
                    'fetching source MIB %s, mtime %s' %
                    (location, response.getheader('Last-Modified')))

                return MibInfo(
                    path='%s://%s:%s%s' %
                    (self._schema, self._host, self._port, location),
                    file=mibfile,
                    name=mibalias,
                    mtime=mtime), decode(response.read(self.maxMibSize))

        raise error.PySmiReaderFileNotFoundError('source MIB %s not found' %
                                                 mibname,
                                                 reader=self)
Ejemplo n.º 5
0
    def getData(self, mibname):
        headers = {'Accept': 'text/plain', 'User-Agent': self._user_agent}

        mibname = decode(mibname)

        debug.logger & debug.flagReader and debug.logger(
            'looking for MIB %s' % mibname)

        for mibalias, mibfile in self.getMibVariants(mibname):
            if self.MIB_MAGIC in self._url:
                url = self._url.replace(self.MIB_MAGIC, mibfile)
            else:
                url = self._url + mibfile

            debug.logger & debug.flagReader and debug.logger(
                'trying to fetch MIB from %s' % url)

            try:
                req = Request(url, headers=headers)
                response = urlopen(req)

            except Exception:
                debug.logger & debug.flagReader and debug.logger(
                    'failed to fetch MIB from %s: %s' %
                    (url, sys.exc_info()[1]))
                continue

            debug.logger & debug.flagReader and debug.logger(
                'HTTP response %s' % response.code)

            if response.code == 200:
                try:
                    mtime = time.mktime(
                        time.strptime(response.getheader('Last-Modified'),
                                      "%a, %d %b %Y %H:%M:%S %Z"))

                except Exception:
                    debug.logger & debug.flagReader and debug.logger(
                        'malformed HTTP headers: %s' % sys.exc_info()[1])
                    mtime = time.time()

                debug.logger & debug.flagReader and debug.logger(
                    'fetching source MIB %s, mtime %s' %
                    (url, response.getheader('Last-Modified')))

                return MibInfo(path=url,
                               file=mibfile,
                               name=mibalias,
                               mtime=mtime), decode(
                                   response.read(self.maxMibSize))

        raise error.PySmiReaderFileNotFoundError('source MIB %s not found' %
                                                 mibname,
                                                 reader=self)
Ejemplo n.º 6
0
    def genCode(self, ast, symbolTable, **kwargs):
        self.genRules['text'] = kwargs.get('genTexts', False)
        self.textFilter = kwargs.get('textFilter') or (
            lambda symbol, text: re.sub('\s+', ' ', text))
        self.symbolTable = symbolTable
        self._rows.clear()
        self._cols.clear()
        self._exports.clear()
        self._seenSyms.clear()
        self._importMap.clear()
        self._out.clear()
        self._moduleIdentityOid = None
        self.moduleName[0], moduleOid, imports, declarations = ast

        out, importedModules = self.genImports(imports or {})

        for declr in declarations or []:
            if declr:
                clausetype = declr[0]
                classmode = clausetype == 'typeDeclaration'
                self.handlersTable[declr[0]](self,
                                             self.prepData(
                                                 declr[1:], classmode),
                                             classmode)

        for sym in self.symbolTable[self.moduleName[0]]['_symtable_order']:
            if sym not in self._out:
                raise error.PySmiCodegenError(
                    'No generated code for symbol %s' % sym)
            out += self._out[sym]

        out += self.genExports()

        if 'comments' in kwargs:
            out = ''.join(['# %s\n' % x
                           for x in kwargs['comments']]) + '#\n' + out
            out = '#\n# PySNMP MIB module %s (http://snmplabs.com/pysmi)\n' % self.moduleName[
                0] + out

        debug.logger & debug.flagCodegen and debug.logger(
            'canonical MIB name %s (%s), imported MIB(s) %s, Python code size %s bytes'
            % (self.moduleName[0], moduleOid, ','.join(importedModules)
               or '<none>', len(out)))

        return MibInfo(oid=moduleOid,
                       identity=self._moduleIdentityOid,
                       name=self.moduleName[0],
                       revision=self._moduleRevision,
                       oids=[],
                       enterprise=None,
                       compliance=[],
                       imported=tuple([
                           x for x in importedModules if x not in self.fakeMibs
                       ])), out
Ejemplo n.º 7
0
    def getData(self, mibname, **options):
        debug.logger & debug.flagReader and debug.logger(
            '%slooking for MIB %s' %
            (self._recursive and 'recursively ' or '', mibname))

        for path in self.getSubdirs(self._path, self._recursive,
                                    self._ignoreErrors):

            for mibalias, mibfile in self.getMibVariants(mibname, **options):
                f = os.path.join(decode(path), decode(mibfile))

                debug.logger & debug.flagReader and debug.logger(
                    'trying MIB %s' % f)

                if os.path.exists(f) and os.path.isfile(f):
                    try:
                        mtime = os.stat(f)[8]

                        debug.logger & debug.flagReader and debug.logger(
                            'source MIB %s mtime is %s, fetching data...' %
                            (f,
                             time.strftime("%a, %d %b %Y %H:%M:%S GMT",
                                           time.gmtime(mtime))))

                        fp = open(f, mode='rb')
                        mibData = fp.read(self.maxMibSize)
                        fp.close()

                        if len(mibData) == self.maxMibSize:
                            raise IOError('MIB %s too large' % f)

                        return MibInfo(path='file://%s' % f,
                                       file=mibfile,
                                       name=mibalias,
                                       mtime=mtime), decode(mibData)

                    except (OSError, IOError):
                        debug.logger & debug.flagReader and debug.logger(
                            'source file %s open failure: %s' %
                            (f, sys.exc_info()[1]))

                        if not self._ignoreErrors:
                            raise error.PySmiError('file %s access error: %s' %
                                                   (f, sys.exc_info()[1]))

                    raise error.PySmiReaderFileNotModifiedError(
                        'source MIB %s is older than needed' % f, reader=self)

        raise error.PySmiReaderFileNotFoundError('source MIB %s not found' %
                                                 mibname,
                                                 reader=self)
Ejemplo n.º 8
0
    def genCode(self, ast, symbolTable, **kwargs):
        self.genRules['text'] = kwargs.get('genTexts', False)
        self.textFilter = kwargs.get('textFilter') or (
            lambda symbol, text: re.sub('\s+', ' ', text))
        self.symbolTable = symbolTable
        self._rows.clear()
        self._cols.clear()
        self._seenSyms.clear()
        self._importMap.clear()
        self._out.clear()
        self._moduleIdentityOid = None
        self._enterpriseOid = None
        self._oids = set()
        self._complianceOids = []
        self.moduleName[0], moduleOid, imports, declarations = ast

        outDict, importedModules = self.genImports(imports and imports or {})

        for declr in declarations or []:
            if declr:
                self.handlersTable[declr[0]](self, self.prepData(declr[1:]))

        for sym in self.symbolTable[self.moduleName[0]]['_symtable_order']:
            if sym not in self._out:
                raise error.PySmiCodegenError(
                    'No generated code for symbol %s' % sym)

            outDict[sym] = self._out[sym]

        outDict['meta'] = OrderedDict()
        outDict['meta']['module'] = self.moduleName[0]

        if 'comments' in kwargs:
            outDict['meta']['comments'] = kwargs['comments']

        debug.logger & debug.flagCodegen and debug.logger(
            'canonical MIB name %s (%s), imported MIB(s) %s' %
            (self.moduleName[0], moduleOid, ','.join(importedModules)
             or '<none>'))

        return MibInfo(oid=moduleOid,
                       identity=self._moduleIdentityOid,
                       name=self.moduleName[0],
                       revision=self._moduleRevision,
                       oids=self._oids,
                       enterprise=self._enterpriseOid,
                       compliance=self._complianceOids,
                       imported=tuple([
                           x for x in importedModules if x not in self.fakeMibs
                       ])), outDict
Ejemplo n.º 9
0
 def genCode(self, ast, symbolTable, **kwargs):
     self.genRules['text'] = kwargs.get('genTexts', False)
     self.symbolTable = symbolTable
     out = ''
     importedModules = ()
     self._rows.clear()
     self._cols.clear()
     self._exports.clear()
     self._presentedSyms.clear()
     self._importMap.clear()
     self._out.clear()
     self.moduleName[0], moduleOid, imports, declarations = ast
     out, importModules = self.genImports(imports and imports or {})
     for declr in declarations and declarations or []:
         if declr:
             clausetype = declr[0]
             classmode = clausetype == 'typeDeclaration'
             self.handlersTable[declr[0]](self,
                                          self.prepData(
                                              declr[1:], classmode),
                                          classmode)
     for sym in self.symbolTable[self.moduleName[0]]['_symtable_order']:
         if sym not in self._out:
             raise error.PySmiCodegenError(
                 'No generated code for symbol %s' % sym)
         out += self._out[sym]
     out += self.genExports()
     if 'comments' in kwargs:
         out = ''.join(['# %s\n' % x
                        for x in kwargs['comments']]) + '#\n' + out
         out = '#\n# NetSnmp MIB module' + out
     debug.logger & debug.flagCodegen and debug.logger(
         'canonical MIB name %s (%s), imported MIB(s) %s, C code size %s bytes'
         % (self.moduleName[0], moduleOid, ','.join(importedModules)
            or '<none>', len(out)))
     return MibInfo(oid=None,
                    NameError=self.moduleName[0],
                    importedModules=tuple([
                        x for x in importedModules if x not in fakedMibs
                    ])), out
Ejemplo n.º 10
0
    def getData(self, mibname):
        if self._ssl:
            conn = ftplib.FTP_TLS()
        else:
            conn = ftplib.FTP()

        try:
            conn.connect(self._host, self._port, self._timeout)

        except ftplib.all_errors:
            raise error.PySmiReaderFileNotFoundError(
                'failed to connect to FTP server %s:%s: %s' %
                (self._host, self._port, sys.exc_info()[1]),
                reader=self)

        try:
            conn.login(self._user, self._password)

        except ftplib.all_errors:
            conn.close()
            raise error.PySmiReaderFileNotFoundError(
                'failed to log in to FTP server %s:%s as %s/%s: %s' %
                (self._host, self._port, self._user, self._password,
                 sys.exc_info()[1]),
                reader=self)

        mibname = decode(mibname)

        debug.logger & debug.flagReader and debug.logger(
            'looking for MIB %s' % mibname)

        for mibalias, mibfile in self.getMibVariants(mibname):
            location = self._locationTemplate.replace('@mib@', mibfile)

            mtime = time.time()

            debug.logger & debug.flagReader and debug.logger(
                'trying to fetch MIB %s from %s:%s' %
                (location, self._host, self._port))

            data = []

            try:
                try:
                    response = conn.sendcmd('MDTM %s' % location)

                except ftplib.all_errors:
                    debug.logger & debug.flagReader and debug.logger(
                        'server %s:%s does not support MDTM command, fetching file %s'
                        % (self._host, self._port, location))

                else:
                    debug.logger & debug.flagReader and debug.logger(
                        'server %s:%s MDTM response is %s' %
                        (self._host, self._port, response))

                    if response[:3] == 213:
                        mtime = time.mktime(
                            time.strptime(response[4:], "%Y%m%d%H%M%S"))

                debug.logger & debug.flagReader and debug.logger(
                    'fetching source MIB %s, mtime %s' %
                    (location,
                     time.strftime("%a, %d %b %Y %H:%M:%S GMT",
                                   time.gmtime(mtime))))

                conn.retrlines('RETR %s' % location,
                               lambda x, y=data: y.append(x))

            except ftplib.all_errors:
                debug.logger & debug.flagReader and debug.logger(
                    'failed to fetch MIB %s from %s:%s: %s' %
                    (location, self._host, self._port, sys.exc_info()[1]))
                continue

            data = decode('\n'.join(data))

            debug.logger & debug.flagReader and debug.logger(
                'fetched %s bytes in %s' % (len(data), location))

            conn.close()

            return MibInfo(path='ftp://%s%s' % (self._host, location),
                           file=mibfile,
                           name=mibalias,
                           mtime=mtime), data

        conn.close()

        raise error.PySmiReaderFileNotFoundError('source MIB %s not found' %
                                                 mibname,
                                                 reader=self)
Ejemplo n.º 11
0
 def genCode(self, ast, symbolTable, **kwargs):
     debug.logger & debug.flagCodegen and debug.logger(
         '%s invoked' % self.__class__.__name__)
     return MibInfo(oid=None, name='', imported=[]), ''
Ejemplo n.º 12
0
    def compile(self, *mibnames, **options):
        """Transform requested and possibly referred MIBs.

        The *compile* method should be invoked when *MibCompiler* object
        is operational meaning at least *sources* are specified.

        Once called with a MIB module name, *compile* will:

        * fetch ASN.1 MIB module with given name by calling *sources*
        * make sure no such transformed MIB already exists (with *searchers*)
        * parse ASN.1 MIB text with *parser*
        * perform actual MIB transformation into target format with *code generator*
        * may attempt to borrow pre-transformed MIB through *borrowers*
        * write transformed MIB through *writer*

        The above sequence will be performed for each MIB name given in
        *mibnames* and may be performed for all MIBs referred to from
        MIBs being processed.

        Args:
            mibnames: list of ASN.1 MIBs names
            options: options that affect the way PySMI components work

        Returns:
            A dictionary of MIB module names processed (keys) and *MibStatus*
            class instances (values)

        """
        processed = {}
        parsedMibs = {}
        failedMibs = {}
        borrowedMibs = {}
        builtMibs = {}
        symbolTableMap = {}
        mibsToParse = [x for x in mibnames]
        canonicalMibNames = {}

        while mibsToParse:
            mibname = mibsToParse.pop(0)

            if mibname in parsedMibs:
                debug.logger & debug.flagCompiler and debug.logger(
                    'MIB %s already parsed' % mibname)
                continue

            if mibname in failedMibs:
                debug.logger & debug.flagCompiler and debug.logger(
                    'MIB %s already failed' % mibname)
                continue

            for source in self._sources:
                debug.logger & debug.flagCompiler and debug.logger(
                    'trying source %s' % source)

                try:
                    fileInfo, fileData = source.getData(mibname)

                    for mibTree in self._parser.parse(fileData):
                        mibInfo, symbolTable = self._symbolgen.genCode(
                            mibTree, symbolTableMap)

                        symbolTableMap[mibInfo.name] = symbolTable

                        parsedMibs[mibInfo.name] = fileInfo, mibInfo, mibTree

                        if mibname in failedMibs:
                            del failedMibs[mibname]

                        mibsToParse.extend(mibInfo.imported)

                        if fileInfo.name in mibnames:
                            if mibInfo.name not in canonicalMibNames:
                                canonicalMibNames[mibInfo.name] = []
                            canonicalMibNames[mibInfo.name].append(
                                fileInfo.name)

                        debug.logger & debug.flagCompiler and debug.logger(
                            '%s (%s) read from %s, immediate dependencies: %s'
                            % (mibInfo.name, mibname, fileInfo.path,
                               ', '.join(mibInfo.imported) or '<none>'))

                    break

                except error.PySmiReaderFileNotFoundError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'no %s found at %s' % (mibname, source))
                    continue

                except error.PySmiError:
                    exc_class, exc, tb = sys.exc_info()
                    exc.source = source
                    exc.mibname = mibname
                    exc.msg += ' at MIB %s' % mibname

                    debug.logger & debug.flagCompiler and debug.logger(
                        '%serror %s from %s' %
                        (options.get('ignoreErrors') and 'ignoring '
                         or 'failing on ', exc, source))

                    failedMibs[mibname] = exc

                    processed[mibname] = statusFailed.setOptions(error=exc)

            else:
                exc = error.PySmiError('MIB source %s not found' % mibname)
                exc.mibname = mibname
                debug.logger & debug.flagCompiler and debug.logger(
                    'no %s found everywhere' % mibname)

                if mibname not in failedMibs:
                    failedMibs[mibname] = exc

                if mibname not in processed:
                    processed[mibname] = statusMissing

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs analyzed %s, MIBs failed %s' %
            (len(parsedMibs), len(failedMibs)))

        #
        # See what MIBs need generating
        #

        for mibname in tuple(parsedMibs):
            fileInfo, mibInfo, mibTree = parsedMibs[mibname]

            debug.logger & debug.flagCompiler and debug.logger(
                'checking if %s requires updating' % mibname)

            for searcher in self._searchers:
                try:
                    searcher.fileExists(mibname,
                                        fileInfo.mtime,
                                        rebuild=options.get('rebuild'))

                except error.PySmiFileNotFoundError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'no compiled MIB %s available through %s' %
                        (mibname, searcher))
                    continue

                except error.PySmiFileNotModifiedError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'will be using existing compiled MIB %s found by %s' %
                        (mibname, searcher))
                    del parsedMibs[mibname]
                    processed[mibname] = statusUntouched
                    break

                except error.PySmiError:
                    exc_class, exc, tb = sys.exc_info()
                    exc.searcher = searcher
                    exc.mibname = mibname
                    exc.msg += ' at MIB %s' % mibname
                    debug.logger & debug.flagCompiler and debug.logger(
                        'error from %s: %s' % (searcher, exc))
                    continue

            else:
                debug.logger & debug.flagCompiler and debug.logger(
                    'no suitable compiled MIB %s found anywhere' % mibname)

                if options.get('noDeps') and mibname not in canonicalMibNames:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'excluding imported MIB %s from code generation' %
                        mibname)
                    del parsedMibs[mibname]
                    processed[mibname] = statusUntouched
                    continue

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs parsed %s, MIBs failed %s' %
            (len(parsedMibs), len(failedMibs)))

        #
        # Generate code for parsed MIBs
        #

        for mibname in parsedMibs.copy():
            fileInfo, mibInfo, mibTree = parsedMibs[mibname]

            debug.logger & debug.flagCompiler and debug.logger(
                'compiling %s read from %s' % (mibname, fileInfo.path))

            platform_info, user_info = self._get_system_info()

            comments = [
                'ASN.1 source %s' % fileInfo.path,
                'Produced by %s-%s at %s' %
                (packageName, packageVersion, time.asctime()),
                'On host %s platform %s version %s by user %s' %
                (platform_info[1], platform_info[0], platform_info[2],
                 user_info[0]),
                'Using Python version %s' % sys.version.split('\n')[0]
            ]

            try:
                mibInfo, mibData = self._codegen.genCode(
                    mibTree,
                    symbolTableMap,
                    comments=comments,
                    genTexts=options.get('genTexts'),
                    textFilter=options.get('textFilter'))

                builtMibs[mibname] = fileInfo, mibInfo, mibData
                del parsedMibs[mibname]

                debug.logger & debug.flagCompiler and debug.logger(
                    '%s read from %s and compiled by %s' %
                    (mibname, fileInfo.path, self._writer))

            except error.PySmiError:
                exc_class, exc, tb = sys.exc_info()
                exc.handler = self._codegen
                exc.mibname = mibname
                exc.msg += ' at MIB %s' % mibname

                debug.logger & debug.flagCompiler and debug.logger(
                    'error from %s: %s' % (self._codegen, exc))

                processed[mibname] = statusFailed.setOptions(error=exc)

                failedMibs[mibname] = exc
                del parsedMibs[mibname]

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs built %s, MIBs failed %s' %
            (len(parsedMibs), len(failedMibs)))

        #
        # Try to borrow pre-compiled MIBs for failed ones
        #

        for mibname in failedMibs.copy():
            if options.get('noDeps') and mibname not in canonicalMibNames:
                debug.logger & debug.flagCompiler and debug.logger(
                    'excluding imported MIB %s from borrowing' % mibname)
                continue

            for borrower in self._borrowers:
                debug.logger & debug.flagCompiler and debug.logger(
                    'trying to borrow %s from %s' % (mibname, borrower))
                try:
                    fileInfo, fileData = borrower.getData(
                        mibname, genTexts=options.get('genTexts'))

                    borrowedMibs[mibname] = fileInfo, MibInfo(
                        name=mibname, imported=[]), fileData

                    del failedMibs[mibname]

                    debug.logger & debug.flagCompiler and debug.logger(
                        '%s borrowed with %s' % (mibname, borrower))
                    break

                except error.PySmiError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'error from %s: %s' % (borrower, sys.exc_info()[1]))

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs available for borrowing %s, MIBs failed %s' %
            (len(borrowedMibs), len(failedMibs)))

        #
        # See what MIBs need borrowing
        #

        for mibname in borrowedMibs.copy():
            debug.logger & debug.flagCompiler and debug.logger(
                'checking if failed MIB %s requires borrowing' % mibname)

            fileInfo, mibInfo, mibData = borrowedMibs[mibname]

            for searcher in self._searchers:
                try:
                    searcher.fileExists(mibname,
                                        fileInfo.mtime,
                                        rebuild=options.get('rebuild'))

                except error.PySmiFileNotFoundError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'no compiled MIB %s available through %s' %
                        (mibname, searcher))
                    continue

                except error.PySmiFileNotModifiedError:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'will be using existing compiled MIB %s found by %s' %
                        (mibname, searcher))
                    del borrowedMibs[mibname]
                    processed[mibname] = statusUntouched
                    break

                except error.PySmiError:
                    exc_class, exc, tb = sys.exc_info()
                    exc.searcher = searcher
                    exc.mibname = mibname
                    exc.msg += ' at MIB %s' % mibname

                    debug.logger & debug.flagCompiler and debug.logger(
                        'error from %s: %s' % (searcher, exc))

                    continue
            else:
                debug.logger & debug.flagCompiler and debug.logger(
                    'no suitable compiled MIB %s found anywhere' % mibname)

                if options.get('noDeps') and mibname not in canonicalMibNames:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'excluding imported MIB %s from borrowing' % mibname)
                    processed[mibname] = statusUntouched

                else:
                    debug.logger & debug.flagCompiler and debug.logger(
                        'will borrow MIB %s' % mibname)
                    builtMibs[mibname] = borrowedMibs[mibname]

                    processed[mibname] = statusBorrowed.setOptions(
                        path=fileInfo.path,
                        file=fileInfo.file,
                        alias=fileInfo.name)

                del borrowedMibs[mibname]

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs built %s, MIBs failed %s' %
            (len(builtMibs), len(failedMibs)))

        #
        # We could attempt to ignore missing/failed MIBs
        #

        if failedMibs and not options.get('ignoreErrors'):
            debug.logger & debug.flagCompiler and debug.logger(
                'failing with problem MIBs %s' % ', '.join(failedMibs))

            for mibname in builtMibs:
                processed[mibname] = statusUnprocessed

            return processed

        debug.logger & debug.flagCompiler and debug.logger(
            'proceeding with built MIBs %s, failed MIBs %s' %
            (', '.join(builtMibs), ', '.join(failedMibs)))

        #
        # Store compiled MIBs
        #

        for mibname in builtMibs.copy():
            fileInfo, mibInfo, mibData = builtMibs[mibname]

            try:
                if options.get('writeMibs', True):
                    self._writer.putData(mibname,
                                         mibData,
                                         dryRun=options.get('dryRun'))

                debug.logger & debug.flagCompiler and debug.logger(
                    '%s stored by %s' % (mibname, self._writer))

                del builtMibs[mibname]

                if mibname not in processed:
                    processed[mibname] = statusCompiled.setOptions(
                        path=fileInfo.path,
                        file=fileInfo.file,
                        alias=fileInfo.name,
                        oid=mibInfo.oid,
                        oids=mibInfo.oids,
                        identity=mibInfo.identity,
                        revision=mibInfo.revision,
                        enterprise=mibInfo.enterprise,
                        compliance=mibInfo.compliance,
                    )

            except error.PySmiError:
                exc_class, exc, tb = sys.exc_info()
                exc.handler = self._codegen
                exc.mibname = mibname
                exc.msg += ' at MIB %s' % mibname

                debug.logger & debug.flagCompiler and debug.logger(
                    'error %s from %s' % (exc, self._writer))

                processed[mibname] = statusFailed.setOptions(error=exc)
                failedMibs[mibname] = exc
                del builtMibs[mibname]

        debug.logger & debug.flagCompiler and debug.logger(
            'MIBs modified: %s' % ', '.join([
                x
                for x in processed if processed[x] in ('compiled', 'borrowed')
            ]))

        return processed