makeapi, makeaci: do not fail on missing imports

Add import hook to makeapi and makeaci which makes them ignore import
errors in modules in our source tree and instead print a warning.

This makes it possible to build IPA without having to have most of our
runtime dependencies installed.

https://fedorahosted.org/freeipa/ticket/6418

Reviewed-By: Petr Spacek <pspacek@redhat.com>
Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Jan Cholasta 2016-08-24 13:36:12 +02:00 committed by David Kupka
parent 0b91735c79
commit 9b53423815
4 changed files with 102 additions and 11 deletions

View File

@ -89,22 +89,11 @@ BuildRequires: python-lesscpy
#
BuildRequires: krb5-workstation
BuildRequires: python-ldap
BuildRequires: python-setuptools
BuildRequires: python-nss
# 0.6: serialization.load_pem_private_key, load_pem_public_key
BuildRequires: python-cryptography >= 0.6
BuildRequires: python-netaddr
BuildRequires: python-gssapi
BuildRequires: python-libipa_hbac
BuildRequires: python-memcached
BuildRequires: python-lxml
BuildRequires: python-pyasn1
BuildRequires: python-dns
# pki Python package
BuildRequires: pki-base
BuildRequires: python-six
BuildRequires: dbus-python
BuildRequires: python-netifaces
BuildRequires: python-libsss_nss_idmap
BuildRequires: python-cffi
@ -113,22 +102,32 @@ BuildRequires: python-cffi
#
%if 0%{?with_lint}
BuildRequires: samba-python
BuildRequires: python-setuptools
# 0.6: serialization.load_pem_private_key, load_pem_public_key
BuildRequires: python-cryptography >= 0.6
BuildRequires: python-gssapi
BuildRequires: pylint >= 1.0
# workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1096506
BuildRequires: python2-polib
BuildRequires: python-libipa_hbac
BuildRequires: python-memcached
BuildRequires: python-lxml
# 5.0.0: QRCode.print_ascii
BuildRequires: python-qrcode-core >= 5.0.0
# 1.11.0: resolver.YXDOMAIN, Resolver.set_flags
BuildRequires: python-dns >= 1.11.0
BuildRequires: jsl
BuildRequires: python-yubico
# pki Python package
# 10.2.1: crypto.NSSCryptoProvider(password_file)
BuildRequires: pki-base >= 10.2.1
BuildRequires: python-pytest-multihost
BuildRequires: python-pytest-sourceorder
BuildRequires: python-jwcrypto
BuildRequires: python-custodia
BuildRequires: dbus-python
BuildRequires: python-dateutil
BuildRequires: python-netifaces
BuildRequires: python-sss
BuildRequires: python-sss-murmur
BuildRequires: python-sssdconfig

87
ignore_import_errors.py Normal file
View File

@ -0,0 +1,87 @@
#
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
"""
ImportError ignoring import hook.
"""
from __future__ import print_function
import imp
import inspect
import os.path
import sys
DIRNAME = os.path.dirname(os.path.abspath(__file__))
class FailedImport(object):
def __init__(self, loader, name):
self.__file__ = __file__
self.__name__ = name
self.__path__ = []
self.__loader__ = loader
self.__package__ = name
def __repr__(self):
return '<failed import {!r}>'.format(self.__name__)
class IgnoringImporter(object):
def find_module(self, fullname, path=None):
parentname, dot, name = fullname.rpartition('.')
assert (not dot and path is None) or (dot and path is not None)
# check if the module can be found
try:
file, _filename, _description = imp.find_module(name, path)
except ImportError:
pass
else:
if file is not None:
file.close()
# it can be found, do normal import
return None
# check if the parent module import failed
if dot and isinstance(sys.modules[parentname], FailedImport):
# it did fail, so this import will fail as well
return self
# find out from where are we importing
if path is None:
path = sys.path
for pathname in path:
pathname = os.path.abspath(pathname)
if not pathname.startswith(DIRNAME):
break
else:
# importing from our source tree, do normal import
return None
# find out into what .py file are we importing
frame = inspect.currentframe().f_back
filename = frame.f_code.co_filename
if filename.startswith('<'):
# not a file, do normal import
return None
filename = os.path.abspath(filename)
if not filename.startswith(DIRNAME):
# not a file in our source tree, do normal import
return None
return self
def load_module(self, fullname):
frame = inspect.currentframe().f_back
print("{}: {}:{}: ignoring ImportError: No module named {}".format(
sys.argv[0],
os.path.relpath(frame.f_code.co_filename),
frame.f_lineno,
fullname))
return sys.modules.setdefault(fullname, FailedImport(self, fullname))
sys.meta_path.insert(0, IgnoringImporter())

View File

@ -30,6 +30,8 @@ import sys
import difflib
from argparse import ArgumentParser
import ignore_import_errors # pylint: disable=unused-import
from ipalib import api
from ipapython.dn import DN
from ipapython.ipaldap import LDAPClient

View File

@ -32,6 +32,9 @@ import os
import re
import inspect
import operator
import ignore_import_errors # pylint: disable=unused-import
from ipalib import api
from ipalib.parameters import Param
from ipalib.output import Output