diff options
Diffstat (limited to 'gr-utils/python/modtool/core')
-rw-r--r-- | gr-utils/python/modtool/core/CMakeLists.txt | 22 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/__init__.py | 22 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/add.py | 307 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/base.py | 202 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/disable.py | 161 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/info.py | 132 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/makeyaml.py | 353 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/newmod.py | 89 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/rename.py | 175 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/rm.py | 167 | ||||
-rw-r--r-- | gr-utils/python/modtool/core/update.py | 101 |
11 files changed, 0 insertions, 1731 deletions
diff --git a/gr-utils/python/modtool/core/CMakeLists.txt b/gr-utils/python/modtool/core/CMakeLists.txt deleted file mode 100644 index 764e79d09c..0000000000 --- a/gr-utils/python/modtool/core/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -include(GrPython) - -GR_PYTHON_INSTALL(FILES - __init__.py - add.py - base.py - disable.py - info.py - makeyaml.py - newmod.py - rm.py - rename.py - update.py - DESTINATION ${GR_PYTHON_DIR}/gnuradio/modtool/core -) diff --git a/gr-utils/python/modtool/core/__init__.py b/gr-utils/python/modtool/core/__init__.py deleted file mode 100644 index 5f89eee30f..0000000000 --- a/gr-utils/python/modtool/core/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright 2013-2014, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -from .base import ModTool, ModToolException, get_block_candidates -from .add import ModToolAdd -from .disable import ModToolDisable -from .info import ModToolInfo -from .makeyaml import ModToolMakeYAML, yaml_generator -from .newmod import ModToolNewModule -from .rm import ModToolRemove -from .rename import ModToolRename -from .update import ModToolUpdate, get_xml_candidates diff --git a/gr-utils/python/modtool/core/add.py b/gr-utils/python/modtool/core/add.py deleted file mode 100644 index adacb1ef90..0000000000 --- a/gr-utils/python/modtool/core/add.py +++ /dev/null @@ -1,307 +0,0 @@ -# -# Copyright 2013-2014,2017-2019 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Module to add new blocks """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import logging - -from ..tools import render_template, append_re_line_sequence, CMakeFileEditor -from ..templates import Templates -from .base import ModTool, ModToolException - -logger = logging.getLogger(__name__) - - -class ModToolAdd(ModTool): - """ Add block to the out-of-tree module. """ - name = 'add' - description = 'Add new block into a module.' - block_types = ('sink', 'source', 'sync', 'decimator', 'interpolator', - 'general', 'tagged_stream', 'hier', 'noblock') - language_candidates = ('cpp', 'python', 'c++') - - def __init__(self, blockname=None, block_type=None, lang=None, copyright=None, - license_file=None, argument_list="", add_python_qa=False, - add_cpp_qa=False, skip_cmakefiles=False, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['blocktype'] = block_type - self.info['lang'] = lang - self.license_file = license_file - self.info['copyrightholder'] = copyright - self.info['arglist'] = argument_list - self.add_py_qa = add_python_qa - self.add_cc_qa = add_cpp_qa - self.skip_cmakefiles = skip_cmakefiles - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if self.info['blocktype'] is None: - raise ModToolException('Blocktype not specified.') - if self.info['blocktype'] not in self.block_types: - raise ModToolException('Invalid blocktype') - if self.info['lang'] is None: - raise ModToolException('Programming language not specified.') - if self.info['lang'] not in self.language_candidates: - raise ModToolException('Invalid programming language.') - if self.info['blocktype'] == 'tagged_stream' and self.info['lang'] == 'python': - raise ModToolException('Tagged Stream Blocks for Python currently unsupported') - if self.info['blockname'] is None: - raise ModToolException('Blockname not specified.') - if not re.match('^[a-zA-Z0-9_]+$', self.info['blockname']): - raise ModToolException('Invalid block name.') - if not isinstance(self.add_py_qa, bool): - raise ModToolException('Expected a boolean value for add_python_qa.') - if not isinstance(self.add_cc_qa, bool): - raise ModToolException('Expected a boolean value for add_cpp_qa.') - if not isinstance(self.skip_cmakefiles, bool): - raise ModToolException('Expected a boolean value for skip_cmakefiles.') - - def assign(self): - if self.info['lang'] == 'c++': - self.info['lang'] = 'cpp' - if ((self.skip_subdirs['lib'] and self.info['lang'] == 'cpp') - or (self.skip_subdirs['python'] and self.info['lang'] == 'python')): - raise ModToolException('Missing or skipping relevant subdir.') - self.info['fullblockname'] = self.info['modname'] + '_' + self.info['blockname'] - if not self.license_file: - if self.info['copyrightholder'] is None: - self.info['copyrightholder'] = '<+YOU OR YOUR COMPANY+>' - self.info['license'] = self.setup_choose_license() - if (self.info['blocktype'] in ('noblock') or self.skip_subdirs['python']): - self.add_py_qa = False - if not self.info['lang'] == 'cpp': - self.add_cc_qa = False - if self.info['version'] == 'autofoo' and not self.skip_cmakefiles: - self.skip_cmakefiles = True - - def setup_choose_license(self): - """ Select a license by the following rules, in this order: - 1) The contents of the file given by --license-file - 2) The contents of the file LICENSE or LICENCE in the modules - top directory - 3) The default license. """ - if self.license_file is not None \ - and os.path.isfile(self.license_file): - with open(self.license_file) as f: - return f.read() - elif os.path.isfile('LICENSE'): - with open('LICENSE') as f: - return f.read() - elif os.path.isfile('LICENCE'): - with open('LICENCE') as f: - return f.read() - elif self.info['is_component']: - return Templates['grlicense'] - else: - return Templates['defaultlicense'].format(**self.info) - - def _write_tpl(self, tpl, path, fname): - """ Shorthand for writing a substituted template to a file""" - path_to_file = os.path.join(path, fname) - logger.info("Adding file '{}'...".format(path_to_file)) - with open(path_to_file, 'w') as f: - f.write(render_template(tpl, **self.info)) - self.scm.add_files((path_to_file,)) - - def run(self): - """ Go, go, go. """ - - # Some validation covered by the CLI - validate all parameters here - self.validate() - self.assign() - - has_swig = ( - self.info['lang'] == 'cpp' - and not self.skip_subdirs['swig'] - ) - has_grc = False - if self.info['lang'] == 'cpp': - self._run_lib() - has_grc = has_swig - else: # Python - self._run_python() - if self.info['blocktype'] != 'noblock': - has_grc = True - if has_swig: - self._run_swig() - if self.add_py_qa: - self._run_python_qa() - if has_grc and not self.skip_subdirs['grc']: - self._run_grc() - - def _run_cc_qa(self): - " Add C++ QA files for 3.7 API if intructed from _run_lib" - fname_qa_h = 'qa_{}.h'.format(self.info['blockname']) - fname_qa_cc = 'qa_{}.cc'.format(self.info['blockname']) - self._write_tpl('qa_cpp', 'lib', fname_qa_cc) - self._write_tpl('qa_h', 'lib', fname_qa_h) - if self.skip_cmakefiles: - return - try: - append_re_line_sequence(self._file['cmlib'], - r'list\(APPEND test_{}_sources.*\n'.format(self.info['modname']), - 'qa_{}.cc'.format(self.info['blockname'])) - append_re_line_sequence(self._file['qalib'], - '#include.*\n', - '#include "{}"'.format(fname_qa_h)) - append_re_line_sequence(self._file['qalib'], - '(addTest.*suite.*\n|new CppUnit.*TestSuite.*\n)', - ' s->addTest(gr::{}::qa_{}::suite());'.format(self.info['modname'], - self.info['blockname']) - ) - self.scm.mark_files_updated((self._file['qalib'],)) - except IOError: - logger.warning("Can't add C++ QA files.") - - def _run_cc_qa_boostutf(self): - " Add C++ QA files for 3.8 API if intructed from _run_lib" - fname_qa_cc = 'qa_{}.cc'.format(self.info['blockname']) - self._write_tpl('qa_cpp_boostutf', 'lib', fname_qa_cc) - if self.skip_cmakefiles: - return - try: - append_re_line_sequence(self._file['cmlib'], - r'list\(APPEND test_{}_sources.*\n'.format(self.info['modname']), - 'qa_{}.cc'.format(self.info['blockname'])) - self.scm.mark_files_updated((self._file['cmlib'],)) - except IOError: - logger.warning("Can't add C++ QA files.") - - def _run_lib(self): - """ Do everything that needs doing in the subdir 'lib' and 'include'. - - add .cc and .h files - - include them into CMakeLists.txt - - check if C++ QA code is req'd - - if yes, create qa_*.{cc,h} and add them to CMakeLists.txt - """ - fname_cc = None - fname_h = None - if self.info['version'] in ('37', '38'): - fname_h = self.info['blockname'] + '.h' - fname_cc = self.info['blockname'] + '.cc' - if self.info['blocktype'] in ('source', 'sink', 'sync', 'decimator', - 'interpolator', 'general', 'hier', 'tagged_stream'): - fname_cc = self.info['blockname'] + '_impl.cc' - self._write_tpl('block_impl_h', 'lib', self.info['blockname'] + '_impl.h') - self._write_tpl('block_impl_cpp', 'lib', fname_cc) - self._write_tpl('block_def_h', self.info['includedir'], fname_h) - else: # Pre-3.7 or autotools - fname_h = self.info['fullblockname'] + '.h' - fname_cc = self.info['fullblockname'] + '.cc' - self._write_tpl('block_h36', self.info['includedir'], fname_h) - self._write_tpl('block_cpp36', 'lib', fname_cc) - if self.add_cc_qa: - if self.info['version'] == '38': - self._run_cc_qa_boostutf() - elif self.info['version'] == '37': - self._run_cc_qa() - elif self.info['version'] == '36': - logger.warning("Warning: C++ QA files not supported for 3.6-style OOTs.") - elif self.info['version'] == 'autofoo': - logger.warning("Warning: C++ QA files not supported for autotools.") - if not self.skip_cmakefiles: - ed = CMakeFileEditor(self._file['cmlib']) - cmake_list_var = '[a-z]*_?' + self.info['modname'] + '_sources' - if not ed.append_value('list', fname_cc, to_ignore_start='APPEND ' + cmake_list_var): - ed.append_value('add_library', fname_cc) - ed.write() - ed = CMakeFileEditor(self._file['cminclude']) - ed.append_value('install', fname_h, to_ignore_end='DESTINATION[^()]+') - ed.write() - self.scm.mark_files_updated((self._file['cminclude'], self._file['cmlib'])) - - def _run_swig(self): - """ Do everything that needs doing in the subdir 'swig'. - - Edit main *.i file - """ - if self._get_mainswigfile() is None: - logger.warning('Warning: No main swig file found.') - return - logger.info("Editing {}...".format(self._file['swig'])) - mod_block_sep = '/' - if self.info['version'] == '36': - mod_block_sep = '_' - swig_block_magic_str = render_template('swig_block_magic', **self.info) - with open(self._file['swig'], 'a') as f: - f.write(swig_block_magic_str) - include_str = '#include "{}{}{}.h"'.format( - {True: 'gnuradio/' + self.info['modname'], False: self.info['modname']}[self.info['is_component']], - mod_block_sep, - self.info['blockname']) - with open(self._file['swig'], 'r') as f: - oldfile = f.read() - if re.search('#include', oldfile): - append_re_line_sequence(self._file['swig'], '^#include.*\n', include_str) - else: # I.e., if the swig file is empty - regexp = re.compile(r'^%\{\n', re.MULTILINE) - oldfile = regexp.sub('%%{\n%s\n' % include_str, oldfile, count=1) - with open(self._file['swig'], 'w') as f: - f.write(oldfile) - self.scm.mark_files_updated((self._file['swig'],)) - - def _run_python_qa(self): - """ Do everything that needs doing in the subdir 'python' to add - QA code. - - add .py files - - include in CMakeLists.txt - """ - fname_py_qa = 'qa_' + self.info['blockname'] + '.py' - self._write_tpl('qa_python', self.info['pydir'], fname_py_qa) - os.chmod(os.path.join(self.info['pydir'], fname_py_qa), 0o755) - self.scm.mark_files_updated((os.path.join(self.info['pydir'], fname_py_qa),)) - if self.skip_cmakefiles or CMakeFileEditor(self._file['cmpython']).check_for_glob('qa_*.py'): - return - logger.info("Editing {}/CMakeLists.txt...".format(self.info['pydir'])) - with open(self._file['cmpython'], 'a') as f: - f.write( - 'GR_ADD_TEST(qa_%s ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/%s)\n' % \ - (self.info['blockname'], fname_py_qa)) - self.scm.mark_files_updated((self._file['cmpython'],)) - - def _run_python(self): - """ Do everything that needs doing in the subdir 'python' to add - a Python block. - - add .py file - - include in CMakeLists.txt - - include in __init__.py - """ - fname_py = self.info['blockname'] + '.py' - self._write_tpl('block_python', self.info['pydir'], fname_py) - append_re_line_sequence(self._file['pyinit'], - '(^from.*import.*\n|# import any pure.*\n)', - 'from .{} import {}'.format(self.info['blockname'], self.info['blockname'])) - self.scm.mark_files_updated((self._file['pyinit'],)) - if self.skip_cmakefiles: - return - ed = CMakeFileEditor(self._file['cmpython']) - ed.append_value('GR_PYTHON_INSTALL', fname_py, to_ignore_end='DESTINATION[^()]+') - ed.write() - self.scm.mark_files_updated((self._file['cmpython'],)) - - def _run_grc(self): - """ Do everything that needs doing in the subdir 'grc' to add - a GRC bindings YAML file. - - add .yml file - - include in CMakeLists.txt - """ - fname_grc = self.info['fullblockname'] + '.block.yml' - self._write_tpl('grc_yml', 'grc', fname_grc) - ed = CMakeFileEditor(self._file['cmgrc'], '\n ') - if self.skip_cmakefiles or ed.check_for_glob('*.yml'): - return - logger.info("Editing grc/CMakeLists.txt...") - ed.append_value('install', fname_grc, to_ignore_end='DESTINATION[^()]+') - ed.write() - self.scm.mark_files_updated((self._file['cmgrc'],)) diff --git a/gr-utils/python/modtool/core/base.py b/gr-utils/python/modtool/core/base.py deleted file mode 100644 index 4073756ca7..0000000000 --- a/gr-utils/python/modtool/core/base.py +++ /dev/null @@ -1,202 +0,0 @@ -# -# Copyright 2013, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" 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 - -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) - from ..cli import setup_cli_logger - 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(r'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') diff --git a/gr-utils/python/modtool/core/disable.py b/gr-utils/python/modtool/core/disable.py deleted file mode 100644 index 1fb4628312..0000000000 --- a/gr-utils/python/modtool/core/disable.py +++ /dev/null @@ -1,161 +0,0 @@ -# -# Copyright 2013, 2018, 2019 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Disable blocks module """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import sys -import logging - -from ..tools import CMakeFileEditor -from .base import ModTool, ModToolException - -logger = logging.getLogger(__name__) - - -class ModToolDisable(ModTool): - """ Disable block (comments out CMake entries for files) """ - name = 'disable' - description = 'Disable selected block in module.' - - def __init__(self, blockname=None, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['pattern'] = blockname - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if not self.info['pattern'] or self.info['pattern'].isspace(): - raise ModToolException("Invalid pattern!") - - def run(self): - """ Go, go, go! """ - def _handle_py_qa(cmake, fname): - """ Do stuff for py qa """ - cmake.comment_out_lines('GR_ADD_TEST.*'+fname) - self.scm.mark_file_updated(cmake.filename) - return True - def _handle_py_mod(cmake, fname): - """ Do stuff for py extra files """ - try: - with open(self._file['pyinit']) as f: - initfile = f.read() - except IOError: - logger.warning("Could not edit __init__.py, that might be a problem.") - return False - pymodname = os.path.splitext(fname)[0] - initfile = re.sub(r'((from|import)\s+\b'+pymodname+r'\b)', r'#\1', initfile) - with open(self._file['pyinit'], 'w') as f: - f.write(initfile) - self.scm.mark_file_updated(self._file['pyinit']) - return False - def _handle_cc_qa(cmake, fname): - """ Do stuff for cc qa """ - if self.info['version'] == '37': - cmake.comment_out_lines(r'\$\{CMAKE_CURRENT_SOURCE_DIR\}/'+fname) - fname_base = os.path.splitext(fname)[0] - ed = CMakeFileEditor(self._file['qalib']) # Abusing the CMakeFileEditor... - ed.comment_out_lines(r'#include\s+"{}.h"'.format(fname_base), comment_str='//') - ed.comment_out_lines(r'{}::suite\(\)'.format(fname_base), comment_str='//') - ed.write() - self.scm.mark_file_updated(self._file['qalib']) - elif self.info['version'] == '38': - fname_qa_cc = 'qa_{}.cc'.format(self.info['blockname']) - cmake.comment_out_lines(fname_qa_cc) - elif self.info['version'] == '36': - cmake.comment_out_lines('add_executable.*'+fname) - cmake.comment_out_lines('target_link_libraries.*'+os.path.splitext(fname)[0]) - cmake.comment_out_lines('GR_ADD_TEST.*'+os.path.splitext(fname)[0]) - self.scm.mark_file_updated(cmake.filename) - return True - def _handle_h_swig(cmake, fname): - """ Comment out include files from the SWIG file, - as well as the block magic """ - with open(self._file['swig']) as f: - swigfile = f.read() - (swigfile, nsubs) = re.subn(r'(.include\s+"({}/)?{}")'.format( - self.info['modname'], fname), - r'//\1', swigfile) - if nsubs > 0: - logger.info("Changing {}...".format(self._file['swig'])) - if nsubs > 1: # Need to find a single BLOCK_MAGIC - blockname = os.path.splitext(fname[len(self.info['modname'])+1:])[0] - if self.info['version'] in ('37', '38'): - blockname = os.path.splitext(fname)[0] - (swigfile, nsubs) = re.subn('(GR_SWIG_BLOCK_MAGIC2?.+{}.+;)'.format(blockname), r'//\1', swigfile) - if nsubs > 1: - logger.warning("Hm, changed more then expected while editing {}.".format(self._file['swig'])) - with open(self._file['swig'], 'w') as f: - f.write(swigfile) - self.scm.mark_file_updated(self._file['swig']) - return False - def _handle_i_swig(cmake, fname): - """ Comment out include files from the SWIG file, - as well as the block magic """ - with open(self._file['swig']) as f: - swigfile = f.read() - blockname = os.path.splitext(fname[len(self.info['modname'])+1:])[0] - if self.info['version'] in ('37', '38'): - blockname = os.path.splitext(fname)[0] - swigfile = re.sub(r'(%include\s+"'+fname+'")', r'//\1', swigfile) - logger.info("Changing {}...".format(self._file['swig'])) - swigfile = re.sub('(GR_SWIG_BLOCK_MAGIC2?.+'+blockname+'.+;)', r'//\1', swigfile) - with open(self._file['swig'], 'w') as f: - f.write(swigfile) - self.scm.mark_file_updated(self._file['swig']) - return False - - # This portion will be covered by the CLI - if not self.cli: - self.validate() - else: - from ..cli import cli_input - # List of special rules: 0: subdir, 1: filename re match, 2: callback - special_treatments = ( - ('python', r'qa.+py$', _handle_py_qa), - ('python', r'^(?!qa).+py$', _handle_py_mod), - ('lib', r'qa.+\.cc$', _handle_cc_qa), - ('include/{}'.format(self.info['modname']), r'.+\.h$', _handle_h_swig), - ('include', r'.+\.h$', _handle_h_swig), - ('swig', r'.+\.i$', _handle_i_swig) - ) - for subdir in self._subdirs: - if self.skip_subdirs[subdir]: - continue - if self.info['version'] in ('37', '38') and subdir == 'include': - subdir = 'include/{}'.format(self.info['modname']) - try: - cmake = CMakeFileEditor(os.path.join(subdir, 'CMakeLists.txt')) - except IOError: - continue - logger.info("Traversing {}...".format(subdir)) - filenames = cmake.find_filenames_match(self.info['pattern']) - yes = self.info['yes'] - for fname in filenames: - file_disabled = False - if not yes: - ans = cli_input("Really disable {}? [Y/n/a/q]: ".format(fname)).lower().strip() - if ans == 'a': - yes = True - if ans == 'q': - sys.exit(0) - if ans == 'n': - continue - for special_treatment in special_treatments: - if special_treatment[0] == subdir and re.match(special_treatment[1], fname): - file_disabled = special_treatment[2](cmake, fname) - if not file_disabled: - cmake.disable_file(fname) - cmake.write() - self.scm.mark_files_updated((os.path.join(subdir, 'CMakeLists.txt'),)) - logger.warning("Careful: 'gr_modtool disable' does not resolve dependencies.") diff --git a/gr-utils/python/modtool/core/info.py b/gr-utils/python/modtool/core/info.py deleted file mode 100644 index e242af0e6e..0000000000 --- a/gr-utils/python/modtool/core/info.py +++ /dev/null @@ -1,132 +0,0 @@ -# -# Copyright 2013, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Returns information about a module """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os - -from ..tools import get_modname -from .base import ModTool, ModToolException - - -class ModToolInfo(ModTool): - """ Return information about a given module """ - name = 'info' - description = 'Return information about a given module.' - - def __init__(self, python_readable=False, suggested_dirs=None, **kwargs): - ModTool.__init__(self, **kwargs) - # Don't call ModTool._validate(), is is too chatty! - self._directory = self.dir - self._python_readable = python_readable - self._suggested_dirs = suggested_dirs - - def run(self): - """ Go, go, go! """ - mod_info = dict() - mod_info['base_dir'] = self._get_base_dir(self._directory) - if mod_info['base_dir'] is None: - raise ModToolException('{}' if self._python_readable else "No module found.") - os.chdir(mod_info['base_dir']) - mod_info['modname'] = get_modname() - if mod_info['modname'] is None: - raise ModToolException('{}' if self._python_readable else "No module found.") - if self.info['version'] == '36' and ( - os.path.isdir(os.path.join('include', mod_info['modname'])) or - os.path.isdir(os.path.join('include', 'gnuradio', mod_info['modname'])) - ): - self.info['version'] = '37' - if not os.path.isfile(os.path.join('cmake', 'Modules', 'FindCppUnit.cmake')): - self.info['version'] = '38' - mod_info['version'] = self.info['version'] - if 'is_component' in list(self.info.keys()) and self.info['is_component']: - mod_info['is_component'] = True - mod_info['incdirs'] = [] - mod_incl_dir = os.path.join(mod_info['base_dir'], 'include') - if os.path.isdir(os.path.join(mod_incl_dir, mod_info['modname'])): - mod_info['incdirs'].append(os.path.join(mod_incl_dir, mod_info['modname'])) - else: - mod_info['incdirs'].append(mod_incl_dir) - build_dir = self._get_build_dir(mod_info) - if build_dir is not None: - mod_info['build_dir'] = build_dir - mod_info['incdirs'] += self._get_include_dirs(mod_info) - if self._python_readable: - print(str(mod_info)) - else: - self._pretty_print(mod_info) - - def _get_base_dir(self, start_dir): - """ Figure out the base dir (where the top-level cmake file is) """ - base_dir = os.path.abspath(start_dir) - if self._check_directory(base_dir): - return base_dir - else: - (up_dir, this_dir) = os.path.split(base_dir) - if os.path.split(up_dir)[1] == 'include': - up_dir = os.path.split(up_dir)[0] - if self._check_directory(up_dir): - return up_dir - return None - - def _get_build_dir(self, mod_info): - """ Figure out the build dir (i.e. where you run 'cmake'). This checks - for a file called CMakeCache.txt, which is created when running cmake. - If that hasn't happened, the build dir cannot be detected, unless it's - called 'build', which is then assumed to be the build dir. """ - base_build_dir = mod_info['base_dir'] - if 'is_component' in list(mod_info.keys()): - (base_build_dir, rest_dir) = os.path.split(base_build_dir) - has_build_dir = os.path.isdir(os.path.join(base_build_dir, 'build')) - if (has_build_dir and os.path.isfile(os.path.join(base_build_dir, 'CMakeCache.txt'))): - return os.path.join(base_build_dir, 'build') - else: - for (dirpath, dirnames, filenames) in os.walk(base_build_dir): - if 'CMakeCache.txt' in filenames: - return dirpath - if has_build_dir: - return os.path.join(base_build_dir, 'build') - return None - - def _get_include_dirs(self, mod_info): - """ Figure out include dirs for the make process. """ - inc_dirs = [] - path_or_internal = {True: 'INTERNAL', - False: 'PATH'}['is_component' in list(mod_info.keys())] - try: - cmakecache_fid = open(os.path.join(mod_info['build_dir'], 'CMakeCache.txt')) - for line in cmakecache_fid: - if line.find('GNURADIO_RUNTIME_INCLUDE_DIRS:{}'.format(path_or_internal)) != -1: - inc_dirs += line.replace('GNURADIO_RUNTIME_INCLUDE_DIRS:{}='.format(path_or_internal), '').strip().split(';') - except IOError: - pass - if not inc_dirs and self._suggested_dirs is not None: - inc_dirs = [os.path.normpath(path) for path in self._suggested_dirs.split(':') if os.path.isdir(path)] - return inc_dirs - - def _pretty_print(elf, mod_info): - """ Output the module info in human-readable format """ - index_names = {'base_dir': 'Base directory', - 'modname': 'Module name', - 'is_component': 'Is GR component', - 'build_dir': 'Build directory', - 'incdirs': 'Include directories'} - for key in list(mod_info.keys()): - if key == 'version': - print(" API version: {}".format({ - '36': 'pre-3.7', - '37': 'post-3.7', - '38': 'post-3.8', - 'autofoo': 'Autotools (pre-3.5)' - }[mod_info['version']])) - else: - print('%19s: %s' % (index_names[key], mod_info[key])) diff --git a/gr-utils/python/modtool/core/makeyaml.py b/gr-utils/python/modtool/core/makeyaml.py deleted file mode 100644 index adf93cf4bd..0000000000 --- a/gr-utils/python/modtool/core/makeyaml.py +++ /dev/null @@ -1,353 +0,0 @@ -# -# Copyright 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Automatically create YAML bindings for GRC from block code """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import glob -import logging -import yaml - -from collections import OrderedDict - -try: - from yaml import CLoader as Loader, CDumper as Dumper -except: - from yaml import Loader, Dumper - -try: - from gnuradio.blocktool.core import Constants -except ImportError: - have_blocktool = False -else: - have_blocktool = True - -from ..tools import ParserCCBlock, CMakeFileEditor, ask_yes_no, GRCYAMLGenerator -from .base import ModTool, ModToolException - - -logger = logging.getLogger(__name__) - -## setup dumper for dumping OrderedDict ## -_MAPPING_TAG = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG - - -def dict_representer(dumper, data): - """ Representer to represent special OrderedDict """ - return dumper.represent_dict(data.items()) - - -def dict_constructor(loader, node): - """ Construct an OrderedDict for dumping """ - return OrderedDict(loader.construct_pairs(node)) - - -Dumper.add_representer(OrderedDict, dict_representer) -Loader.add_constructor(_MAPPING_TAG, dict_constructor) - - -class ModToolMakeYAML(ModTool): - """ Make YAML file for GRC block bindings """ - name = 'makeyaml' - description = 'Generate YAML files for GRC block bindings.' - - def __init__(self, blockname=None, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['pattern'] = blockname - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if not self.info['pattern'] or self.info['pattern'].isspace(): - raise ModToolException("Incorrect blockname (Regex)!") - - def run(self): - """ Go, go, go! """ - # This portion will be covered by the CLI - if not self.cli: - self.validate() - logger.warning( - "Warning: This is an experimental feature. Don't expect any magic.") - # 1) Go through lib/ - if not self.skip_subdirs['lib']: - if self.info['version'] in ('37', '38'): - files = self._search_files('lib', '*_impl.cc') - else: - files = self._search_files('lib', '*.cc') - for f in files: - if os.path.basename(f)[0:2] == 'qa': - continue - (params, iosig, blockname) = self._parse_cc_h(f) - self._make_grc_yaml_from_block_data(params, iosig, blockname) - # 2) Go through python/ - # TODO - - def _search_files(self, path, path_glob): - """ Search for files matching pattern in the given path. """ - files = sorted(glob.glob("{}/{}".format(path, path_glob))) - files_filt = [] - logger.info("Searching for matching files in {}/:".format(path)) - for f in files: - if re.search(self.info['pattern'], os.path.basename(f)) is not None: - files_filt.append(f) - if len(files_filt) == 0: - logger.info("None found.") - return files_filt - - def _make_grc_yaml_from_block_data(self, params, iosig, blockname): - """ Take the return values from the parser and call the YAML - generator. Also, check the makefile if the .yml file is in there. - If necessary, add. """ - fname_yml = '{}_{}.block.yml'.format(self.info['modname'], blockname) - path_to_yml = os.path.join('grc', fname_yml) - # Some adaptions for the GRC - for inout in ('in', 'out'): - if iosig[inout]['max_ports'] == '-1': - iosig[inout]['max_ports'] = '$num_{}puts'.format(inout) - params.append({'key': 'num_{}puts'.format(inout), - 'type': 'int', - 'name': 'Num {}puts'.format(inout), - 'default': '2', - 'in_constructor': False}) - file_exists = False - if os.path.isfile(path_to_yml): - if not self.info['yes']: - if not ask_yes_no('Overwrite existing GRC file?', False): - return - else: - file_exists = True - logger.warning("Warning: Overwriting existing GRC file.") - grc_generator = GRCYAMLGenerator( - modname=self.info['modname'], - blockname=blockname, - params=params, - iosig=iosig - ) - grc_generator.save(path_to_yml) - if file_exists: - self.scm.mark_files_updated((path_to_yml,)) - else: - self.scm.add_files((path_to_yml,)) - if not self.skip_subdirs['grc']: - ed = CMakeFileEditor(self._file['cmgrc']) - if re.search(fname_yml, ed.cfile) is None and not ed.check_for_glob('*.yml'): - logger.info("Adding GRC bindings to grc/CMakeLists.txt...") - ed.append_value('install', fname_yml, - to_ignore_end='DESTINATION[^()]+') - ed.write() - self.scm.mark_files_updated(self._file['cmgrc']) - - def _parse_cc_h(self, fname_cc): - """ Go through a .cc and .h-file defining a block and return info """ - def _type_translate(p_type, default_v=None): - """ Translates a type from C++ to GRC """ - translate_dict = {'float': 'float', - 'double': 'real', - 'int': 'int', - 'gr_complex': 'complex', - 'char': 'byte', - 'unsigned char': 'byte', - 'std::string': 'string', - 'std::vector<int>': 'int_vector', - 'std::vector<float>': 'real_vector', - 'std::vector<gr_complex>': 'complex_vector', - } - if p_type in ('int',) and default_v is not None and len(default_v) > 1 and default_v[:2].lower() == '0x': - return 'hex' - try: - return translate_dict[p_type] - except KeyError: - return 'raw' - - def _get_blockdata(fname_cc): - """ Return the block name and the header file name from the .cc file name """ - blockname = os.path.splitext(os.path.basename( - fname_cc.replace('_impl.', '.')))[0] - fname_h = (blockname + '.h').replace('_impl.', '.') - contains_modulename = blockname.startswith( - self.info['modname']+'_') - blockname = blockname.replace(self.info['modname']+'_', '', 1) - return (blockname, fname_h, contains_modulename) - # Go, go, go - logger.info("Making GRC bindings for {}...".format(fname_cc)) - (blockname, fname_h, contains_modulename) = _get_blockdata(fname_cc) - try: - parser = ParserCCBlock(fname_cc, - os.path.join( - self.info['includedir'], fname_h), - blockname, - self.info['version'], - _type_translate - ) - except IOError: - raise ModToolException( - "Can't open some of the files necessary to parse {}.".format(fname_cc)) - - if contains_modulename: - return (parser.read_params(), parser.read_io_signature(), self.info['modname']+'_'+blockname) - else: - return (parser.read_params(), parser.read_io_signature(), blockname) - - -def yaml_generator(self, **kwargs): - """ - Generate YAML file from the block header file using blocktool API - """ - header = self.filename.split('.')[0] - block = self.modname.split('-')[-1] - label = header.split('_') - del label[-1] - yml_file = os.path.join('.', block+'_'+header+'.block.yml') - _header = (('id', '{}_{}'.format(block, header)), - ('label', ' '.join(label).upper()), - ('category', '[{}]'.format(block.capitalize())), - ('flags', '[python, cpp]') - ) - params_list = [ - '${'+s['name']+'}' for s in self.parsed_data['properties'] if self.parsed_data['properties']] - _templates = [('imports', 'from gnuradio import {}'.format(block)), - ('make', '{}.{}({})'.format(block, header, ', '.join(params_list))) - ] - - if self.parsed_data['methods']: - list_callbacks = [] - for param in self.parsed_data['methods']: - arguments = [] - for args in param['arguments_type']: - arguments.append(args['name']) - arg_list = ['${'+s+'}' for s in arguments if arguments] - list_callbacks.append( - param['name']+'({})'.format(', '.join(arg_list))) - callback_key = ('callbacks') - callbacks = (callback_key, tuple(list_callbacks)) - _templates.append(callbacks) - _templates = tuple(_templates) - - data = OrderedDict() - for tag, value in _header: - data[tag] = value - - templates = OrderedDict() - for tag, value in _templates: - templates[tag] = value - data['templates'] = templates - - parameters = [] - for param in self.parsed_data['properties']: - parameter = OrderedDict() - parameter['id'] = param['name'] - parameter['label'] = param['name'].capitalize() - parameter['dtype'] = param['dtype'] - parameter['read_only'] = param['read_only'] - parameters.append(parameter) - if parameters: - data['parameters'] = parameters - - input_signature = [] - max_input_port = self.parsed_data['io_signature']['input']['max_streams'] - i_sig = self.parsed_data['io_signature']['input']['signature'] - for port in range(0, int(max_input_port)): - input_sig = OrderedDict() - if i_sig is Constants.MAKE: - input_sig['domain'] = 'stream' - input_sig['dtype'] = self.parsed_data['io_signature']['input']['sizeof_stream_item'] - elif i_sig is Constants.MAKE2: - input_sig['domain'] = 'stream' - input_sig['dtype'] = self.parsed_data['io_signature']['input']['sizeof_stream_item' + - str(port+1)] - elif i_sig is Constants.MAKE3: - input_sig['domain'] = 'stream' - input_sig['dtype'] = self.parsed_data['io_signature']['input']['sizeof_stream_item' + - str(port+1)] - elif i_sig is Constants.MAKEV: - input_sig['domain'] = 'stream' - input_sig['dtype'] = self.parsed_data['io_signature']['input']['sizeof_stream_items'] - input_signature.append(input_sig) - - if self.parsed_data['message_port']['input']: - for _input in self.parsed_data['message_port']['input']: - m_input_sig = OrderedDict() - m_input_sig['domain'] = 'message' - m_input_sig['id'] = _input - input_signature.append(m_input_sig) - if input_signature: - data['inputs'] = input_signature - - output_signature = [] - max_output_port = self.parsed_data['io_signature']['output']['max_streams'] - o_sig = self.parsed_data['io_signature']['output']['signature'] - for port in range(0, int(max_output_port)): - output_sig = OrderedDict() - if o_sig is Constants.MAKE: - output_sig['domain'] = 'stream' - output_sig['dtype'] = self.parsed_data['io_signature']['output']['sizeof_stream_item'] - elif o_sig is Constants.MAKE2: - output_sig['domain'] = 'stream' - output_sig['dtype'] = self.parsed_data['io_signature']['output']['sizeof_stream_item' + - str(port+1)] - elif o_sig is Constants.MAKE3: - output_sig['domain'] = 'stream' - output_sig['dtype'] = self.parsed_data['io_signature']['output']['sizeof_stream_item' + - str(port+1)] - elif o_sig is Constants.MAKEV: - output_sig['domain'] = 'stream' - output_sig['dtype'] = self.parsed_data['io_signature']['output']['sizeof_stream_items'] - output_signature.append(output_sig) - - if self.parsed_data['message_port']['output']: - for _output in self.parsed_data['message_port']['output']: - m_output_sig = OrderedDict() - m_output_sig['domain'] = 'message' - m_output_sig['id'] = _output - output_signature.append(m_output_sig) - if output_signature: - data['outputs'] = output_signature - - _cpp_templates = [('includes', '#include <gnuradio/{}/{}>'.format(block, self.filename)), - ('declarations', '{}::{}::sptr ${{id}}'.format(block, header)), - ('make', 'this->${{id}} = {}::{}::make({})'.format( - block, header, ', '.join(params_list))) - ] - - if self.parsed_data['methods']: - list_callbacks = [] - for param in self.parsed_data['methods']: - arguments = [] - for args in param['arguments_type']: - arguments.append(args['name']) - arg_list = ['${'+s+'}' for s in arguments if arguments] - list_callbacks.append( - param['name']+'({})'.format(', '.join(arg_list))) - callback_key = ('callbacks') - callbacks = (callback_key, tuple(list_callbacks)) - _cpp_templates.append(callbacks) - - link = ('link', 'gnuradio-{}'.format(block)) - _cpp_templates.append(link) - _cpp_templates = tuple(_cpp_templates) - - cpp_templates = OrderedDict() - for tag, value in _cpp_templates: - cpp_templates[tag] = value - data['cpp_templates'] = cpp_templates - - if self.parsed_data['docstring'] is not None: - data['documentation'] = self.parsed_data['docstring'] - data['file_format'] = 1 - - if kwargs['output']: - with open(yml_file, 'w') as yml: - yaml.dump(data, yml, Dumper=Dumper, default_flow_style=False) - else: - print(yaml.dump(data, Dumper=Dumper, allow_unicode=True, - default_flow_style=False, indent=4)) diff --git a/gr-utils/python/modtool/core/newmod.py b/gr-utils/python/modtool/core/newmod.py deleted file mode 100644 index 1d22626e10..0000000000 --- a/gr-utils/python/modtool/core/newmod.py +++ /dev/null @@ -1,89 +0,0 @@ -# -# Copyright 2013, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Create a whole new out-of-tree module """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import shutil -import os -import re -import logging - -from gnuradio import gr -from ..tools import SCMRepoFactory -from .base import ModTool, ModToolException - -logger = logging.getLogger(__name__) - -class ModToolNewModule(ModTool): - """ Create a new out-of-tree module """ - name = 'newmod' - description = 'Create new empty module, use add to add blocks.' - def __init__(self, module_name=None, srcdir=None, **kwargs): - ModTool.__init__(self, None, module_name, **kwargs) - # Don't call ModTool._validate(), that assumes an existing module. - self.srcdir = srcdir - self.directory = self.dir - - def assign(self): - self.dir = os.path.join(self.directory, 'gr-{}'.format(self.info['modname'])) - if self.srcdir is None: - self.srcdir = os.path.join(gr.prefix(),'share','gnuradio','modtool','templates','gr-newmod') - - def validate(self): - """ Validates the arguments """ - if not self.info['modname']: - raise ModToolException('Module name not specified.') - if not re.match('[a-zA-Z0-9_]+$', self.info['modname']): - raise ModToolException('Invalid module name.') - try: - os.stat(self.dir) - except OSError: - pass # This is what should happen - else: - raise ModToolException('The given directory exists.') - if not os.path.isdir(self.srcdir): - raise ModToolException('Could not find gr-newmod source dir \'' + self.srcdir + '\'') - - def run(self): - """ - * Copy the example dir recursively - * Open all files, rename howto and HOWTO to the module name - * Rename files and directories that contain the word howto - """ - # This portion will be covered by the CLI - if not self.cli: - self.assign() - self.validate() - self._setup_scm(mode='new') - logger.info("Creating out-of-tree module in {}...".format(self.dir)) - try: - shutil.copytree(self.srcdir, self.dir) - os.chdir(self.dir) - except OSError: - raise ModToolException('Could not create directory {}.'.format(self.dir)) - for root, dirs, files in os.walk('.'): - for filename in files: - f = os.path.join(root, filename) - with open(f, 'r') as filetext: - s = filetext.read() - s = s.replace('howto', self.info['modname']) - s = s.replace('HOWTO', self.info['modname'].upper()) - with open(f, 'w') as filetext: - filetext.write(s) - if filename.find('howto') != -1: - os.rename(f, os.path.join(root, filename.replace('howto', self.info['modname']))) - if os.path.basename(root) == 'howto': - os.rename(root, os.path.join(os.path.dirname(root), self.info['modname'])) - logger.info("Done.") - if self.scm.init_repo(path_to_repo="."): - logger.info("Created repository... you might want to commit before continuing.") - logger.info("Use 'gr_modtool add' to add a new block to this currently empty module.") diff --git a/gr-utils/python/modtool/core/rename.py b/gr-utils/python/modtool/core/rename.py deleted file mode 100644 index d202d2375a..0000000000 --- a/gr-utils/python/modtool/core/rename.py +++ /dev/null @@ -1,175 +0,0 @@ -# -# Copyright 2014, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Module to rename blocks """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import logging - -from .base import get_block_candidates, ModTool, ModToolException - -logger = logging.getLogger(__name__) - - -class ModToolRename(ModTool): - """ Rename a block in the out-of-tree module. """ - name = 'rename' - description = 'Rename a block inside a module.' - - def __init__(self, blockname=None, new_name=None, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['oldname'] = blockname - self.info['newname'] = new_name - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if not self.info['oldname']: - raise ModToolException('Old block name (blockname) not specified.') - if not re.match('[a-zA-Z0-9_]+', self.info['oldname']): - raise ModToolException('Invalid block name.') - block_candidates = get_block_candidates() - if self.info['oldname'] not in block_candidates: - choices = [x for x in block_candidates if self.info['oldname'] in x] - if len(choices)>0: - print("Suggested alternatives: "+str(choices)) - raise ModToolException("Blockname for renaming does not exists!") - if not self.info['newname']: - raise ModToolException('New blockname (new_name) not specified.') - if not re.match('[a-zA-Z0-9_]+', self.info['newname']): - raise ModToolException('Invalid new block name.') - - def assign(self): - self.info['fullnewname'] = self.info['modname'] + '_' + self.info['newname'] - - def run(self): - """ Go, go, go. """ - # This portion will be covered by the CLI - if not self.cli: - self.validate() - self.assign() - module = self.info['modname'] - oldname = self.info['oldname'] - newname = self.info['newname'] - logger.info("In module '{}' rename block '{}' to '{}'".format(module, oldname, newname)) - self._run_swig_rename(self._file['swig'], oldname, newname) - self._run_grc_rename(self.info['modname'], oldname, newname) - self._run_python_qa(self.info['modname'], oldname, newname) - self._run_python(self.info['modname'], oldname, newname) - self._run_lib(self.info['modname'], oldname, newname) - self._run_include(self.info['modname'], oldname, newname) - return - - def _run_swig_rename(self, swigfilename, old, new): - """ Rename SWIG includes and block_magic """ - nsubs = self._run_file_replace(swigfilename, old, new) - if nsubs < 1: - logger.info("Couldn't find '{}' in file '{}'.".format(old, swigfilename)) - if nsubs == 2: - logger.info("Changing 'noblock' type file") - if nsubs > 3: - logger.warning("Hm, changed more then expected while editing {}.".format(swigfilename)) - return False - - def _run_lib(self, module, old, new): - ccfile = './lib/' + old + '_impl.cc' - if not os.path.isfile(ccfile): # in case it is a 'noblock' - ccfile = './lib/' + old + '.cc' - hfile = './lib/' + old + '_impl.h' - self._run_file_replace(ccfile, old, new) - self._run_file_replace(hfile, old, new) - self._run_file_replace(hfile, old.upper(), new.upper()) # take care of include guards - self._run_cmakelists('./lib/', old, new) - self._run_file_rename('./lib/', old, new) - self._run_cpp_qa(module, old, new) - - def _run_cpp_qa(self, module, old, new): - path = './lib/' - filename = 'qa_' + module + '.cc' - nsubs = self._run_file_replace(path + filename, old, new) - if nsubs > 0: - logger.info("C++ QA code detected, renaming...") - filename = 'qa_' + old + '.cc' - self._run_file_replace(path + filename, old, new) - filename = 'qa_' + old + '.h' - self._run_file_replace(path + filename, old, new) - self._run_file_replace(path + filename, old.upper(), new.upper()) - self._run_file_rename(path, 'qa_' + old, 'qa_' + new) - else: - logger.info("No C++ QA code detected, skipping...") - - def _run_include(self, module, old, new): - path = './include/' + module + '/' - filename = path + old + '.h' - self._run_file_replace(filename, old, new) - self._run_file_replace(filename, old.upper(), new.upper()) # take care of include guards - self._run_cmakelists(path, old, new) - self._run_file_rename(path, old, new) - - def _run_python(self, module, old, new): - path = './python/' - filename = '__init__.py' - nsubs = self._run_file_replace(path + filename, old, new) - if nsubs > 0: - logger.info("Python block detected, renaming...") - filename = old + '.py' - self._run_file_replace(path + filename, old, new) - self._run_cmakelists(path, old, new) - self._run_file_rename(path, old, new) - else: - logger.info("Not a Python block, nothing to do here...") - - def _run_python_qa(self, module, old, new): - new = 'qa_' + new - old = 'qa_' + old - filename = './python/' + old + '.py' - self._run_file_replace(filename, old, new) - self._run_cmakelists('./python/', old, new) - self._run_file_rename('./python/', old, new) - - def _run_grc_rename(self, module, old, new): - grcfile = './grc/' + module + '_' + old + '.yml' - self._run_file_replace(grcfile, old, new) - self._run_cmakelists('./grc/', old, new) - self._run_file_rename('./grc/', module + '_' + old, module + '_' + new) - - def _run_cmakelists(self, path, first, second): - filename = path + 'CMakeLists.txt' - nsubs = self._run_file_replace(filename, first, second) - if nsubs < 1: - logger.info("'{}' wasn't in '{}'.".format(first, filename)) - - def _run_file_rename(self, path, old, new): - files = os.listdir(path) - for file in files: - if file.find(old) > -1 and file.find(old) < 3: - nl = file.replace(old, new) - src = path + file - dst = path + nl - logger.info("Renaming file '{}' to '{}'.".format(src, dst)) - os.rename(src, dst) - - def _run_file_replace(self, filename, old, new): - if not os.path.isfile(filename): - return False - else: - logger.info("In '{}' renaming occurrences of '{}' to '{}'".format(filename, old, new)) - - with open(filename) as f: - cfile = f.read() - (cfile, nsubs) = re.subn(old, new, cfile) - - with open(filename, 'w') as f: - f.write(cfile) - self.scm.mark_file_updated(filename) - return nsubs diff --git a/gr-utils/python/modtool/core/rm.py b/gr-utils/python/modtool/core/rm.py deleted file mode 100644 index 72c9da4666..0000000000 --- a/gr-utils/python/modtool/core/rm.py +++ /dev/null @@ -1,167 +0,0 @@ -# -# Copyright 2013, 2018, 2019 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Remove blocks module """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import sys -import glob -import logging - -from ..tools import remove_pattern_from_file, CMakeFileEditor -from .base import ModTool, ModToolException - -logger = logging.getLogger(__name__) - - -class ModToolRemove(ModTool): - """ Remove block (delete files and remove Makefile entries) """ - name = 'remove' - description = 'Remove a block from a module.' - - def __init__(self, blockname=None, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['pattern'] = blockname - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if not self.info['pattern'] or self.info['pattern'].isspace(): - raise ModToolException("Incorrect blockname (Regex)!") - - def run(self): - """ Go, go, go! """ - # This portion will be covered by the CLI - if not self.cli: - self.validate() - else: - from ..cli import cli_input - def _remove_cc_test_case(filename=None, ed=None): - """ Special function that removes the occurrences of a qa*.cc file - from the CMakeLists.txt. """ - if filename[:2] != 'qa': - return - if self.info['version'] == '37': - (base, ext) = os.path.splitext(filename) - if ext == '.h': - remove_pattern_from_file(self._file['qalib'], - r'^#include "{}"\s*$'.format(filename)) - remove_pattern_from_file(self._file['qalib'], - r'^\s*s->addTest\(gr::{}::{}::suite\(\)\);\s*$'.format( - self.info['modname'], base) - ) - self.scm.mark_file_updated(self._file['qalib']) - elif ext == '.cc': - ed.remove_value('list', - r'\$\{CMAKE_CURRENT_SOURCE_DIR\}/%s' % filename, - to_ignore_start='APPEND test_{}_sources'.format(self.info['modname'])) - self.scm.mark_file_updated(ed.filename) - elif self.info['version'] == '38': - (base, ext) = os.path.splitext(filename) - if ext == '.cc': - ed.remove_value( - 'list', filename, - to_ignore_start='APPEND test_{}_sources'.format(self.info['modname'])) - self.scm.mark_file_updated(ed.filename) - else: - filebase = os.path.splitext(filename)[0] - ed.delete_entry('add_executable', filebase) - ed.delete_entry('target_link_libraries', filebase) - ed.delete_entry('GR_ADD_TEST', filebase) - ed.remove_double_newlines() - self.scm.mark_file_updated(ed.filename) - - def _remove_py_test_case(filename=None, ed=None): - """ Special function that removes the occurrences of a qa*.{cc,h} file - from the CMakeLists.txt and the qa_$modname.cc. """ - if filename[:2] != 'qa': - return - filebase = os.path.splitext(filename)[0] - ed.delete_entry('GR_ADD_TEST', filebase) - ed.remove_double_newlines() - - def _make_swig_regex(filename): - filebase = os.path.splitext(filename)[0] - pyblockname = filebase.replace(self.info['modname'] + '_', '') - regexp = r'(^\s*GR_SWIG_BLOCK_MAGIC2?\({},\s*{}\);|^\s*.include\s*"({}/)?{}"\s*)'.format \ - (self.info['modname'], pyblockname, self.info['modname'], filename) - return regexp - # Go, go, go! - if not self.skip_subdirs['lib']: - self._run_subdir('lib', ('*.cc', '*.h'), ('add_library', 'list'), - cmakeedit_func=_remove_cc_test_case) - if not self.skip_subdirs['include']: - incl_files_deleted = self._run_subdir(self.info['includedir'], ('*.h',), ('install',)) - if not self.skip_subdirs['swig']: - swig_files_deleted = self._run_subdir('swig', ('*.i',), ('install',)) - for f in incl_files_deleted + swig_files_deleted: - # TODO do this on all *.i files - remove_pattern_from_file(self._file['swig'], _make_swig_regex(f)) - self.scm.mark_file_updated(self._file['swig']) - if not self.skip_subdirs['python']: - py_files_deleted = self._run_subdir('python', ('*.py',), ('GR_PYTHON_INSTALL',), - cmakeedit_func=_remove_py_test_case) - for f in py_files_deleted: - remove_pattern_from_file(self._file['pyinit'], r'.*import\s+{}.*'.format(f[:-3])) - remove_pattern_from_file(self._file['pyinit'], r'.*from\s+{}\s+import.*\n'.format(f[:-3])) - if not self.skip_subdirs['grc']: - self._run_subdir('grc', ('*.yml',), ('install',)) - - def _run_subdir(self, path, globs, makefile_vars, cmakeedit_func=None): - """ Delete all files that match a certain pattern in path. - path - The directory in which this will take place - globs - A tuple of standard UNIX globs of files to delete (e.g. *.yml) - makefile_vars - A tuple with a list of CMakeLists.txt-variables which - may contain references to the globbed files - cmakeedit_func - If the CMakeLists.txt needs special editing, use this - """ - if self.cli: - from ..cli import cli_input - # 1. Create a filtered list - files = [] - for g in globs: - files = files + sorted(glob.glob("{}/{}".format(path, g))) - files_filt = [] - logger.info("Searching for matching files in {}/:".format(path)) - for f in files: - if re.search(self.info['pattern'], os.path.basename(f)) is not None: - files_filt.append(f) - if len(files_filt) == 0: - logger.info("None found.") - return [] - # 2. Delete files, Makefile entries and other occurrences - files_deleted = [] - ed = CMakeFileEditor('{}/CMakeLists.txt'.format(path)) - yes = self.info['yes'] - for f in files_filt: - b = os.path.basename(f) - if not yes and self.cli: - ans = cli_input("Really delete {}? [Y/n/a/q]: ".format(f)).lower().strip() - if ans == 'a': - yes = True - if ans == 'q': - sys.exit(0) - if ans == 'n': - continue - files_deleted.append(b) - logger.info("Deleting {}.".format(f)) - self.scm.remove_file(f) - os.unlink(f) - logger.info("Deleting occurrences of {} from {}/CMakeLists.txt...".format(b, path)) - for var in makefile_vars: - ed.remove_value(var, b) - if cmakeedit_func is not None: - cmakeedit_func(b, ed) - ed.write() - self.scm.mark_files_updated(('{}/CMakeLists.txt'.format(path))) - return files_deleted diff --git a/gr-utils/python/modtool/core/update.py b/gr-utils/python/modtool/core/update.py deleted file mode 100644 index 2d3af1e7e0..0000000000 --- a/gr-utils/python/modtool/core/update.py +++ /dev/null @@ -1,101 +0,0 @@ -# -# Copyright 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Module to convert XML bindings to YAML bindings """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import os -import re -import glob -import logging - -from .base import ModTool, ModToolException -from ..tools import get_modname - -logger = logging.getLogger(__name__) - - -def get_xml_candidates(): - """ Returns a list of XML candidates for update """ - xml_candidates = [] - xml_files = [x for x in glob.glob1("grc", "*.xml")] - mod_name = get_modname() - for candidate in xml_files: - candidate = os.path.splitext(candidate)[0] - candidate = candidate.split(mod_name + "_", 1)[-1] - xml_candidates.append(candidate) - return xml_candidates - - -class ModToolUpdate(ModTool): - """ Update the grc bindings for a block """ - name = 'update' - description = 'Update the grc bindings for a block' - - def __init__(self, blockname=None, complete=False, include_blacklisted=False, **kwargs): - ModTool.__init__(self, blockname, **kwargs) - self.info['complete'] = complete - self.info['include_blacklisted'] = include_blacklisted - - - def validate(self): - """ Validates the arguments """ - ModTool._validate(self) - if self.info['complete']: - return - if not self.info['blockname'] or self.info['blockname'].isspace(): - raise ModToolException('Block name not specified!') - block_candidates = get_xml_candidates() - if self.info['blockname'] not in block_candidates: - choices = [x for x in block_candidates if self.info['blockname'] in x] - if len(choices) > 0: - print("Suggested alternatives: "+str(choices)) - raise ModToolException("The XML bindings does not exists!") - - def run(self): - from gnuradio.grc.converter import Converter - if not self.cli: - self.validate() - logger.warning("Warning: This is an experimental feature. Please verify the bindings.") - module_name = self.info['modname'] - path = './grc/' - conv = Converter(path, path) - if self.info['complete']: - blocks = get_xml_candidates() - else: - blocks = [self.info['blockname']] - for blockname in blocks: - xml_file = "{}_{}.xml".format(module_name, blockname) - yml_file = "{}_{}.block.yml".format(module_name, blockname) - if not conv.load_block_xml(path+xml_file, self.info["include_blacklisted"]): - continue - logger.info("Converted {} to {}".format(xml_file, yml_file)) - os.remove(path+xml_file) - nsubs = self._run_cmakelists(xml_file, yml_file) - if nsubs > 1: - logger.warning("Changed more than expected for the block '%s' in the CMakeLists.txt. " - "Please verify the CMakeLists manually.", blockname) - elif nsubs == 0: - logger.warning("No entry found for the block '%s' in the CMakeLists.txt. " - 'Please verify the CMakeLists manually.', blockname) - else: - logger.info('Updated the CMakeLists.txt') - - def _run_cmakelists(self, to_remove, to_add): - """ Changes in the CMakeLists """ - filename = './grc/CMakeLists.txt' - with open(filename) as f: - cfile = f.read() - (cfile, nsubs) = re.subn(to_remove, to_add, cfile) - with open(filename, 'w') as f: - f.write(cfile) - self.scm.mark_file_updated(filename) - return nsubs |