diff options
Diffstat (limited to 'gr-utils/python/modtool/tools')
-rw-r--r-- | gr-utils/python/modtool/tools/CMakeLists.txt | 19 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/__init__.py | 19 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/cmakefile_editor.py | 140 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/code_generator.py | 52 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/grc_yaml_generator.py | 129 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/parser_cc_block.py | 223 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/scm.py | 223 | ||||
-rw-r--r-- | gr-utils/python/modtool/tools/util_functions.py | 167 |
8 files changed, 0 insertions, 972 deletions
diff --git a/gr-utils/python/modtool/tools/CMakeLists.txt b/gr-utils/python/modtool/tools/CMakeLists.txt deleted file mode 100644 index 8248bb3e7d..0000000000 --- a/gr-utils/python/modtool/tools/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 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 - cmakefile_editor.py - code_generator.py - grc_yaml_generator.py - parser_cc_block.py - scm.py - util_functions.py - DESTINATION ${GR_PYTHON_DIR}/gnuradio/modtool/tools -) diff --git a/gr-utils/python/modtool/tools/__init__.py b/gr-utils/python/modtool/tools/__init__.py deleted file mode 100644 index 55a55fd166..0000000000 --- a/gr-utils/python/modtool/tools/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright 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 .cmakefile_editor import CMakeFileEditor -from .code_generator import render_template -from .grc_yaml_generator import GRCYAMLGenerator -from .parser_cc_block import ParserCCBlock -from .scm import SCMRepoFactory -from .util_functions import *
\ No newline at end of file diff --git a/gr-utils/python/modtool/tools/cmakefile_editor.py b/gr-utils/python/modtool/tools/cmakefile_editor.py deleted file mode 100644 index 29f9c3eb09..0000000000 --- a/gr-utils/python/modtool/tools/cmakefile_editor.py +++ /dev/null @@ -1,140 +0,0 @@ -# -# Copyright 2013, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Edit CMakeLists.txt files """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import re -import logging - -logger = logging.getLogger(__name__) - - -class CMakeFileEditor(object): - """A tool for editing CMakeLists.txt files. """ - def __init__(self, filename, separator='\n ', indent=' '): - self.filename = filename - with open(filename, 'r') as f: - self.cfile = f.read() - self.separator = separator - self.indent = indent - - def append_value(self, entry, value, to_ignore_start='', to_ignore_end=''): - """ Add a value to an entry. """ - regexp = re.compile(r'({}\({}[^()]*?)\s*?(\s?{})\)'.format(entry, to_ignore_start, to_ignore_end), - re.MULTILINE) - substi = r'\1' + self.separator + value + r'\2)' - (self.cfile, nsubs) = regexp.subn(substi, self.cfile, count=1) - return nsubs - - def remove_value(self, entry, value, to_ignore_start='', to_ignore_end=''): - """ - Remove a value from an entry. - Example: You want to remove file.cc from this list() entry: - list(SOURCES - file.cc - other_file.cc - ) - - Then run: - >>> C.remove_value('list', 'file.cc', 'SOURCES') - - Returns the number of occurrences of entry in the current file - that were removed. - """ - # In the case of the example above, these are cases we need to catch: - # - list(file.cc ... - # entry is right after the value parentheses, no whitespace. Can only happen - # when to_ignore_start is empty. - # - list(... file.cc) - # Other entries come first, then entry is preceded by whitespace. - # - list(SOURCES ... file.cc) # whitespace! - # When to_ignore_start is not empty, entry must always be preceded by whitespace. - if len(to_ignore_start) == 0: - regexp = r'^\s*({entry}\((?:[^()]*?\s+|)){value}\s*([^()]*{to_ignore_end}\s*\)){to_ignore_start}' - else: - regexp = r'^\s*({entry}\(\s*{to_ignore_start}[^()]*?\s+){value}\s*([^()]*{to_ignore_end}\s*\))' - regexp = regexp.format( - entry=entry, - to_ignore_start=to_ignore_start, - value=value, - to_ignore_end=to_ignore_end, - ) - regexp = re.compile(regexp, re.MULTILINE) - (self.cfile, nsubs) = re.subn(regexp, r'\1\2', self.cfile, count=1) - return nsubs - - def delete_entry(self, entry, value_pattern=''): - """Remove an entry from the current buffer.""" - regexp = r'{}\s*\([^()]*{}[^()]*\)[^\n]*\n'.format(entry, value_pattern) - regexp = re.compile(regexp, re.MULTILINE) - (self.cfile, nsubs) = re.subn(regexp, '', self.cfile, count=1) - return nsubs - - def write(self): - """ Write the changes back to the file. """ - with open(self.filename, 'w') as f: - f.write(self.cfile) - - def remove_double_newlines(self): - """Simply clear double newlines from the file buffer.""" - self.cfile = re.compile('\n\n\n+', re.MULTILINE).sub('\n\n', self.cfile) - - def find_filenames_match(self, regex): - """ Find the filenames that match a certain regex - on lines that aren't comments """ - filenames = [] - reg = re.compile(regex) - fname_re = re.compile(r'[a-zA-Z]\w+\.\w{1,5}$') - for line in self.cfile.splitlines(): - if len(line.strip()) == 0 or line.strip()[0] == '#': - continue - for word in re.split('[ /)(\t\n\r\f\v]', line): - if fname_re.match(word) and reg.search(word): - filenames.append(word) - return filenames - - def disable_file(self, fname): - """ Comment out a file. - Example: - add_library( - file1.cc - ) - - Here, file1.cc becomes #file1.cc with disable_file('file1.cc'). - """ - starts_line = False - for line in self.cfile.splitlines(): - if len(line.strip()) == 0 or line.strip()[0] == '#': - continue - if re.search(r'\b'+fname+r'\b', line): - if re.match(fname, line.lstrip()): - starts_line = True - break - comment_out_re = r'#\1' + '\n' + self.indent - if not starts_line: - comment_out_re = r'\n' + self.indent + comment_out_re - (self.cfile, nsubs) = re.subn(r'(\b'+fname+r'\b)\s*', comment_out_re, self.cfile) - if nsubs == 0: - logger.warning("Warning: A replacement failed when commenting out {}. Check the CMakeFile.txt manually.".format(fname)) - elif nsubs > 1: - logger.warning("Warning: Replaced {} {} times (instead of once). Check the CMakeFile.txt manually.".format(fname, nsubs)) - - def comment_out_lines(self, pattern, comment_str='#'): - """ Comments out all lines that match with pattern """ - for line in self.cfile.splitlines(): - if re.search(pattern, line): - self.cfile = self.cfile.replace(line, comment_str+line) - - def check_for_glob(self, globstr): - """ Returns true if a glob as in globstr is found in the cmake file """ - glob_re = r'GLOB\s[a-z_]+\s"{}"'.format(globstr.replace('*', r'\*')) - return re.search(glob_re, self.cfile, flags=re.MULTILINE|re.IGNORECASE) is not None diff --git a/gr-utils/python/modtool/tools/code_generator.py b/gr-utils/python/modtool/tools/code_generator.py deleted file mode 100644 index fb0d7da686..0000000000 --- a/gr-utils/python/modtool/tools/code_generator.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright 2013-2014 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" A code generator (needed by ModToolAdd) """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -from mako.template import Template -from ..templates import Templates -from .util_functions import str_to_fancyc_comment -from .util_functions import str_to_python_comment -from .util_functions import strip_default_values -from .util_functions import strip_arg_types -from .util_functions import strip_arg_types_grc - -GRTYPELIST = { - 'sync': 'sync_block', - 'sink': 'sync_block', - 'source': 'sync_block', - 'decimator': 'sync_decimator', - 'interpolator': 'sync_interpolator', - 'general': 'block', - 'tagged_stream': 'tagged_stream_block', - 'hier': 'hier_block2', - 'noblock': '' -} - -def render_template(tpl_id, **kwargs): - """ Return the parsed and rendered template given by tpl_id """ - # Choose template - tpl = Template(Templates[tpl_id]) - # Set up all variables - kwargs['str_to_fancyc_comment'] = str_to_fancyc_comment - kwargs['str_to_python_comment'] = str_to_python_comment - kwargs['strip_default_values'] = strip_default_values - kwargs['strip_arg_types'] = strip_arg_types - kwargs['strip_arg_types_grc'] = strip_arg_types_grc - kwargs['grblocktype'] = GRTYPELIST[kwargs['blocktype']] - if kwargs['is_component']: - kwargs['include_dir_prefix'] = "gnuradio/" + kwargs['modname'] - else: - kwargs['include_dir_prefix'] = kwargs['modname'] - # Render and return - return tpl.render(**kwargs) - diff --git a/gr-utils/python/modtool/tools/grc_yaml_generator.py b/gr-utils/python/modtool/tools/grc_yaml_generator.py deleted file mode 100644 index 07c00639cf..0000000000 --- a/gr-utils/python/modtool/tools/grc_yaml_generator.py +++ /dev/null @@ -1,129 +0,0 @@ -# -# Copyright 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" A tool for generating YAML bindings """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -from collections import OrderedDict - -import yaml -try: - from yaml import CLoader as Loader, CDumper as Dumper -except: - from yaml import Loader, Dumper - -from .util_functions import is_number - - -## 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 GRCYAMLGenerator(object): - """ Create and write the YAML bindings for a GRC block. """ - def __init__(self, modname=None, blockname=None, doc=None, params=None, iosig=None): - """docstring for __init__""" - params_list = ['${'+s['key']+'}' for s in params if s['in_constructor']] - # Can't make a dict 'cause order matters - self._header = (('id', '{}_{}'.format(modname, blockname)), - ('label', blockname.replace('_', ' ')), - ('category', '[{}]'.format(modname.capitalize())) - ) - self._templates = (('imports', 'import {}'.format(modname)), - ('make', '{}.{}({})'.format(modname, blockname, ', '.join(params_list))) - ) - self.params = params - self.iosig = iosig - self.doc = doc - self.data = None - - def make_yaml(self): - """ Create the actual tag tree """ - data = OrderedDict() - for tag, value in self._header: - data[tag] = value - - templates = OrderedDict() - for tag, value in self._templates: - templates[tag] = value - - data['templates'] = templates - - parameters = [] - for param in self.params: - parameter = OrderedDict() - parameter['id'] = param['key'] - parameter['label'] = param['key'].capitalize() - if param['default']: - parameter['default'] = param['default'] - parameter['dtype'] = param['type'] - parameters.append(parameter) - - if parameters: - data['parameters'] = parameters - - inputs = [] - outputs = [] - iosig = self.iosig - for inout in sorted(iosig.keys()): - if iosig[inout]['max_ports'] == '0': - continue - for i in range(len(iosig[inout]['type'])): - s_type = {'in': 'input', 'out': 'output'}[inout] - s_obj = OrderedDict() - s_obj['label'] = inout - s_obj['domain'] = 'stream' - s_obj['dtype'] = iosig[inout]['type'][i] - if iosig[inout]['vlen'][i] != '1': - vlen = iosig[inout]['vlen'][i] - if is_number(vlen): - s_obj['vlen'] = vlen - else: - s_obj['vlen'] = '${ '+vlen+' }' - if i == len(iosig[inout]['type'])-1: - if not is_number(iosig[inout]['max_ports']): - s_obj['multiplicity'] = iosig[inout]['max_ports'] - elif len(iosig[inout]['type']) < int(iosig[inout]['max_ports']): - s_obj['multiplicity'] = str(int(iosig[inout]['max_ports']) - - len(iosig[inout]['type'])+1) - if s_type == 'input': - inputs.append(s_obj) - elif s_type == 'output': - outputs.append(s_obj) - - if inputs: - data['inputs'] = inputs - - if outputs: - data['outputs'] = outputs - - if self.doc is not None: - data['documentation'] = self.doc - self.data = data - data['file_format'] = 1 - - def save(self, filename): - """ Write the YAML file """ - self.make_yaml() - with open(filename, 'w') as f: - yaml.dump(self.data, f, Dumper=Dumper, default_flow_style=False) diff --git a/gr-utils/python/modtool/tools/parser_cc_block.py b/gr-utils/python/modtool/tools/parser_cc_block.py deleted file mode 100644 index 81c10f0cdc..0000000000 --- a/gr-utils/python/modtool/tools/parser_cc_block.py +++ /dev/null @@ -1,223 +0,0 @@ -# -# Copyright 2013, 2018 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -''' A parser for blocks written in C++ ''' - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import re -import sys -import logging - -logger = logging.getLogger(__name__) - -def dummy_translator(the_type, default_v=None): - """ Doesn't really translate. """ - return the_type - -class ParserCCBlock(object): - """ Class to read blocks written in C++ """ - def __init__(self, filename_cc, filename_h, blockname, version, type_trans=dummy_translator): - with open(filename_cc) as f: - self.code_cc = f.read() - with open(filename_h) as f: - self.code_h = f.read() - self.blockname = blockname - self.type_trans = type_trans - self.version = version - - def read_io_signature(self): - """ Scans a .cc file for an IO signature. """ - def _figure_out_iotype_and_vlen(iosigcall, typestr): - """ From a type identifier, returns the data type. - E.g., for sizeof(int), it will return 'int'. - Returns a list! """ - if 'gr::io_signature::makev' in iosigcall: - logger.error('tbi') - raise ValueError - return {'type': [_typestr_to_iotype(x) for x in typestr.split(',')], - 'vlen': [_typestr_to_vlen(x) for x in typestr.split(',')] - } - def _typestr_to_iotype(typestr): - """ Convert a type string (e.g. sizeof(int) * vlen) to the type (e.g. 'int'). """ - type_match = re.search(r'sizeof\s*\(([^)]*)\)', typestr) - if type_match is None: - return self.type_trans('char') - return self.type_trans(type_match.group(1)) - def _typestr_to_vlen(typestr): - """ From a type identifier, returns the vector length of the block's - input/out. E.g., for 'sizeof(int) * 10', it returns 10. For - 'sizeof(int)', it returns '1'. For 'sizeof(int) * vlen', it returns - the string vlen. """ - # Catch fringe case where no sizeof() is given - if typestr.find('sizeof') == -1: - return typestr - if typestr.find('*') == -1: - return '1' - vlen_parts = typestr.split('*') - for fac in vlen_parts: - if fac.find('sizeof') != -1: - vlen_parts.remove(fac) - if len(vlen_parts) == 1: - return vlen_parts[0].strip() - elif len(vlen_parts) > 1: - return '*'.join(vlen_parts).strip() - iosig = {} - iosig_regex = r'(?P<incall>gr::io_signature::make[23v]?)\s*\(\s*(?P<inmin>[^,]+),\s*(?P<inmax>[^,]+),' + \ - r'\s*(?P<intype>(\([^\)]*\)|[^)])+)\),\s*' + \ - r'(?P<outcall>gr::io_signature::make[23v]?)\s*\(\s*(?P<outmin>[^,]+),\s*(?P<outmax>[^,]+),' + \ - r'\s*(?P<outtype>(\([^\)]*\)|[^)])+)\)' - iosig_match = re.compile(iosig_regex, re.MULTILINE).search(self.code_cc) - try: - iosig['in'] = _figure_out_iotype_and_vlen(iosig_match.group('incall'), - iosig_match.group('intype')) - iosig['in']['min_ports'] = iosig_match.group('inmin') - iosig['in']['max_ports'] = iosig_match.group('inmax') - except Exception: - logger.error("Error: Can't parse input signature.") - try: - iosig['out'] = _figure_out_iotype_and_vlen(iosig_match.group('outcall'), - iosig_match.group('outtype')) - iosig['out']['min_ports'] = iosig_match.group('outmin') - iosig['out']['max_ports'] = iosig_match.group('outmax') - except Exception: - logger.error("Error: Can't parse output signature.") - return iosig - - - def read_params(self): - """ Read the parameters required to initialize the block """ - def _scan_param_list(start_idx): - """ Go through a parameter list and return a tuple each: - (type, name, default_value). Python's re just doesn't cut - it for C++ code :( """ - i = start_idx - c = self.code_h - if c[i] != '(': - raise ValueError - i += 1 - - param_list = [] - read_state = 'type' - in_string = False - parens_count = 0 # Counts () - brackets_count = 0 # Counts <> - end_of_list = False - this_type = '' - this_name = '' - this_defv = '' - WHITESPACE = ' \t\n\r\f\v' - while not end_of_list: - # Keep track of (), stop when reaching final closing parens - if not in_string: - if c[i] == ')': - if parens_count == 0: - if read_state == 'type' and len(this_type): - raise ValueError( - 'Found closing parentheses before finishing ' - 'last argument (this is how far I got: {})'.format \ - (str(param_list)) - ) - if len(this_type): - param_list.append((this_type, this_name, this_defv)) - end_of_list = True - break - else: - parens_count -= 1 - elif c[i] == '(': - parens_count += 1 - # Parameter type (int, const std::string, std::vector<gr_complex>, unsigned long ...) - if read_state == 'type': - if c[i] == '<': - brackets_count += 1 - if c[i] == '>': - brackets_count -= 1 - if c[i] == '&': - i += 1 - continue - if c[i] in WHITESPACE and brackets_count == 0: - while c[i] in WHITESPACE: - i += 1 - continue - if this_type == 'const' or this_type == '': # Ignore this - this_type = '' - elif this_type == 'unsigned': # Continue - this_type += ' ' - continue - else: - read_state = 'name' - continue - this_type += c[i] - i += 1 - continue - # Parameter name - if read_state == 'name': - if c[i] == '&' or c[i] in WHITESPACE: - i += 1 - elif c[i] == '=': - if parens_count != 0: - raise ValueError( - 'While parsing argument {} ({}): name finished but no closing parentheses.'.format \ - (len(param_list)+1, this_type + ' ' + this_name) - ) - read_state = 'defv' - i += 1 - elif c[i] == ',': - if parens_count: - raise ValueError( - 'While parsing argument {} ({}): name finished but no closing parentheses.'.format \ - (len(param_list)+1, this_type + ' ' + this_name) - ) - read_state = 'defv' - else: - this_name += c[i] - i += 1 - continue - # Default value - if read_state == 'defv': - if in_string: - if c[i] == '"' and c[i-1] != '\\': - in_string = False - else: - this_defv += c[i] - elif c[i] == ',': - if parens_count: - raise ValueError( - 'While parsing argument {} ({}): default value finished but no closing parentheses.'.format \ - (len(param_list)+1, this_type + ' ' + this_name) - ) - read_state = 'type' - param_list.append((this_type, this_name, this_defv)) - this_type = '' - this_name = '' - this_defv = '' - else: - this_defv += c[i] - i += 1 - continue - return param_list - # Go, go, go! - if self.version in ('37', '38'): - make_regex = r'static\s+sptr\s+make\s*' - else: - make_regex = r'(?<=_API)\s+\w+_sptr\s+\w+_make_\w+\s*' - make_match = re.compile(make_regex, re.MULTILINE).search(self.code_h) - try: - params_list = _scan_param_list(make_match.end(0)) - except ValueError as ve: - logger.error("Can't parse the argument list: ", ve.args[0]) - sys.exit(0) - params = [] - for plist in params_list: - params.append({'type': self.type_trans(plist[0], plist[2]), - 'key': plist[1], - 'default': plist[2], - 'in_constructor': True}) - return params diff --git a/gr-utils/python/modtool/tools/scm.py b/gr-utils/python/modtool/tools/scm.py deleted file mode 100644 index 707ed6754c..0000000000 --- a/gr-utils/python/modtool/tools/scm.py +++ /dev/null @@ -1,223 +0,0 @@ -# -# Copyright 2013 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# SPDX-License-Identifier: GPL-3.0-or-later -# -# -""" Class to handle source code management repositories. """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import logging -import subprocess - -logger = logging.getLogger(__name__) - -try: - import git - HAS_GITPYTHON = True -except ImportError: - HAS_GITPYTHON = False -# GitPython is a bit too unstable currently -HAS_GITPYTHON = False - -class InvalidSCMError(Exception): - """ Exception for when trying to access a repo of wrong type. """ - def __init__(self): - Exception.__init__(self) - -### Base class ############################################################### -class SCMRepository(object): - """ Base class to handle interactions with source code management systems. """ - handles_scm_type = '*' - def __init__(self, path_to_repo, is_empty=False): - self.path_to_repo = path_to_repo - self.is_empty = is_empty - - def init_repo(self, path_to_repo=None, add_files=True): - """ Initialize the directory as a repository. Assumes the self.path_to_repo - (or path_to_repo, if specified) does *not* contain a valid repository. - If add_files is True, all files in this directory are added to version control. - Returns true if actually created a repo. - """ - if path_to_repo is not None: - self.path_to_repo = path_to_repo - return False - - def add_files(self, paths_to_files): - """ Add a tuple or list of files to the current repository. """ - pass - - def add_file(self, path_to_file): - """ Add a file to the current repository. """ - self.add_files([path_to_file]) - - def remove_files(self, paths_to_files): - """ Remove a tuple or list of files from the current repository. """ - pass - - def remove_file(self, path_to_file): - """ Remove a file from the current repository. """ - self.remove_files([path_to_file]) - - def mark_files_updated(self, paths_to_files): - """ Mark a list of tuple of files as changed. """ - pass - - def mark_file_updated(self, path_to_file): - """ Mark a file as changed. """ - self.mark_files_updated([path_to_file]) - - def is_active(self): - """ Returns true if this repository manager is operating on an active, source-controlled directory. """ - return self.is_empty - - def get_gituser(self): - """ Gets the git user """ - try: - return (subprocess.check_output('git config --global user.name', shell=True).strip()).decode('utf-8') - except (OSError, subprocess.CalledProcessError): - return None - - -### Git ##################################################################### -class GitManagerGitPython(object): - """ Manage git through GitPython (preferred way). """ - def __init__(self, path_to_repo, init=False): - if init: - self.repo = git.Repo.init(path_to_repo, mkdir=False) - else: - try: - self.repo = git.Repo(path_to_repo) - except git.InvalidGitRepositoryError: - self.repo = None - raise InvalidSCMError - self.index = self.repo.index - - def add_files(self, paths_to_files): - """ Adds a tuple of files to the index of the current repository. """ - if self.repo is not None: - self.index.add(paths_to_files) - - def remove_files(self, paths_to_files): - """ Removes a tuple of files from the index of the current repository. """ - if self.repo is not None: - self.index.remove(paths_to_files) - - -class GitManagerShell(object): - """ Call the git executable through a shell. """ - def __init__(self, path_to_repo, init=False, git_executable=None): - self.path_to_repo = path_to_repo - if git_executable is None: - try: - self.git_executable = subprocess.check_output('which git', shell=True).strip() - except (OSError, subprocess.CalledProcessError): - raise InvalidSCMError - try: - if init: - subprocess.check_output([self.git_executable, 'init']) - else: - subprocess.check_output([self.git_executable, 'status']) - except OSError: - raise InvalidSCMError - except subprocess.CalledProcessError: - raise InvalidSCMError - - def add_files(self, paths_to_files): - """ Adds a tuple of files to the index of the current repository. Does not commit. """ - subprocess.check_output([self.git_executable, 'add'] + list(paths_to_files)) - - def remove_files(self, paths_to_files): - """ Removes a tuple of files from the index of the current repository. Does not commit. """ - subprocess.check_output([self.git_executable, 'rm', '--cached'] + list(paths_to_files)) - - -class GitRepository(SCMRepository): - """ Specific to operating on git repositories. """ - handles_scm_type = 'git' - def __init__(self, path_to_repo, is_empty=False): - SCMRepository.__init__(self, path_to_repo, is_empty) - if not is_empty: - try: - if HAS_GITPYTHON: - self.repo_manager = GitManagerGitPython(path_to_repo) - else: - self.repo_manager = GitManagerShell(path_to_repo) - except InvalidSCMError: - self.repo_manager = None - else: - self.repo_manager = None - - def init_repo(self, path_to_repo=None, add_files=True): - """ Makes the directory in self.path_to_repo a git repo. - If add_file is True, all files in this dir are added to the index. """ - SCMRepository.init_repo(self, path_to_repo, add_files) - if HAS_GITPYTHON: - self.repo_manager = GitManagerGitPython(self.path_to_repo, init=True) - else: - self.repo_manager = GitManagerShell(self.path_to_repo, init=True) - if add_files: - self.add_files(('*',)) - return True - - def add_files(self, paths_to_files): - """ Add a file to the current repository. Does not commit. """ - self.repo_manager.add_files(paths_to_files) - - def remove_files(self, paths_to_files): - """ Remove a file from the current repository. Does not commit. """ - self.repo_manager.remove_files(paths_to_files) - - def mark_files_updated(self, paths_to_files): - """ Mark a file as changed. Since this is git, same as adding new files. """ - self.add_files(paths_to_files) - - def is_active(self): - return self.repo_manager is not None - - -############################################################################## -### Factory ################################################################## -class SCMRepoFactory(object): - """ Factory object to create the correct SCM class from the given options and dir. """ - def __init__(self, options, path_to_repo): - self.path_to_repo = path_to_repo - self.options = options - - def make_active_scm_manager(self): - """ Returns a valid, usable object of type SCMRepository. """ - if self.options.scm_mode == 'no': - return SCMRepository(self.path_to_repo) - for glbl in list(globals().values()): - try: - if issubclass(glbl, SCMRepository): - the_scm = glbl(self.path_to_repo) - if the_scm.is_active(): - logger.info('Found SCM of type:', the_scm.handles_scm_type) - return the_scm - except (TypeError, AttributeError, InvalidSCMError): - pass - if self.options == 'yes': - return None - return SCMRepository(self.path_to_repo) - - def make_empty_scm_manager(self, scm_type='git'): - """ Returns a valid, usable object of type SCMRepository for an uninitialized dir. """ - if self.options.scm_mode == 'no': - return SCMRepository(self.path_to_repo) - for glbl in list(globals().values()): - try: - if issubclass(glbl, SCMRepository): - if glbl.handles_scm_type == scm_type: - return glbl(self.path_to_repo, is_empty=True) - except (TypeError, AttributeError, InvalidSCMError): - pass - if self.options == 'yes': - return None - return SCMRepository(self.path_to_repo) - diff --git a/gr-utils/python/modtool/tools/util_functions.py b/gr-utils/python/modtool/tools/util_functions.py deleted file mode 100644 index d7f2b11317..0000000000 --- a/gr-utils/python/modtool/tools/util_functions.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 -# -# -""" Utility functions for gr_modtool """ - -from __future__ import print_function -from __future__ import absolute_import -from __future__ import unicode_literals - -import re -import sys -import readline - -# None of these must depend on other modtool stuff! - -def append_re_line_sequence(filename, linepattern, newline): - """ Detects the re 'linepattern' in the file. After its last occurrence, - paste 'newline'. If the pattern does not exist, append the new line - to the file. Then, write. """ - with open(filename, 'r') as f: - oldfile = f.read() - lines = re.findall(linepattern, oldfile, flags=re.MULTILINE) - if len(lines) == 0: - with open(filename, 'a') as f: - f.write(newline) - return - last_line = lines[-1] - newfile = oldfile.replace(last_line, last_line + newline + '\n') - with open(filename, 'w') as f: - f.write(newfile) - -def remove_pattern_from_file(filename, pattern): - """ Remove all occurrences of a given pattern from a file. """ - with open(filename, 'r') as f: - oldfile = f.read() - pattern = re.compile(pattern, re.MULTILINE) - with open(filename, 'w') as f: - f.write(pattern.sub('', oldfile)) - -def str_to_fancyc_comment(text): - """ Return a string as a C formatted comment. """ - l_lines = text.splitlines() - if len(l_lines[0]) == 0: - outstr = "/*\n" - else: - outstr = "/* " + l_lines[0] + "\n" - for line in l_lines[1:]: - if len(line) == 0: - outstr += " *\n" - else: - outstr += " * " + line + "\n" - outstr += " */\n" - return outstr - -def str_to_python_comment(text): - """ Return a string as a Python formatted comment. """ - l_lines = text.splitlines() - if len(l_lines[0]) == 0: - outstr = "#\n" - else: - outstr = "# " + l_lines[0] + "\n" - for line in l_lines[1:]: - if len(line) == 0: - outstr += "#\n" - else: - outstr += "# " + line + "\n" - outstr += "#\n" - return outstr - -def strip_default_values(string): - """ Strip default values from a C++ argument list. """ - return re.sub(' *=[^,)]*', '', string) - -def strip_arg_types(string): - """" - Strip the argument types from a list of arguments. - Example: "int arg1, double arg2" -> "arg1, arg2" - Note that some types have qualifiers, which also are part of - the type, e.g. "const std::string &name" -> "name", or - "const char *str" -> "str". - """ - string = strip_default_values(string) - return ", ".join( - [part.strip().split(' ')[-1] for part in string.split(',')] - ).replace('*','').replace('&','') - -def strip_arg_types_grc(string): - """" Strip the argument types from a list of arguments for GRC make tag. - Example: "int arg1, double arg2" -> "$arg1, $arg2" """ - if len(string) == 0: - return "" - else: - string = strip_default_values(string) - return ", ".join(['${' + part.strip().split(' ')[-1] + '}' for part in string.split(',')]) - -def get_modname(): - """ Grep the current module's name from gnuradio.project or CMakeLists.txt """ - modname_trans = {'howto-write-a-block': 'howto'} - try: - with open('gnuradio.project', 'r') as f: - prfile = f.read() - regexp = r'projectname\s*=\s*([a-zA-Z0-9-_]+)$' - return re.search(regexp, prfile, flags=re.MULTILINE).group(1).strip() - except IOError: - pass - # OK, there's no gnuradio.project. So, we need to guess. - with open('CMakeLists.txt', 'r') as f: - cmfile = f.read() - regexp = r'(project\s*\(\s*|GR_REGISTER_COMPONENT\(")gr-(?P<modname>[a-zA-Z0-9-_]+)(\s*(CXX)?|" ENABLE)' - try: - modname = re.search(regexp, cmfile, flags=re.MULTILINE).group('modname').strip() - if modname in list(modname_trans.keys()): - modname = modname_trans[modname] - return modname - except AttributeError: - return None - -def is_number(s): - """ Return True if the string s contains a number. """ - try: - float(s) - return True - except ValueError: - return False - -def ask_yes_no(question, default): - """ Asks a binary question. Returns True for yes, False for no. - default is given as a boolean. """ - question += {True: ' [Y/n] ', False: ' [y/N] '}[default] - if input(question).lower() != {True: 'n', False: 'y'}[default]: - return default - else: - return not default - -class SequenceCompleter(object): - """ A simple completer function wrapper to be used with readline, e.g. - option_iterable = ("search", "seek", "destroy") - readline.set_completer(SequenceCompleter(option_iterable).completefunc) - - Typical usage is with the `with` statement. Restores the previous completer - at exit, thus nestable. - """ - - def __init__(self, sequence=None): - self._seq = sequence or [] - self._tmp_matches = [] - - def completefunc(self, text, state): - if not text and state < len(self._seq): - return self._seq[state] - if not state: - self._tmp_matches = [candidate for candidate in self._seq if candidate.startswith(text)] - if state < len(self._tmp_matches): - return self._tmp_matches[state] - - def __enter__(self): - self._old_completer = readline.get_completer() - readline.set_completer(self.completefunc) - readline.parse_and_bind("tab: complete") - - def __exit__(self, exception_type, exception_value, traceback): - readline.set_completer(self._old_completer) |