def __LoadGroup(self, module_directory, parent_group, module_path=None, allow_non_existing_modules=False, exception_if_present=None, top_group=None): """Loads a single command group from a directory. Args: module_directory: The path to the location of the module. parent_group: backend.CommandGroup, The parent command group for this command group, or None if this is the top group. module_path: An optional name override for the module. If not set, it will default to using the name of the directory containing the module. allow_non_existing_modules: True to allow this module directory to not exist, False to raise an exception if this module does not exist. exception_if_present: Exception, An exception to throw if the module actually exists, or None. top_group: backend.CommandGroup, The top command group for this CLI. Raises: LayoutException: If the module directory does not exist and allow_non_existing is False. Returns: The backend.CommandGroup object, or None if the module directory does not exist and allow_non_existing is True. """ if not os.path.isdir(module_directory): if allow_non_existing_modules: return None raise backend.LayoutException( 'The given module directory does not exist: {}'.format( module_directory)) elif exception_if_present: # pylint: disable=raising-bad-type, This will be an actual exception. raise exception_if_present module_root, module = os.path.split(module_directory) if not module_path: module_path = [module] # If this is the top level, don't register the name of the module directory # itself, it should assume the name of the command. If this is another # module directory, its name gets explicitly registered under the root # command. is_top = not parent_group sub_parser = parent_group.SubParser() if parent_group else None path = [self.__name] if is_top else [self.__name] + module_path group = backend.CommandGroup(module_root, [module], path, uuid.uuid4().hex, self, sub_parser, self.__config_hooks, help_func=self.__help_func, parent_group=top_group) return group
def __LoadTopGroup(self, group_info): """Actually loads the top group of the CLI based on the given group_info. Args: group_info: A tuple of (module_dir, module_path, name) generated by self.__GetGroupInfo() Returns: The backend.CommandGroup object. """ (module_root, module, name, release_track) = group_info return backend.CommandGroup(module_root, module, [name], release_track, uuid.uuid4().hex, self, None)
def __LoadTopGroup(self, group_info): """Actually loads the top group of the CLI based on the given group_info. Args: group_info: A tuple of (module_dir, module_path, path) generated by self.__GetGroupInfo() Returns: The backend.CommandGroup object. """ (module_root, module, path) = group_info return backend.CommandGroup( module_root, module, path, uuid.uuid4().hex, self, None, self.__config_hooks, help_func=self.__help_func)
def Generate(self): """Uses the registered information to generate the CLI tool. Returns: CLI, The generated CLI tool. """ # The root group of the CLI. impl_path = self.__ValidateCommandOrGroupInfo( self.__command_root_directory, allow_non_existing_modules=False) top_group = backend.CommandGroup([impl_path], [self.__name], calliope_base.ReleaseTrack.GA, uuid.uuid4().hex, self, None) self.__AddBuiltinGlobalFlags(top_group) # Sub groups for each alternate release track. loaded_release_tracks = dict([(calliope_base.ReleaseTrack.GA, top_group)]) track_names = set(track.prefix for track in self.__release_tracks.keys()) for track, (module_dir, component) in self.__release_tracks.iteritems(): impl_path = self.__ValidateCommandOrGroupInfo( module_dir, allow_non_existing_modules=self.__allow_non_existing_modules) if impl_path: # Add the release track sub group into the top group. # pylint: disable=protected-access top_group._groups_to_load[track.prefix] = [impl_path] # Override the release track because this is specifically a top level # release track group. track_group = top_group.LoadSubElement( track.prefix, allow_empty=True, release_track_override=track) # Copy all the root elements of the top group into the release group. top_group.CopyAllSubElementsTo(track_group, ignore=track_names) loaded_release_tracks[track] = track_group elif component: self.__missing_components[track.prefix] = component # Load the normal set of registered sub groups. for module_dot_path, module_dir_path, component in self.__modules: is_command = module_dir_path.endswith(_COMMAND_SUFFIX) if is_command: module_dir_path = module_dir_path[:-len(_COMMAND_SUFFIX)] match = CLILoader.PATH_RE.match(module_dot_path) root, name = match.group(1, 2) try: # Mount each registered sub group under each release track that exists. for track, track_root_group in loaded_release_tracks.iteritems( ): parent_group = self.__FindParentGroup( track_root_group, root) exception_if_present = None if not parent_group: if track != calliope_base.ReleaseTrack.GA: # Don't error mounting sub groups if the parent group can't be # found unless this is for the GA group. The GA should always be # there, but for alternate release channels, the parent group # might not be enabled for that particular release channel, so it # is valid to not exist. continue exception_if_present = command_loading.LayoutException( 'Root [{root}] for command group [{group}] does not exist.' .format(root=root, group=name)) cmd_or_grp_name = module_dot_path.split('.')[-1] impl_path = self.__ValidateCommandOrGroupInfo( module_dir_path, allow_non_existing_modules=self. __allow_non_existing_modules, exception_if_present=exception_if_present) if impl_path: # pylint: disable=protected-access if is_command: parent_group._commands_to_load[cmd_or_grp_name] = [ impl_path ] else: parent_group._groups_to_load[cmd_or_grp_name] = [ impl_path ] elif component: prefix = track.prefix + '.' if track.prefix else '' self.__missing_components[prefix + module_dot_path] = component except command_loading.CommandLoadFailure as e: log.exception(e) cli = self.__MakeCLI(top_group) return cli