diff options
Diffstat (limited to 'grc/core/Platform.py')
-rw-r--r-- | grc/core/Platform.py | 272 |
1 files changed, 131 insertions, 141 deletions
diff --git a/grc/core/Platform.py b/grc/core/Platform.py index 2907342be5..f6bb756b4e 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -1,5 +1,5 @@ """ -Copyright 2008-2015 Free Software Foundation, Inc. +Copyright 2008-2016 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -21,30 +21,89 @@ import os import sys from gnuradio import gr -from . import ParseXML, Messages -from .Constants import ( - BLOCK_TREE_DTD, FLOW_GRAPH_DTD, DOMAIN_DTD, - HIER_BLOCKS_LIB_DIR, BLOCK_DTD, DEFAULT_FLOW_GRAPH, BLOCKS_DIRS, - PREFS_FILE, CORE_TYPES, PREFS_FILE_OLD, -) +from . import ParseXML, Messages, Constants + from .Element import Element from .generator import Generator +from .FlowGraph import FlowGraph +from .Connection import Connection +from .Block import Block +from .Port import Port +from .Param import Param + from .utils import odict, extract_docs +from os.path import expanduser, normpath, expandvars, dirname, exists + + +class Config(object): + + key = 'grc' + name = 'GNU Radio Companion' + license = __doc__.strip() + website = 'http://gnuradio.org' + version = gr.version() + version2 = (gr.major_version(), gr.api_version(), gr.minor_version()) + + hier_block_lib_dir = os.environ.get('GRC_HIER_PATH', expanduser('~/.grc_gnuradio')) + + def __init__(self): + self.prefs = self._get_prefs() + + # Ensure hier and conf directories + if not exists(self.hier_block_lib_dir): + os.mkdir(self.hier_block_lib_dir) + if not exists(dirname(Constants.PREFS_FILE)): + os.mkdir(dirname(Constants.PREFS_FILE)) + + @staticmethod + def _get_prefs(): + try: + from gnuradio import gr + prefs = gr.prefs() + except ImportError: + import ConfigParser + prefs = ConfigParser.ConfigParser() + + return prefs + + @property + def block_paths(self): + path_list_sep = {'/': ':', '\\': ';'}[os.path.sep] + + paths_sources = ( + self.hier_block_lib_dir, + os.environ.get('GRC_BLOCKS_PATH', ''), + self.prefs.get_string('grc', 'local_blocks_path', ''), + self.prefs.get_string('grc', 'global_blocks_path', ''), + ) + + collected_paths = sum((paths.split(path_list_sep) + for paths in paths_sources), []) + + valid_paths = [normpath(expanduser(expandvars(path))) + for path in collected_paths if exists(path)] + + return valid_paths + + class Platform(Element): + Generator = Generator + FlowGraph = FlowGraph + Connection = Connection + Block = Block + Port = Port + Param = Param + is_platform = True def __init__(self): - """ Make a platform for gnuradio """ + """ Make a platform for GNU Radio """ Element.__init__(self) - # Ensure hier and conf directories - if not os.path.exists(HIER_BLOCKS_LIB_DIR): - os.mkdir(HIER_BLOCKS_LIB_DIR) - if not os.path.exists(os.path.dirname(PREFS_FILE)): - os.mkdir(os.path.dirname(PREFS_FILE)) + self.config = Config() self.block_docstrings = {} self.block_docstrings_loaded_callback = lambda: None # dummy to be replaced by BlockTreeWindow @@ -54,37 +113,27 @@ class Platform(Element): callback_finished=lambda: self.block_docstrings_loaded_callback() ) - self._name = 'GNU Radio Companion' - # Save the version string to the first - version = (gr.version(), gr.major_version(), gr.api_version(), gr.minor_version()) - self._version = version[0] - self._version_major = version[1] - self._version_api = version[2] - self._version_minor = version[3] - self._version_short = version[1] + "." + version[2] + "." + version[3] - - self._key = 'grc' - self._license = __doc__.strip() - self._website = 'http://gnuradio.org' - self._block_paths = list(set(BLOCKS_DIRS)) - self._block_dtd = BLOCK_DTD - self._default_flow_graph = DEFAULT_FLOW_GRAPH - self._generator = Generator - self._colors = [(name, color) for name, key, sizeof, color in CORE_TYPES] + self._block_paths = list(set(Constants.BLOCKS_DIRS)) + self._block_dtd = Constants.BLOCK_DTD + self._default_flow_graph = Constants.DEFAULT_FLOW_GRAPH + # Create a dummy flow graph for the blocks self._flow_graph = Element(self) self._flow_graph.connections = [] - self._blocks = None + self.blocks = None self._blocks_n = None self._category_trees_n = None - self._domains = dict() - self._connection_templates = dict() - self.load_blocks() + self.domains = dict() + self.connection_templates = dict() - _move_old_pref_file() self._auto_hier_block_generate_chain = set() + self.load_blocks() + + def __str__(self): + return 'Platform - {}({})'.format(self.config.key, self.config.name) + @staticmethod def find_file_in_paths(filename, paths, cwd): """Checks the provided paths relative to cwd for a certain filename""" @@ -102,7 +151,7 @@ class Platform(Element): return file_path def load_and_generate_flow_graph(self, file_path): - """Loads a flowgraph from file and generates it""" + """Loads a flow graph from file and generates it""" Messages.set_indent(len(self._auto_hier_block_generate_chain)) Messages.send('>>> Loading: %r\n' % file_path) if file_path in self._auto_hier_block_generate_chain: @@ -127,7 +176,7 @@ class Platform(Element): try: Messages.send('>>> Generating: {}\n'.format(file_path)) - generator = self.get_generator()(flow_graph, file_path) + generator = self.Generator(flow_graph, file_path) generator.write() except Exception as e: Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e))) @@ -140,11 +189,11 @@ class Platform(Element): """load the blocks and block tree from the search paths""" self._docstring_extractor.start() # Reset - self._blocks = odict() + self.blocks = odict() self._blocks_n = odict() self._category_trees_n = list() - self._domains.clear() - self._connection_templates.clear() + self.domains.clear() + self.connection_templates.clear() ParseXML.xml_failures.clear() # Try to parse and load blocks for xml_file in self.iter_xml_files(): @@ -159,7 +208,6 @@ class Platform(Element): # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) pass except Exception as e: - raise print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file) self._docstring_extractor.finish() @@ -184,10 +232,10 @@ class Platform(Element): # Get block instance and add it to the list of blocks block = self.Block(self._flow_graph, n) key = block.get_key() - if key in self._blocks: + if key in self.blocks: print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) else: # Store the block - self._blocks[key] = block + self.blocks[key] = block self._blocks_n[key] = n self._docstring_extractor.query( @@ -196,31 +244,22 @@ class Platform(Element): block.get_make(raw=True) ) - def _save_docstring_extraction_result(self, key, docstrings): - docs = {} - for match, docstring in docstrings.iteritems(): - if not docstring or match.endswith('_sptr'): - continue - docstring = docstring.replace('\n\n', '\n').strip() - docs[match] = docstring - self.block_docstrings[key] = docs - def load_category_tree_xml(self, xml_file): """Validate and parse category tree file and add it to list""" - ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD) + ParseXML.validate_dtd(xml_file, Constants.BLOCK_TREE_DTD) n = ParseXML.from_file(xml_file).find('cat') self._category_trees_n.append(n) def load_domain_xml(self, xml_file): """Load a domain properties and connection templates from XML""" - ParseXML.validate_dtd(xml_file, DOMAIN_DTD) + ParseXML.validate_dtd(xml_file, Constants.DOMAIN_DTD) n = ParseXML.from_file(xml_file).find('domain') key = n.find('key') if not key: - print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.foramt(xml_file) + print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file) return - if key in self.get_domains(): # test against repeated keys + if key in self.domains: # test against repeated keys print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) return @@ -239,7 +278,7 @@ class Platform(Element): print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) color = None - self._domains[key] = dict( + self.domains[key] = dict( name=n.find('name') or key, multiple_sinks=to_bool(n.find('multiple_sinks'), True), multiple_sources=to_bool(n.find('multiple_sources'), False), @@ -249,27 +288,10 @@ class Platform(Element): key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) if not all(key): print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file) - elif key in self._connection_templates: + elif key in self.connection_templates: print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file) else: - self._connection_templates[key] = connection_n.find('make') or '' - - def parse_flow_graph(self, flow_graph_file): - """ - Parse a saved flow graph file. - Ensure that the file exists, and passes the dtd check. - - Args: - flow_graph_file: the flow graph file - - Returns: - nested data - @throws exception if the validation fails - """ - flow_graph_file = flow_graph_file or self._default_flow_graph - open(flow_graph_file, 'r') # Test open - ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD) - return ParseXML.from_file(flow_graph_file) + self.connection_templates[key] = connection_n.find('make') or '' def load_block_tree(self, block_tree): """ @@ -289,10 +311,10 @@ class Platform(Element): map(lambda c: load_category(c, parent), cat_n.findall('cat')) # Add blocks in this category for block_key in cat_n.findall('block'): - if block_key not in self.get_block_keys(): + if block_key not in self.blocks: print >> sys.stderr, 'Warning: Block key "{}" not found when loading category tree.'.format(block_key) continue - block = self.get_block(block_key) + block = self.blocks[block_key] # If it exists, the block's category shall not be overridden by the xml tree if not block.get_category(): block.set_category(parent) @@ -302,85 +324,53 @@ class Platform(Element): load_category(category_tree_n) # Add blocks to block tree - for block in self.get_blocks(): + for block in self.blocks.itervalues(): # Blocks with empty categories are hidden if not block.get_category(): continue block_tree.add_block(block.get_category(), block) - def __str__(self): - return 'Platform - {}({})'.format(self.get_key(), self.get_name()) - - def get_new_flow_graph(self): - return self.FlowGraph(platform=self) - - def get_generator(self): - return self._generator + def _save_docstring_extraction_result(self, key, docstrings): + docs = {} + for match, docstring in docstrings.iteritems(): + if not docstring or match.endswith('_sptr'): + continue + docstring = docstring.replace('\n\n', '\n').strip() + docs[match] = docstring + self.block_docstrings[key] = docs ############################################## - # Access Blocks + # Access ############################################## - def get_block_keys(self): - return self._blocks.keys() - - def get_block(self, key): - return self._blocks[key] - - def get_blocks(self): - return self._blocks.values() - - def get_new_block(self, flow_graph, key): - return self.Block(flow_graph, n=self._blocks_n[key]) - - def get_domains(self): - return self._domains - - def get_domain(self, key): - return self._domains.get(key) - - def get_connection_templates(self): - return self._connection_templates - - def get_name(self): - return self._name - def get_version(self): - return self._version - - def get_version_major(self): - return self._version_major - - def get_version_api(self): - return self._version_api + def parse_flow_graph(self, flow_graph_file): + """ + Parse a saved flow graph file. + Ensure that the file exists, and passes the dtd check. - def get_version_minor(self): - return self._version_minor + Args: + flow_graph_file: the flow graph file - def get_version_short(self): - return self._version_short + Returns: + nested data + @throws exception if the validation fails + """ + flow_graph_file = flow_graph_file or self._default_flow_graph + open(flow_graph_file, 'r') # Test open + ParseXML.validate_dtd(flow_graph_file, Constants.FLOW_GRAPH_DTD) + return ParseXML.from_file(flow_graph_file) - def get_key(self): - return self._key + def get_new_flow_graph(self): + return self.FlowGraph(platform=self) - def get_license(self): - return self._license + def get_blocks(self): + return self.blocks.values() - def get_website(self): - return self._website + def get_new_block(self, flow_graph, key): + return self.Block(flow_graph, n=self._blocks_n[key]) def get_colors(self): - return self._colors + return [(name, color) for name, key, sizeof, color in Constants.CORE_TYPES] def get_block_paths(self): return self._block_paths - - -def _move_old_pref_file(): - if PREFS_FILE == PREFS_FILE_OLD: - return # prefs file overridden with env var - if os.path.exists(PREFS_FILE_OLD) and not os.path.exists(PREFS_FILE): - try: - import shutil - shutil.move(PREFS_FILE_OLD, PREFS_FILE) - except Exception as e: - print >> sys.stderr, e |