summaryrefslogtreecommitdiff
path: root/gr-utils/python/modtool/core/base.py
diff options
context:
space:
mode:
authorSwapnil Negi <swapnil.negi09@gmail.com>2019-01-04 18:29:50 +0100
committerAndrej Rode <mail@andrejro.de>2019-01-04 18:58:02 +0100
commit055287896c8c97eb0cdda825559e217d8db54a14 (patch)
tree613262f5ed45ba4eaadf1bd76009aa16ad22806f /gr-utils/python/modtool/core/base.py
parent2fcf3b8afe51092003b7f916edb9e5d6372d4842 (diff)
modtool: gr-modtool overhaul GSoC 2018
This commit contains all the changes done during the 2018 GSoC "gr-modtool overhaul". Changes include: - Rewrite of gr-modtool based on Python Click - Split of gr-modtool in cli and core - Adherence to new GNU Radio 3.8 API for OOTs - Pylint improvements - Py3k and Py2k compatibility This feature is merged in a squash-merge due to big refactoring on the head and base branch and the impossibility to unclutter both.
Diffstat (limited to 'gr-utils/python/modtool/core/base.py')
-rw-r--r--gr-utils/python/modtool/core/base.py214
1 files changed, 214 insertions, 0 deletions
diff --git a/gr-utils/python/modtool/core/base.py b/gr-utils/python/modtool/core/base.py
new file mode 100644
index 0000000000..5d133892e6
--- /dev/null
+++ b/gr-utils/python/modtool/core/base.py
@@ -0,0 +1,214 @@
+#
+# Copyright 2013, 2018 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+""" Base class for the modules """
+
+from __future__ import print_function
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import os
+import re
+import glob
+import logging
+import itertools
+from types import SimpleNamespace
+
+from gnuradio import gr
+from ..tools import get_modname, SCMRepoFactory
+from ..cli import setup_cli_logger
+
+logger = logging.getLogger('gnuradio.modtool')
+
+
+def get_block_candidates():
+ """ Returns a list of all possible blocknames """
+ block_candidates = []
+ cpp_filters = ["*.cc", "*.cpp"]
+ cpp_blocks = []
+ for ftr in cpp_filters:
+ cpp_blocks += [x for x in glob.glob1("lib", ftr) if not (x.startswith('qa_') or
+ x.startswith('test_'))]
+ python_blocks = [x for x in glob.glob1("python", "*.py") if not (x.startswith('qa_') or
+ x.startswith('build') or x.startswith('__init__'))]
+ for block in itertools.chain(cpp_blocks, python_blocks):
+ block = os.path.splitext(block)[0]
+ block = block.split('_impl')[0]
+ block_candidates.append(block)
+ return block_candidates
+
+
+class ModToolException(Exception):
+ """ Standard exception for modtool classes. """
+ pass
+
+
+class ModTool(object):
+ """ Base class for all modtool command classes. """
+ name = 'base'
+ description = None
+
+ def __init__(self, blockname=None, module_name=None, **kwargs):
+ # List subdirs where stuff happens
+ self._subdirs = ['lib', 'include', 'python', 'swig', 'grc']
+ self.has_subdirs = {}
+ self.skip_subdirs = {}
+ self.info = {}
+ self._file = {}
+ for subdir in self._subdirs:
+ self.has_subdirs[subdir] = False
+ self.skip_subdirs[subdir] = False
+ self.info['blockname'] = blockname
+ self.info['modname'] = module_name
+ self.cli = kwargs.get('cli', False)
+ self.dir = kwargs.get('directory', '.')
+ self.skip_subdirs['lib'] = kwargs.get('skip_lib', False)
+ self.skip_subdirs['python'] = kwargs.get('skip_python', False)
+ self.skip_subdirs['swig'] = kwargs.get('skip_swig', False)
+ self.skip_subdirs['grc'] = kwargs.get('skip_grc', False)
+ self._scm = kwargs.get('scm_mode',
+ gr.prefs().get_string('modtool', 'scm_mode', 'no'))
+ if not self.cli:
+ logging.basicConfig(level=logging.ERROR, format='%(message)s')
+ self.info['yes'] = True
+ else:
+ self.info['yes'] = kwargs.get('yes', False)
+ setup_cli_logger(logger)
+
+ if not type(self).__name__ in ['ModToolInfo', 'ModToolNewModule']:
+ if self.cli:
+ self._validate()
+
+ def _validate(self):
+ """ Validates the arguments """
+ if not isinstance(self.skip_subdirs['lib'], bool):
+ raise ModToolException('Expected a boolean value for skip_lib')
+ if not isinstance(self.skip_subdirs['swig'], bool):
+ raise ModToolException('Expected a boolean value for skip_swig')
+ if not isinstance(self.skip_subdirs['python'], bool):
+ raise ModToolException('Expected a boolean value for skip_python')
+ if not isinstance(self.skip_subdirs['grc'], bool):
+ raise ModToolException('Expected a boolean value for skip_grc')
+ self._assign()
+
+ def _assign(self):
+ if not self._check_directory(self.dir):
+ raise ModToolException('No GNU Radio module found in the given directory.')
+ if self.info['modname'] is None:
+ self.info['modname'] = get_modname()
+ if self.info['modname'] is None:
+ raise ModToolException('No GNU Radio module found in the given directory.')
+ if self.info['version'] == '36' and (
+ os.path.isdir(os.path.join('include', self.info['modname'])) or
+ os.path.isdir(os.path.join('include', 'gnuradio', self.info['modname']))
+ ):
+ self.info['version'] = '37'
+ if not os.path.isfile(os.path.join('cmake', 'Modules', 'FindCppUnit.cmake')):
+ self.info['version'] = '38'
+ if self.skip_subdirs['lib'] or not self.has_subdirs['lib']:
+ self.skip_subdirs['lib'] = True
+ if not self.has_subdirs['python']:
+ self.skip_subdirs['python'] = True
+ if self._get_mainswigfile() is None or not self.has_subdirs['swig']:
+ self.skip_subdirs['swig'] = True
+ if not self.has_subdirs['grc']:
+ self.skip_subdirs['grc'] = True
+
+ self._setup_files()
+ self._setup_scm()
+
+ def _setup_files(self):
+ """ Initialise the self._file[] dictionary """
+ if not self.skip_subdirs['swig']:
+ self._file['swig'] = os.path.join('swig', self._get_mainswigfile())
+ self.info['pydir'] = 'python'
+ if os.path.isdir(os.path.join('python', self.info['modname'])):
+ self.info['pydir'] = os.path.join('python', self.info['modname'])
+ self._file['qalib'] = os.path.join('lib', 'qa_{}.cc'.format(self.info['modname']))
+ self._file['pyinit'] = os.path.join(self.info['pydir'], '__init__.py')
+ self._file['cmlib'] = os.path.join('lib', 'CMakeLists.txt')
+ self._file['cmgrc'] = os.path.join('grc', 'CMakeLists.txt')
+ self._file['cmpython'] = os.path.join(self.info['pydir'], 'CMakeLists.txt')
+ if self.info['is_component']:
+ self.info['includedir'] = os.path.join('include', 'gnuradio', self.info['modname'])
+ elif self.info['version'] in ('37', '38'):
+ self.info['includedir'] = os.path.join('include', self.info['modname'])
+ else:
+ self.info['includedir'] = 'include'
+ self._file['cminclude'] = os.path.join(self.info['includedir'], 'CMakeLists.txt')
+ self._file['cmswig'] = os.path.join('swig', 'CMakeLists.txt')
+ self._file['cmfind'] = os.path.join('cmake', 'Modules', 'howtoConfig.cmake')
+
+
+ def _setup_scm(self, mode='active'):
+ """ Initialize source control management. """
+ self.options = SimpleNamespace(scm_mode = self._scm)
+ if mode == 'active':
+ self.scm = SCMRepoFactory(self.options, '.').make_active_scm_manager()
+ else:
+ self.scm = SCMRepoFactory(self.options, '.').make_empty_scm_manager()
+ if self.scm is None:
+ logger.error("Error: Can't set up SCM.")
+ exit(1)
+
+ def _check_directory(self, directory):
+ """ Guesses if dir is a valid GNU Radio module directory by looking for
+ CMakeLists.txt and at least one of the subdirs lib/, python/ and swig/.
+ Changes the directory, if valid. """
+ has_makefile = False
+ try:
+ files = os.listdir(directory)
+ os.chdir(directory)
+ except OSError:
+ logger.error("Can't read or chdir to directory {}.".format(directory))
+ return False
+ self.info['is_component'] = False
+ for f in files:
+ if os.path.isfile(f) and f == 'CMakeLists.txt':
+ with open(f) as filetext:
+ if re.search('find_package\(Gnuradio', filetext.read()) is not None:
+ self.info['version'] = '36' # Might be 37, check that later
+ has_makefile = True
+ elif re.search('GR_REGISTER_COMPONENT', filetext.read()) is not None:
+ self.info['version'] = '36' # Might be 37, check that later
+ self.info['is_component'] = True
+ has_makefile = True
+ # TODO search for autofoo
+ elif os.path.isdir(f):
+ if (f in list(self.has_subdirs.keys())):
+ self.has_subdirs[f] = True
+ else:
+ self.skip_subdirs[f] = True
+ return bool(has_makefile and (list(self.has_subdirs.values())))
+
+ def _get_mainswigfile(self):
+ """ Find out which name the main SWIG file has. In particular, is it
+ a MODNAME.i or a MODNAME_swig.i? Returns None if none is found. """
+ modname = self.info['modname']
+ swig_files = (modname + '.i',
+ modname + '_swig.i')
+ for fname in swig_files:
+ if os.path.isfile(os.path.join(self.dir, 'swig', fname)):
+ return fname
+ return None
+
+ def run(self):
+ """ Override this. """
+ raise NotImplementedError('Module implementation missing')