summaryrefslogtreecommitdiff
path: root/gr-utils/python/modtool/core
diff options
context:
space:
mode:
Diffstat (limited to 'gr-utils/python/modtool/core')
-rw-r--r--gr-utils/python/modtool/core/CMakeLists.txt22
-rw-r--r--gr-utils/python/modtool/core/__init__.py22
-rw-r--r--gr-utils/python/modtool/core/add.py307
-rw-r--r--gr-utils/python/modtool/core/base.py202
-rw-r--r--gr-utils/python/modtool/core/disable.py161
-rw-r--r--gr-utils/python/modtool/core/info.py132
-rw-r--r--gr-utils/python/modtool/core/makeyaml.py353
-rw-r--r--gr-utils/python/modtool/core/newmod.py89
-rw-r--r--gr-utils/python/modtool/core/rename.py175
-rw-r--r--gr-utils/python/modtool/core/rm.py167
-rw-r--r--gr-utils/python/modtool/core/update.py101
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