def __find_file(self, name, revision='*'): yang_file = find_first_file('/'.join(self.__path.split('/')[0:-1]), name + '.yang', name + '@' + revision + '.yang') if yang_file is None: yang_file = find_first_file(self.__yang_models, name + '.yang', name + '@' + revision + '.yang') return yang_file
def __find_file(self, name, revision='*', submodule=False, normal_search=True): yang_file = find_first_file('/'.join(self.__path.split('/')[0:-1]), name + '.yang' , name + '@' + revision + '.yang') if yang_file is None: if normal_search: if submodule: self.__missing_submodules.append(name) else: self.__missing_modules.append(name) yang_file = find_first_file(self.yang_models, name + '.yang', name + '@' + revision + '.yang') return yang_file
def _parse_imp_inc(self, modules: list, set_of_names: set, is_include: bool, schema_base: str): """ Parse all yang modules which are either sumodules or imports of a certain module. Submodules and import modules are also added to the dumper object. This method is then recursively called for all found submodules and imported modules. Arguments: :param modules (list) List of modules to check (either submodules or imports of module) :param set_of_namea (set) Set of all the modules parsed out from the capability file :param is_include (bool) Whether module is include or not :param schema_base (str) url to a raw module on github up to and not including the commit hash """ for module in modules: if not is_include: name = module.arg conformance_type = 'import' else: name = module.name conformance_type = None # Skip if name of submodule/import is already in list of module names if name not in set_of_names: LOGGER.info('Parsing module {}'.format(name)) set_of_names.add(name) pattern = '{}.yang'.format(name) pattern_with_revision = '{}@*.yang'.format(name) yang_file = find_first_file(os.path.dirname(self.xml_file), pattern, pattern_with_revision, self.dir_paths['yang_models']) if yang_file is None: return try: try: yang = VendorModule(name, yang_file, self.parsed_jsons, self.dir_paths, self.commit_hash, self.dumper.yang_modules, schema_base, submodule_name=self.submodule_name) except ParseException: LOGGER.exception( 'ParseException while parsing {}'.format(name)) continue yang.add_vendor_information(self.platform_data, conformance_type, self.capabilities, self.netconf_versions) self.dumper.add_module(yang) self._parse_imp_inc(yang.submodule, set_of_names, True, schema_base) self._parse_imp_inc(yang.imports, set_of_names, False, schema_base) except FileNotFoundError: LOGGER.warning( 'File {} not found in the repository'.format(name))
def _find_file(self, name: str, revision: str = '*'): yang_name = '{}.yang'.format(name) yang_name_rev = '{}@{}.yang'.format(name, revision) directory = '/'.join(self._path.split('/')[0:-1]) yang_file = find_first_file(directory, yang_name, yang_name_rev, self._yang_models) return yang_file
def resolve_organization(path: str, parsed_yang) -> str: """Parse yang file and resolve organization out of the module. If the module is a submodule find it's parent and resolve its organization Arguments: :param path: (str) path to a file to parse and resolve a organization :param parsed_yang (object) pyang parsed yang file object :return: (str) organization the yang file belongs to """ organization = None results = parsed_yang.search('organization') if results: result = results[0].arg.lower() if 'cisco' in result: organization = 'cisco' elif 'ietf' in result: organization = 'ietf' namespace = None results = parsed_yang.search('namespace') if results: namespace = results[0].arg.lower() else: results = parsed_yang.search('belongs-to') if results: belongs_to = results[0].arg pattern = '{}.yang'.format(belongs_to) pattern_with_revision = '{}@*.yang'.format(belongs_to) results = None yang_file = find_first_file(os.path.dirname(path), pattern, pattern_with_revision) if yang_file is None: yang_file = find_first_file('/'.join(path.split('/')[:-2]), pattern, pattern_with_revision) if yang_file is not None: try: parsed = yangParser.parse(os.path.abspath(yang_file)) if parsed: results = parsed.search('namespace') if results: namespace = results[0].arg.lower() except yangParser.ParseException: pass if namespace is None: return MISSING_ELEMENT else: return match_organization(namespace, organization)
def test_find_first_file_empty_arguments(self): """ Test result of method, when empty strings are passed as an argument. Nothing should be found in this case. """ directory = '' pattern = '' pattern_with_revision = '' result = util.find_first_file(directory, pattern, pattern_with_revision) self.assertEqual(result, None)
def test_find_first_file_without_revision_empty_search( self, mock_yang_parse: mock.MagicMock): """ Try to find the first file that matches the pattern without specified revision. It will try to parse the yang module to get its revision, but exception occur during parsing. """ mock_yang_parse.return_value.search.return_value = [] pattern = 'ietf-yang-types.yang' pattern_with_revision = '*****@*****.**' result = util.find_first_file(self.util_tests_dir, pattern, pattern_with_revision) self.assertEqual(result, None)
def test_find_first_file_without_revision(self): """ Try to find the first file that matches the pattern without specified revision. It will try to parse the yang module to get its revision and check if that revision is also in 'pattern_with_revision' variable. """ pattern = 'ietf-yang-types.yang' pattern_with_revision = '*****@*****.**' result = util.find_first_file(self.util_tests_dir, pattern, pattern_with_revision) self.assertEqual(result, '{}/ietf-yang-types.yang'.format(self.util_tests_dir))
def test_find_first_file_with_wildcard_revision(self): """ Try to find the first file that matches the pattern with an unspecified revision (specified by an asterisk). Test if a module with the same name and without revision in name is returned. """ pattern = 'ietf-yang-types.yang' pattern_with_revision = 'ietf-yang-types@*.yang' result = util.find_first_file(self.util_tests_dir, pattern, pattern_with_revision) self.assertEqual(result, '{}/ietf-yang-types.yang'.format(self.util_tests_dir))
def test_find_first_file_with_specific_revision(self): """ Try to find the first file that matches the pattern with specific revision. Test if a module with the same name and revision was found. """ pattern = 'ietf-yang-types.yang' pattern_with_revision = '*****@*****.**' result = util.find_first_file(self.util_tests_dir, pattern, pattern_with_revision) self.assertEqual( result, '{}/[email protected]'.format(self.util_tests_dir))
def check_dependencies(dep_type: t.Literal['import', 'include'], parsed_module: Statement, directory: str, yang_models_dir: str) -> t.Tuple[t.Set[str], t.Set[str]]: all_modules: t.Set[str] = set() missing_modules: t.Set[str] = set() for dependency in parsed_module.search(dep_type): name = dependency.arg all_modules.add(name) revisions = dependency.search('revision-date') revision = revisions[0].arg if revisions else '*' pattern = '{}.yang'.format(name) pattern_with_revision = '{}@{}.yang'.format(name, revision) if not find_first_file(directory, pattern, pattern_with_revision, yang_models_dir): # TODO: if the matched filename doesn't include the revision, maybe we should check it? if revision != '*': missing_modules.add('{}@{}'.format(name, revision)) else: missing_modules.add(name) return all_modules, missing_modules
def _find_file(self, name: str, revision: str = '*') -> t.Optional[str]: pattern = '{}.yang'.format(name) pattern_with_revision = '{}@{}.yang'.format(name, revision) yang_file = find_first_file(os.path.dirname(self._path), pattern, pattern_with_revision, self.yang_models) return yang_file