1#
2# Copyright 2018 Free Software Foundation, Inc.
3#
4# This file is part of GNU Radio
5#
6# GNU Radio is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3, or (at your option)
9# any later version.
10#
11# GNU Radio is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with GNU Radio; see the file COPYING.  If not, write to
18# the Free Software Foundation, Inc., 51 Franklin Street,
19# Boston, MA 02110-1301, USA.
20#
21""" Module to convert XML bindings to YAML bindings """
22
23from __future__ import print_function
24from __future__ import absolute_import
25from __future__ import unicode_literals
26
27import os
28import re
29import glob
30import logging
31
32from .base import ModTool, ModToolException
33from ..tools import get_modname
34
35logger = logging.getLogger(__name__)
36
37
38def get_xml_candidates():
39    """ Returns a list of XML candidates for update """
40    xml_candidates = []
41    xml_files = [x for x in glob.glob1("grc", "*.xml")]
42    mod_name = get_modname()
43    for candidate in xml_files:
44        candidate = os.path.splitext(candidate)[0]
45        candidate = candidate.split(mod_name + "_", 1)[-1]
46        xml_candidates.append(candidate)
47    return xml_candidates
48
49
50class ModToolUpdate(ModTool):
51    """ Update the grc bindings for a block """
52    name = 'update'
53    description = 'Update the grc bindings for a block'
54
55    def __init__(self, blockname=None, complete=False, **kwargs):
56        ModTool.__init__(self, blockname, **kwargs)
57        self.info['complete'] = complete
58
59
60    def validate(self):
61        """ Validates the arguments """
62        ModTool._validate(self)
63        if self.info['complete']:
64            return
65        if not self.info['blockname'] or self.info['blockname'].isspace():
66            raise ModToolException('Block name not specified!')
67        block_candidates = get_xml_candidates()
68        if self.info['blockname'] not in block_candidates:
69            choices = [x for x in block_candidates if self.info['blockname'] in x]
70            if len(choices) > 0:
71                print("Suggested alternatives: "+str(choices))
72            raise ModToolException("The XML bindings does not exists!")
73
74    def run(self):
75        from gnuradio.grc.converter import Converter
76        if not self.cli:
77            self.validate()
78        logger.warning("Warning: This is an experimental feature. Please verify the bindings.")
79        module_name = self.info['modname']
80        path = './grc/'
81        conv = Converter(path, path)
82        if self.info['complete']:
83            blocks = get_xml_candidates()
84        else:
85            blocks = [self.info['blockname']]
86        for blockname in blocks:
87            xml_file = "{}_{}.xml".format(module_name, blockname)
88            yml_file = "{}_{}.block.yml".format(module_name, blockname)
89            conv.load_block_xml(path+xml_file)
90            logger.info("Converted {} to {}".format(xml_file, yml_file))
91            os.remove(path+xml_file)
92            nsubs = self._run_cmakelists(xml_file, yml_file)
93            if nsubs > 1:
94                logger.warning("Changed more than expected for the block '%s' in the CMakeLists.txt. "
95                               "Please verify the CMakeLists manually.", blockname)
96            elif nsubs == 0:
97                logger.warning("No entry found for the block '%s' in the CMakeLists.txt. "
98                               'Please verify the CMakeLists manually.', blockname)
99            else:
100                logger.info('Updated the CMakeLists.txt')
101
102    def _run_cmakelists(self, to_remove, to_add):
103        """ Changes in the CMakeLists """
104        filename = './grc/CMakeLists.txt'
105        with open(filename) as f:
106            cfile = f.read()
107        (cfile, nsubs) = re.subn(to_remove, to_add, cfile)
108        with open(filename, 'w') as f:
109            f.write(cfile)
110        self.scm.mark_file_updated(filename)
111        return nsubs
112