Move check_dependencies.py to contrib/

Change-Id: I8def867b1042cbb98bb36ff4a473b4cdb92ce122
diff --git a/contrib/check_dependencies.py b/contrib/check_dependencies.py
new file mode 100755
index 0000000..61d08b0
--- /dev/null
+++ b/contrib/check_dependencies.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+
+# just import all python3 modules used by osmo-gsm-tester to make sure they are
+# installed.
+
+
+
+import os
+import sys
+import argparse
+import pprint
+import subprocess
+
+feature_module_map = {
+    '2g': ['bsc_osmo', 'bts_nanobts', 'bts_oc2g', 'bts_octphy', 'bts_osmo', 'bts_osmotrx', 'bts_osmovirtual', 'bts_sysmo', 'bts', 'bts', 'esme', 'ggsn_osmo', 'hlr_osmo', 'mgcpgw_osmo', 'mgw_osmo', 'ms_ofono', 'ms_driver', 'msc_osmo', 'nitb_osmo', 'osmo_ctrl', 'osmocon', 'pcap_recorder', 'pcu_oc2g', 'pcu_osmo', 'pcu_sysmo', 'pcu', 'sgsn_osmo', 'sms', 'smsc', 'stp_osmo'],
+    '4g': [],
+    'srs': ['enb_srs', 'epc_srs', 'ms_srs'],
+    'powersupply': ['powersupply', 'powersupply_intellinet', 'powersupply_sispm'],
+    'rfemu': ['rfemu', 'rfemu_amarisoftctrl', 'rfemu_minicircuits'],
+}
+
+def skip_features_to_skip_modules(skip_features):
+    skip_obj_modules = []
+
+    for skip_feature in skip_features:
+        if skip_feature in feature_module_map:
+            for skip_module in feature_module_map[skip_feature]:
+                skip_obj_modules.append(skip_module)
+        else:
+            skip_obj_modules.append(skip_feature)
+    return skip_obj_modules
+
+def import_runtime_dependencies():
+    # we don't have any right now, but in the future if we import a module during runtime (eg inside a function), then we need to place it here:
+    # import foobar
+    pass
+
+def import_all_py_in_dir(rel_path, skip_modules=[]):
+    selfdir = os.getcwd()
+    dir = os.path.join(selfdir, rel_path)
+    print('importing files in directory %s' % dir)
+    for entry in os.listdir(dir):
+        full_entry = os.path.join(selfdir, rel_path, entry)
+        if not os.path.isfile(full_entry):
+            if args.verbose:
+                print('skipping entry %s' % full_entry)
+            continue
+        if not full_entry.endswith('.py'):
+            if args.verbose:
+                print('skipping file %s' % full_entry)
+            continue
+        modulename =  entry[:-3]
+        if modulename in skip_modules:
+            if args.verbose:
+                print('skipping module %s' % modulename)
+            continue
+        modulepath = rel_path.replace('/', '.') + '.' + modulename
+        print('importing %s' % modulepath)
+        __import__(modulepath, globals(), locals())
+
+def get_module_names():
+    all_modules=sys.modules.items()
+    all_modules_filtered = {}
+    for mname, m in all_modules:
+        if not hasattr(m, '__file__'):
+            continue # skip built-in modules
+        if mname.startswith('_'):
+            continue # skip internal modules
+        if mname.startswith('src.osmo_') or 'osmo_gsm_tester' in mname or 'osmo_ms_driver' in mname:
+            continue # skip our own local modules
+        mname = mname.split('.')[0] # store only main module
+        if m not in all_modules_filtered.values():
+            all_modules_filtered[mname] = m
+    return all_modules_filtered
+
+def print_deb_packages(modules):
+    packages_deb = []
+    modules_err = []
+    for mname, m in modules.items():
+        proc = subprocess.Popen(["dpkg", "-S", m.__file__], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        outs, errs = proc.communicate()
+        if args.verbose:
+            print('out: %s, err: %s' %(outs, errs))
+        if len(errs): # error -> package not found (installed through pip?)
+            modules_err.append((mname, errs.decode('utf-8')))
+        elif len(outs):
+            outs = outs.decode('utf-8')
+            outs = outs.split()[0].rstrip(':') # first part is debian package name
+            if not outs in packages_deb:
+                packages_deb.append(outs)
+        else:
+            print('WARNING: dpkg returns empty!')
+
+    print('Debian packages:')
+    for pkgname in packages_deb:
+        print("\t" + pkgname)
+    print()
+    print('Modules without debian package (pip or setuptools?):')
+    for mname, err in modules_err:
+        print("\t" + mname.ljust(20) + " [" + err.rstrip() +"]")
+
+parser = argparse.ArgumentParser(epilog=__doc__, formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument('-s', '--skip-feature', dest='skip_features', action='append',
+                    help='''All osmo-gsm-tester features not used by the user running the script''')
+parser.add_argument('-p', '--distro-packages', dest='distro_packages', action='store_true',
+        help='Print distro packages installing modules')
+parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
+        help='Print a lot more information')
+args = parser.parse_args()
+
+skip_obj_modules = skip_features_to_skip_modules(list(args.skip_features or []))
+
+print('Skip checking modules: %r' % skip_obj_modules)
+
+rootdir = os.path.realpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+print('Changing workdir dir to %s' % rootdir)
+os.chdir(rootdir)
+sys.path.insert(0, rootdir)
+# We need to add it for cross-references between osmo_ms_driver and osmo_gsm_tester to work:
+sys.path.insert(0, os.path.join(rootdir, 'src/'))
+import_all_py_in_dir('src/osmo_ms_driver')
+import_all_py_in_dir('src/osmo_gsm_tester/core')
+import_all_py_in_dir('src/osmo_gsm_tester/obj', skip_obj_modules)
+import_all_py_in_dir('src/osmo_gsm_tester')
+import_runtime_dependencies()
+print('Importing dependencies ok, all installed')
+
+print('Retreiving list of imported modules...')
+modules = get_module_names()
+if args.verbose:
+    for mname, m in modules.items():
+        print('%s --> %s' %(mname, m.__file__))
+
+if args.distro_packages:
+    print('Generating distro package list from imported module list...')
+    print_deb_packages(modules)