def load_layers(layer_paths): def map_to_layer_filenames(layer_paths): return config_io.glob(layer_paths) def map_to_filename_and_layer(layer_filename): return layer_filename, config_io.load(layer_filename) def do_store(layer_filename, layer): selected_layer_by_path[layer_filename] = layer def map_to_nested_layer_paths(layer_filename, layer): return R.path_or([], "LAYERS")(layer) def get_flat_list(list_of_lists): return R.uniq(R.flatten(list_of_lists)) x = map_to_layer_filenames(layer_paths) # [[layer_filename]] x = R.map(map_to_filename_and_layer)(x) # [layer_filename, layer] x = R.for_each(R.ds(do_store))(x) # [layer_filename, layer] x = R.map(R.ds(map_to_nested_layer_paths))(x) # [[layer_filename]] x = get_flat_list(x) # [layer_filename, layer] if x: load_layers(x)
def get_conflicts_in_layer_paths(layer_paths): generic_paths = {} def map_to_layer_path_and_parts(path): parts = os.path.basename(path).split(".") return path, parts def has_flavours(path, parts): return len(parts) == 3 def map_to_path_and_generic_path(path, parts): generic_path = os.path.join(os.path.dirname(path), parts[0]) return path, generic_path def is_conflict(path, generic_path): result = bool(generic_paths.get(generic_path, None)) if not result: generic_paths[generic_path] = path return result x = layer_paths # [path] x = R.map(map_to_layer_path_and_parts)(x) # [(path, parts)] x = R.filter(R.ds(has_flavours))(x) # [(path, parts)] x = R.map(R.ds(map_to_path_and_generic_path))(x) # [(path, generic_path)] x = R.filter(R.ds(is_conflict))(x) return x
def get_layer_paths_from_command_prefix( command_prefix, metadata_by_layer_name, layer_paths_from_command_prefix, ): def map_to_path(layer_name): if layer_name not in metadata_by_layer_name: known_layer_names = metadata_by_layer_name.keys() raise CommandError( "Unknown layer: %s. Known layers: %s" % (layer_name, ", ".join(known_layer_names)) ) return metadata_by_layer_name[layer_name].target_path layer_names = R.uniq(R.filter(bool)(command_prefix.split("."))) return dict( layer_paths_from_command_prefix=R.map(map_to_path)(layer_names) or layer_paths_from_command_prefix )
def load_named_layers( config_io, metadata_by_layer_name, ): layer_by_target_path = {} def get_target_paths_and_layer_names(): result = {} for layer_name, layer_metadata in metadata_by_layer_name.items(): result[layer_name] = layer_metadata.target_path return result.items() def do_check_valid_target_path(layer_name, target_path): if "*" in target_path: raise CommandError("Layer_name may not contain wildcards: %s" % target_path) if not config_io.glob([target_path]): sys.stderr.write( "Warning: layer not found: %s. Check /LAYER_GROUPS for layer %s\n" % (target_path, layer_name)) def add_layer(layer_name, target_path): is_found = config_io.glob([target_path]) layer = config_io.load(target_path) if is_found else {} return layer_name, target_path, layer def do_store(layer_name, target_path, layer): layer_by_target_path[target_path] = layer x = get_target_paths_and_layer_names() # [path, layer_name] x = R.for_each(R.ds(do_check_valid_target_path))(x) # [path, layer_name] x = R.map(R.ds(add_layer))(x) # [(path, layer_name, layer)] R.for_each(R.ds(do_store))(x) return layer_by_target_path
def _collect_command_dirs( config, config_io, layer_names_by_command_dir, command_aliases, metadata_by_layer_name, layer_by_target_path, ): config_memo = yaml_round_trip_dump(config) for layer_name, layer_metadata in metadata_by_layer_name.items(): def has_command_path(layer): return R.path_or(None, "ROOT", "command_path")(layer) layer_filenames = layer_filename_superset( [layer_metadata.target_path], config_io=config_io ) extra_layers = R.map(config_io.load)(layer_filenames) if R.filter(has_command_path)(extra_layers): base_config = yaml_round_trip_load(config_memo) updated_config, warnings = build_config([base_config] + extra_layers) for command_dir in get_command_dirs_from_config(updated_config): layer_names = layer_names_by_command_dir[command_dir] _add_to_layer_names(layer_names, layer_name) layer = layer_by_target_path[layer_metadata.target_path] for command_alias in get_aliases(layer).items(): alias_prefix = ( "" if command_alias[0] in layer_metadata.inferred_commands else (layer_name + ".") ) cmd_prefix = layer_name + "." command_aliases[alias_prefix + command_alias[0]] = ( cmd_prefix + command_alias[1] )
def handle_arg_complete( command_names, inferred_command_names, command_aliases, metadata_by_layer_name, layer_by_target_path, ): def get_args(): return os.environ["COMP_LINE"].split() def get_prefix_and_command(args): return R.split(args[1].rfind(".") + 1)(args[1]) input_args = get_args() full_command_name = input_args[1] # [arg] (command_prefix, command_name) = get_prefix_and_command(input_args) def get_used_layer_names(command_prefix): return [ x for x in command_prefix.split(".") if x in metadata_by_layer_name ] used_layer_names = get_used_layer_names(command_prefix) def get_commands(): more_aliases = [] for layer_name in used_layer_names: layer_metadata = metadata_by_layer_name[layer_name] layer = layer_by_target_path[layer_metadata.target_path] more_aliases.extend(get_aliases(layer).keys()) return R.uniq(command_names + inferred_command_names + command_aliases + more_aliases) def get_choices(commands): return [(command_prefix + x) for x in commands] commands = get_commands() # [command_name] choices = get_choices(commands) # [choice] def get_possible_layer_names(): return metadata_by_layer_name.keys() def is_already_used(layer_name): return layer_name in used_layer_names def is_conflicting(layer_name): used_layer_metadata = R.map(metadata_by_layer_name)(used_layer_names) used_layer_paths = [x.target_path for x in used_layer_metadata] layer_path = metadata_by_layer_name[layer_name].target_path return get_conflicts_in_layer_paths(used_layer_paths + [layer_path]) def map_to_choices(layer_name): return [command_prefix + layer_name + "." + x for x in commands] x = get_possible_layer_names() # [layer_name] x = R.remove_if(is_already_used)(x) # [layer_name] x = R.remove_if(is_conflicting)(x) # [layer_name] new_choices = R.map(map_to_choices)(x) # [[new_choice]] choices += R.flatten(new_choices) if full_command_name not in choices: parser = ArgumentParser() parser.add_argument("command", choices=choices) argcomplete.autocomplete(parser) # Hack to make argcomplete work with zsh os.environ["COMP_POINT"] = str(len(os.environ["COMP_LINE"])) return command_name
def is_conflicting(layer_name): used_layer_metadata = R.map(metadata_by_layer_name)(used_layer_names) used_layer_paths = [x.target_path for x in used_layer_metadata] layer_path = metadata_by_layer_name[layer_name].target_path return get_conflicts_in_layer_paths(used_layer_paths + [layer_path])