diff options
Diffstat (limited to 'grc')
-rwxr-xr-x | grc/compiler.py | 76 | ||||
-rw-r--r-- | grc/core/Config.py | 4 | ||||
-rw-r--r-- | grc/core/FlowGraph.py | 15 | ||||
-rw-r--r-- | grc/core/Param.py | 2 | ||||
-rw-r--r-- | grc/core/Platform.py | 23 | ||||
-rw-r--r-- | grc/core/generator/flow_graph.tmpl | 3 | ||||
-rw-r--r-- | grc/core/utils/epy_block_io.py | 2 | ||||
-rw-r--r-- | grc/core/utils/shlex.py | 47 | ||||
-rw-r--r-- | grc/gui/Application.py | 3 | ||||
-rw-r--r-- | grc/gui/Constants.py | 10 | ||||
-rw-r--r-- | grc/gui/Dialogs.py | 2 | ||||
-rw-r--r-- | grc/gui/Executor.py | 35 | ||||
-rw-r--r-- | grc/gui/ParamWidgets.py | 4 | ||||
-rw-r--r-- | grc/gui/PropsDialog.py | 4 | ||||
-rw-r--r-- | grc/gui/Utils.py | 10 | ||||
-rw-r--r-- | grc/gui/VariableEditor.py | 10 | ||||
-rw-r--r-- | grc/gui/canvas/block.py | 3 | ||||
-rw-r--r-- | grc/scripts/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | grc/scripts/gnuradio-companion | 34 | ||||
-rwxr-xr-x | grc/scripts/grcc | 64 | ||||
-rw-r--r-- | grc/tests/resources/test_compiler.grc | 253 | ||||
-rw-r--r-- | grc/tests/test_compiler.py | 38 |
22 files changed, 565 insertions, 79 deletions
diff --git a/grc/compiler.py b/grc/compiler.py new file mode 100755 index 0000000000..b2361b86eb --- /dev/null +++ b/grc/compiler.py @@ -0,0 +1,76 @@ +# Copyright 2016 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +from __future__ import print_function, absolute_import + +import argparse +import os +import subprocess + +from gnuradio import gr + +from .core import Messages +from .core.Platform import Platform + + +def argument_parser(): + parser = argparse.ArgumentParser(description=( + "Compile a GRC file (.grc) into a GNU Radio Python program and run it." + )) + parser.add_argument("-o", "--output", metavar='DIR', default='.', + help="Output directory for compiled program [default=%(default)s]") + parser.add_argument("-u", "--user-lib-dir", action='store_true', default=False, + help="Output to default hier_block library (overwrites -o)") + parser.add_argument("-r", "--run", action="store_true", default=False, + help="Run the program after compiling [default=%(default)s]") + parser.add_argument(metavar="GRC_FILE", dest='grc_files', nargs='+', + help=".grc file to compile") + return parser + + +def main(args=None): + args = args or argument_parser().parse_args() + + platform = Platform( + name='GNU Radio Companion Compiler', + prefs=gr.prefs(), + version=gr.version(), + version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()) + ) + out_dir = args.output if not args.user_lib_dir else platform.config.hier_block_lib_dir + if os.path.exists(out_dir): + pass # all is well + elif args.save_to_lib: + os.mkdir(out_dir) # create missing hier_block lib directory + else: + exit('Error: Invalid output directory') + + Messages.send_init(platform) + flow_graph = file_path = None + for grc_file in args.grc_files: + os.path.exists(grc_file) or exit('Error: missing ' + grc_file) + Messages.send('\n') + + flow_graph, file_path = platform.load_and_generate_flow_graph( + os.path.abspath(grc_file), os.path.abspath(out_dir)) + if not file_path: + exit('Compilation error') + if file_path and args.run: + run_command_args = flow_graph.get_run_command(file_path, split=True) + subprocess.call(run_command_args) diff --git a/grc/core/Config.py b/grc/core/Config.py index 3455a382c1..cc199a348f 100644 --- a/grc/core/Config.py +++ b/grc/core/Config.py @@ -32,10 +32,12 @@ class Config(object): hier_block_lib_dir = os.environ.get('GRC_HIER_PATH', Constants.DEFAULT_HIER_BLOCK_LIB_DIR) - def __init__(self, version, version_parts=None, prefs=None): + def __init__(self, version, version_parts=None, name=None, prefs=None): self._gr_prefs = prefs if prefs else DummyPrefs() self.version = version self.version_parts = version_parts or version[1:].split('-', 1)[0].split('.')[:3] + if name: + self.name = name @property def block_paths(self): diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py index 18a5778015..bf5bf6d93e 100644 --- a/grc/core/FlowGraph.py +++ b/grc/core/FlowGraph.py @@ -22,11 +22,12 @@ import time import re from operator import methodcaller import collections +import sys from . import Messages from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION from .Element import Element -from .utils import expr_utils +from .utils import expr_utils, shlex _parameter_matcher = re.compile('^(parameter)$') _monitors_searcher = re.compile('(ctrlport_monitor)') @@ -181,6 +182,16 @@ class FlowGraph(Element): """ return self._options_block.get_param(key).get_evaluated() + def get_run_command(self, file_path, split=False): + run_command = self.get_option('run_command') + try: + run_command = run_command.format( + python=shlex.quote(sys.executable), + filename=shlex.quote(file_path)) + return shlex.split(run_command) if split else run_command + except Exception as e: + raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) + ############################################## # Access Elements ############################################## @@ -392,7 +403,7 @@ class FlowGraph(Element): cwd=self.grc_file_path ) if file_path: # grc file found. load and get block - self.parent_platform.load_and_generate_flow_graph(file_path) + self.parent_platform.load_and_generate_flow_graph(file_path, hier_only=True) block = self.new_block(key) # can be None if not block: # looks like this block key cannot be found diff --git a/grc/core/Param.py b/grc/core/Param.py index 31393b1d79..9544d79764 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -29,7 +29,7 @@ from . import Constants from .Element import Element, nop_write # Blacklist certain ids, its not complete, but should help -ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'math', 'firdes'] + dir(builtins) +ID_BLACKLIST = ['self', 'options', 'gr', 'math', 'firdes'] + dir(builtins) try: from gnuradio import gr ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_')) diff --git a/grc/core/Platform.py b/grc/core/Platform.py index 1e43271dc2..73937f1299 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -90,42 +90,43 @@ class Platform(Element): if os.path.exists(os.path.normpath(file_path)): return file_path - def load_and_generate_flow_graph(self, file_path): + def load_and_generate_flow_graph(self, file_path, out_path=None, hier_only=False): """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) + Messages.send('>>> Loading: {}\n'.format(file_path)) if file_path in self._auto_hier_block_generate_chain: Messages.send(' >>> Warning: cyclic hier_block dependency\n') - return False + return None, None self._auto_hier_block_generate_chain.add(file_path) try: flow_graph = self.get_new_flow_graph() flow_graph.grc_file_path = file_path - # Other, nested higiter_blocks might be auto-loaded here + # Other, nested hier_blocks might be auto-loaded here flow_graph.import_data(self.parse_flow_graph(file_path)) flow_graph.rewrite() flow_graph.validate() if not flow_graph.is_valid(): raise Exception('Flowgraph invalid') - if not flow_graph.get_option('generate_options').startswith('hb'): + if hier_only and not flow_graph.get_option('generate_options').startswith('hb'): raise Exception('Not a hier block') except Exception as e: Messages.send('>>> Load Error: {}: {}\n'.format(file_path, str(e))) - return False + return None, None finally: self._auto_hier_block_generate_chain.discard(file_path) Messages.set_indent(len(self._auto_hier_block_generate_chain)) try: - Messages.send('>>> Generating: {}\n'.format(file_path)) - generator = self.Generator(flow_graph, file_path) + generator = self.Generator(flow_graph, out_path or file_path) + Messages.send('>>> Generating: {}\n'.format(generator.file_path)) generator.write() except Exception as e: Messages.send('>>> Generate Error: {}: {}\n'.format(file_path, str(e))) - return False + return None, None - self.load_block_xml(generator.file_path_xml) - return True + if flow_graph.get_option('generate_options').startswith('hb'): + self.load_block_xml(generator.file_path_xml) + return flow_graph, generator.file_path def build_block_library(self): """load the blocks and block tree from the search paths""" diff --git a/grc/core/generator/flow_graph.tmpl b/grc/core/generator/flow_graph.tmpl index b8913bb087..202362c925 100644 --- a/grc/core/generator/flow_graph.tmpl +++ b/grc/core/generator/flow_graph.tmpl @@ -80,7 +80,7 @@ $imp #set $class_name = $flow_graph.get_option('id') #set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters]) #if $generate_options == 'qt_gui' - +from gnuradio import qtgui class $(class_name)(gr.top_block, Qt.QWidget): @@ -88,6 +88,7 @@ class $(class_name)(gr.top_block, Qt.QWidget): gr.top_block.__init__(self, "$title") Qt.QWidget.__init__(self) self.setWindowTitle("$title") + qtgui.util.check_set_qss() try: self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) except: diff --git a/grc/core/utils/epy_block_io.py b/grc/core/utils/epy_block_io.py index 7a2006a833..fc631203e3 100644 --- a/grc/core/utils/epy_block_io.py +++ b/grc/core/utils/epy_block_io.py @@ -24,7 +24,7 @@ def _ports(sigs, msgs): for i, dtype in enumerate(sigs): port_type = TYPE_MAP.get(dtype.name, None) if not port_type: - raise ValueError("Can't map {0:!r} to GRC port type".format(dtype)) + raise ValueError("Can't map {0!r} to GRC port type".format(dtype)) ports.append((str(i), port_type)) for msg_key in msgs: if msg_key == 'system': diff --git a/grc/core/utils/shlex.py b/grc/core/utils/shlex.py new file mode 100644 index 0000000000..6b620fa396 --- /dev/null +++ b/grc/core/utils/shlex.py @@ -0,0 +1,47 @@ +# Copyright 2016 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +from __future__ import absolute_import + +import re +import shlex + +# back port from python3 + +_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search + + +def _shlex_quote(s): + """Return a shell-escaped version of the string *s*.""" + if not s: + return "''" + if _find_unsafe(s) is None: + return s + + # use single quotes, and put single quotes into double quotes + # the string $'b is then quoted as '$'"'"'b' + return "'" + s.replace("'", "'\"'\"'") + "'" + + +if not hasattr(shlex, 'quote'): + quote = _shlex_quote +else: + quote = shlex.quote + +split = shlex.split diff --git a/grc/gui/Application.py b/grc/gui/Application.py index 5c643eafa1..e2290b3401 100644 --- a/grc/gui/Application.py +++ b/grc/gui/Application.py @@ -519,8 +519,9 @@ class Application(Gtk.Application): elif action == Actions.FLOW_GRAPH_NEW: main.new_page() if args: + flow_graph = main.get_flow_graph() flow_graph._options_block.get_param('generate_options').set_value(args[0]) - flow_graph_update() + flow_graph_update(flow_graph) elif action == Actions.FLOW_GRAPH_OPEN: file_paths = args if args else FileDialogs.OpenFlowGraph(main, page.file_path).run() if file_paths: # Open a new page for each file, show only the first diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 0a555b37c9..01ea23ed3e 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -19,13 +19,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import -from gi.repository import Gtk +from gi.repository import Gtk, Gdk from ..core.Constants import * # default path for the open/save dialogs -DEFAULT_FILE_PATH = os.getcwd() +DEFAULT_FILE_PATH = os.getcwd() if os.name != 'nt' else os.path.expanduser("~/Documents") FILE_EXTENSION = '.grc' # name for new/unsaved flow graphs @@ -101,6 +101,12 @@ Please consider contacting OOT module maintainer for any block in here \ and kindly ask to update their GRC Block Descriptions or Block Tree to include a module name.""" +# _SCREEN = Gdk.Screen.get_default() +# _SCREEN_RESOLUTION = _SCREEN.get_resolution() if _SCREEN else -1 +# DPI_SCALING = _SCREEN_RESOLUTION / 96.0 if _SCREEN_RESOLUTION > 0 else 1.0 +DPI_SCALING = 1.0 # todo: figure out the GTK3 way (maybe cairo does this for us + + def update_font_size(font_size): global PORT_SEPARATION, BLOCK_FONT, PORT_FONT, PARAM_FONT, FONT_SIZE diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index 0eb88952b7..09ecd48a13 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -90,7 +90,7 @@ class TextDisplay(SimpleTextDisplay): # for each \b delete one char from the buffer back_count = 0 start_iter = self.get_buffer().get_end_iter() - while line[back_count] == '\b': + while len(line) > back_count and line[back_count] == '\b': # stop at the beginning of a line if not start_iter.starts_line(): start_iter.backward_char() diff --git a/grc/gui/Executor.py b/grc/gui/Executor.py index 7168c9ef46..7c01d921bc 100644 --- a/grc/gui/Executor.py +++ b/grc/gui/Executor.py @@ -16,12 +16,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import + import os -import threading import shlex import subprocess -import sys -import re +import threading from distutils.spawn import find_executable from gi.repository import GLib @@ -39,6 +38,7 @@ class ExecFlowGraphThread(threading.Thread): threading.Thread.__init__(self) self.page = flow_graph_page # store page and dont use main window calls in run + self.flow_graph = self.page.get_flow_graph() self.xterm_executable = xterm_executable self.update_callback = callback @@ -54,16 +54,9 @@ class ExecFlowGraphThread(threading.Thread): """ Execute this python flow graph. """ - run_command = self.page.flow_graph.get_option('run_command') generator = self.page.get_generator() - - try: - run_command = run_command.format( - python=shlex_quote(sys.executable), - filename=shlex_quote(generator.file_path)) - run_command_args = shlex.split(run_command) - except Exception as e: - raise ValueError("Can't parse run command {!r}: {}".format(run_command, e)) + run_command = self.flow_graph.get_run_command(generator.file_path) + run_command_args = shlex.split(run_command) # When in no gui mode on linux, use a graphical terminal (looks nice) xterm_executable = find_executable(self.xterm_executable) @@ -99,21 +92,3 @@ class ExecFlowGraphThread(threading.Thread): Messages.send_end_exec(self.process.returncode) self.page.process = None self.update_callback() - - -########################################################### -# back-port from python3 -########################################################### -_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search - - -def shlex_quote(s): - """Return a shell-escaped version of the string *s*.""" - if not s: - return "''" - if _find_unsafe(s) is None: - return s - - # use single quotes, and put single quotes into double quotes - # the string $'b is then quoted as '$'"'"'b' - return "'" + s.replace("'", "'\"'\"'") + "'" diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py index e5657c288e..b79a85623f 100644 --- a/grc/gui/ParamWidgets.py +++ b/grc/gui/ParamWidgets.py @@ -20,7 +20,7 @@ import os from gi.repository import Gtk, Gdk -from . import Colors +from . import Colors, Utils class InputParam(Gtk.HBox): @@ -35,7 +35,7 @@ class InputParam(Gtk.HBox): self._editing_callback = editing_callback self.label = Gtk.Label() - self.label.set_size_request(150, -1) + self.label.set_size_request(Utils.scale_scalar(150), -1) self.label.show() self.pack_start(self.label, False, False, 0) diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 3a0f6ae6de..ca1e3c5296 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -51,7 +51,9 @@ class PropsDialog(Gtk.Dialog): Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY, ) self.set_response_sensitive(Gtk.ResponseType.APPLY, False) - self.set_size_request(Constants.MIN_DIALOG_WIDTH, Constants.MIN_DIALOG_HEIGHT) + self.set_size_request(*Utils.scale( + (Constants.MIN_DIALOG_WIDTH, Constants.MIN_DIALOG_HEIGHT) + )) self._block = block self._hash = 0 diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index 782a7e3a01..38fde80465 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -143,3 +143,13 @@ def make_screenshot(flow_graph, file_path, transparent_bg=False): if file_path.endswith('.pdf') or file_path.endswith('.svg'): cr.show_page() psurf.finish() + + +def scale(coor, reverse=False): + factor = Constants.DPI_SCALING if not reverse else 1 / Constants.DPI_SCALING + return tuple(int(x * factor) for x in coor) + + +def scale_scalar(coor, reverse=False): + factor = Constants.DPI_SCALING if not reverse else 1 / Constants.DPI_SCALING + return int(coor * factor) diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index 44dd2923eb..484395be8c 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -21,7 +21,7 @@ from __future__ import absolute_import from gi.repository import Gtk, Gdk, GObject -from . import Actions, Constants +from . import Actions, Constants, Utils BLOCK_INDEX = 0 ID_INDEX = 1 @@ -114,9 +114,9 @@ class VariableEditor(Gtk.VBox): id_column = Gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX) id_column.set_name("id") id_column.set_resizable(True) - id_column.set_max_width(300) - id_column.set_min_width(80) - id_column.set_fixed_width(100) + id_column.set_max_width(Utils.scale_scalar(300)) + id_column.set_min_width(Utils.scale_scalar(80)) + id_column.set_fixed_width(Utils.scale_scalar(100)) id_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) id_column.set_cell_data_func(self.id_cell, self.set_properties) self.id_column = id_column @@ -132,7 +132,7 @@ class VariableEditor(Gtk.VBox): value_column.set_name("value") value_column.set_resizable(False) value_column.set_expand(True) - value_column.set_min_width(100) + value_column.set_min_width(Utils.scale_scalar(100)) value_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) value_column.set_cell_data_func(self.value_cell, self.set_value) self.value_column = value_column diff --git a/grc/gui/canvas/block.py b/grc/gui/canvas/block.py index 7e28a21fc2..fc8a533397 100644 --- a/grc/gui/canvas/block.py +++ b/grc/gui/canvas/block.py @@ -69,7 +69,7 @@ class Block(CoreBlock, Drawable): Returns: the coordinate tuple (x, y) or (0, 0) if failure """ - return self.states['_coordinate'] + return Utils.scale(self.states['_coordinate']) @coordinate.setter def coordinate(self, coor): @@ -79,6 +79,7 @@ class Block(CoreBlock, Drawable): Args: coor: the coordinate tuple (x, y) """ + coor = Utils.scale(coor, reverse=True) if Actions.TOGGLE_SNAP_TO_GRID.get_active(): offset_x, offset_y = (0, self.height / 2) if self.is_horizontal() else (self.height / 2, 0) coor = ( diff --git a/grc/scripts/CMakeLists.txt b/grc/scripts/CMakeLists.txt index 9751952118..20366e0212 100644 --- a/grc/scripts/CMakeLists.txt +++ b/grc/scripts/CMakeLists.txt @@ -19,7 +19,7 @@ ######################################################################## GR_PYTHON_INSTALL( - PROGRAMS gnuradio-companion + PROGRAMS gnuradio-companion grcc DESTINATION ${GR_RUNTIME_DIR} ) diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion index 21d989164f..c1ffdf28bc 100755 --- a/grc/scripts/gnuradio-companion +++ b/grc/scripts/gnuradio-companion @@ -1,22 +1,20 @@ #!/usr/bin/env python -""" -Copyright 2016 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" +# Copyright 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import os import sys diff --git a/grc/scripts/grcc b/grc/scripts/grcc new file mode 100755 index 0000000000..c3a53a91a6 --- /dev/null +++ b/grc/scripts/grcc @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# Copyright 2016 Free Software Foundation, Inc. +# This file is part of GNU Radio +# +# GNU Radio Companion is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# GNU Radio Companion is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +import os +import sys + + +GR_IMPORT_ERROR_MESSAGE = """\ +Cannot import gnuradio. + +Is the model path environment variable set correctly? + All OS: PYTHONPATH + +Is the library path environment variable set correctly? + Linux: LD_LIBRARY_PATH + Windows: PATH + MacOSX: DYLD_LIBRARY_PATH +""" + + +def die(error, message): + msg = "{0}\n\n({1})".format(message, error) + exit(type(error).__name__ + '\n\n' + msg) + + +def check_gnuradio_import(): + try: + from gnuradio import gr + except ImportError as err: + die(err, GR_IMPORT_ERROR_MESSAGE) + + +def run_main(): + script_path = os.path.dirname(os.path.abspath(__file__)) + source_tree_subpath = "/grc/scripts" + + if not script_path.endswith(source_tree_subpath): + # run the installed version + from gnuradio.grc.compiler import main + else: + print("Running from source tree") + sys.path.insert(1, script_path[:-len(source_tree_subpath)]) + from grc.compiler import main + exit(main()) + + +if __name__ == '__main__': + check_gnuradio_import() + run_main() diff --git a/grc/tests/resources/test_compiler.grc b/grc/tests/resources/test_compiler.grc new file mode 100644 index 0000000000..cc56acedca --- /dev/null +++ b/grc/tests/resources/test_compiler.grc @@ -0,0 +1,253 @@ +<?xml version='1.0' encoding='utf-8'?> +<?grc format='1' created='3.7.11'?> +<flow_graph> + <timestamp>Thu Sep 15 12:56:40 2016</timestamp> + <block> + <key>options</key> + <param> + <key>author</key> + <value></value> + </param> + <param> + <key>window_size</key> + <value></value> + </param> + <param> + <key>category</key> + <value>[GRC Hier Blocks]</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>description</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 8)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>generate_options</key> + <value>no_gui</value> + </param> + <param> + <key>hier_block_src_path</key> + <value>.:</value> + </param> + <param> + <key>id</key> + <value>top_block</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>qt_qss_theme</key> + <value></value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>run_command</key> + <value>{python} -u {filename}</value> + </param> + <param> + <key>run_options</key> + <value>run</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>thread_safe_setters</key> + <value></value> + </param> + <param> + <key>title</key> + <value></value> + </param> + </block> + <block> + <key>blocks_add_const_vxx</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>const</key> + <value>1</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(360, 28)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_add_const_vxx_0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_null_sink</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>bus_conns</key> + <value>[[0,],]</value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(504, 32)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_null_sink_0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>num_inputs</key> + <value>1</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + </block> + <block> + <key>blocks_vector_source_x</key> + <param> + <key>alias</key> + <value></value> + </param> + <param> + <key>comment</key> + <value></value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>_coordinate</key> + <value>(208, 12)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + <param> + <key>id</key> + <value>blocks_vector_source_x_0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>repeat</key> + <value>False</value> + </param> + <param> + <key>tags</key> + <value>[]</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>vector</key> + <value>(0, 0, 0)</value> + </param> + </block> + <connection> + <source_block_id>blocks_add_const_vxx_0</source_block_id> + <sink_block_id>blocks_null_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_vector_source_x_0</source_block_id> + <sink_block_id>blocks_add_const_vxx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> +</flow_graph> diff --git a/grc/tests/test_compiler.py b/grc/tests/test_compiler.py new file mode 100644 index 0000000000..27b5670871 --- /dev/null +++ b/grc/tests/test_compiler.py @@ -0,0 +1,38 @@ +# Copyright 2016 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +from argparse import Namespace +from os import path +import tempfile + +from grc.compiler import main + + +def test_compiler(capsys): + args = Namespace( + output=tempfile.gettempdir(), + user_lib_dir=False, + grc_files=[path.join(path.dirname(__file__), 'resources', 'test_compiler.grc')], + run=True + ) + + main(args) + + out, err = capsys.readouterr() + assert not err |