diff --git a/lib/ramble/ramble/cmd/workspace.py b/lib/ramble/ramble/cmd/workspace.py index 76151431b..5ad0cf454 100644 --- a/lib/ramble/ramble/cmd/workspace.py +++ b/lib/ramble/ramble/cmd/workspace.py @@ -25,6 +25,7 @@ import ramble.config import ramble.workspace import ramble.workspace.shell +import ramble.expander import ramble.experiment_set import ramble.context import ramble.pipeline @@ -839,6 +840,15 @@ def workspace_list(args): def workspace_edit_setup_parser(subparser): """edit workspace config or template""" + subparser.add_argument( + "-f", + "--file", + dest="filename", + default=None, + help="Open a single file by filename", + required=False, + ) + subparser.add_argument( "-c", "--config_only", @@ -866,6 +876,14 @@ def workspace_edit_setup_parser(subparser): required=False, ) + subparser.add_argument( + "--all", + dest="all_files", + action="store_true", + help="Open all yaml and template files in workspace config directory", + required=False, + ) + subparser.add_argument( "-p", "--print-file", action="store_true", help="print the file name that would be edited" ) @@ -883,15 +901,28 @@ def workspace_edit(args): config_file = ramble.workspace.config_file(ramble_ws) template_files = ramble.workspace.all_template_paths(ramble_ws) - edit_files = [config_file] + template_files + edit_files = [config_file] + edit_files.extend(template_files) - if args.config_only: + if args.filename: + expander = ramble.expander.Expander( + ramble.workspace.Workspace.get_workspace_paths(ramble_ws), None + ) + # If filename contains expansion strings, edit expanded path. Else assume configs dir. + expanded_filename = expander.expand_var(args.filename) + if expanded_filename != args.filename: + edit_files = [expanded_filename] + else: + edit_files = [ramble.workspace.get_filepath(ramble_ws, expanded_filename)] + elif args.config_only: edit_files = [config_file] elif args.template_only: edit_files = template_files elif args.license_only: licenses_file = [ramble.workspace.licenses_file(ramble_ws)] edit_files = licenses_file + elif args.all_files: + edit_files = ramble.workspace.all_config_files(ramble_ws) + template_files if args.print_file: for f in edit_files: diff --git a/lib/ramble/ramble/test/cmd/workspace.py b/lib/ramble/ramble/test/cmd/workspace.py index 5f267f47c..698abc915 100644 --- a/lib/ramble/ramble/test/cmd/workspace.py +++ b/lib/ramble/ramble/test/cmd/workspace.py @@ -867,8 +867,19 @@ def test_edit_edits_correct_paths(): config_file = ramble.workspace.config_file(ws.root) default_template_path = ws.template_path("execute_experiment") + experiments_test_file = os.path.join(ws.experiment_dir, "test") ws_args = ["-w", "test"] + assert ( + workspace("edit", "-f", "ramble.yaml", "--print-file", global_args=ws_args).strip() + == config_file + ) + assert ( + workspace( + "edit", "-f", "{workspace_experiments}/test", "--print-file", global_args=ws_args + ).strip() + == experiments_test_file + ) assert workspace("edit", "-c", "--print-file", global_args=ws_args).strip() == config_file assert ( workspace("edit", "-t", "--print-file", global_args=ws_args).strip() diff --git a/lib/ramble/ramble/workspace/__init__.py b/lib/ramble/ramble/workspace/__init__.py index 5a3cdad71..27f0fa446 100644 --- a/lib/ramble/ramble/workspace/__init__.py +++ b/lib/ramble/ramble/workspace/__init__.py @@ -30,8 +30,10 @@ exists, is_workspace_dir, get_workspace_path, + get_filepath, config_file, config_file_name, + all_config_files, licenses_file, licenses_file_name, metadata_file_name, @@ -70,8 +72,10 @@ "exists", "is_workspace_dir", "get_workspace_path", + "get_filepath", "config_file", "config_file_name", + "all_config_files", "licenses_file", "licenses_file_name", "metadata_file_name", diff --git a/lib/ramble/ramble/workspace/workspace.py b/lib/ramble/ramble/workspace/workspace.py index 63452e143..4196dbc26 100644 --- a/lib/ramble/ramble/workspace/workspace.py +++ b/lib/ramble/ramble/workspace/workspace.py @@ -258,7 +258,7 @@ def active(name): return _active_workspace and name == _active_workspace.name -def get_yaml_filepath(path, file_name): +def get_filepath(path, file_name): if is_workspace_dir(path): return os.path.join(path, workspace_config_path, file_name) return None @@ -266,12 +266,24 @@ def get_yaml_filepath(path, file_name): def config_file(path): """Returns the path to a workspace's ramble.yaml""" - return get_yaml_filepath(path, config_file_name) + return get_filepath(path, config_file_name) def licenses_file(path): """Returns the path to a workspace's licenses.yaml""" - return get_yaml_filepath(path, licenses_file_name) + return get_filepath(path, licenses_file_name) + + +def all_config_files(path): + """Returns path to all yaml files in workspace config directory""" + config_files = [] + + config_path = os.path.join(path, workspace_config_path) + for f in os.listdir(config_path): + if f.endswith(".yaml"): + config_files.append(os.path.join(config_path, f)) + + return config_files def template_path(ws_path, requested_template_name): @@ -1847,21 +1859,28 @@ def all_auxiliary_software_files(self): """Iterator over each file in $workspace/configs/auxiliary_software_files""" yield from self._auxiliary_software_files.items() + @classmethod + def get_workspace_paths(cls, root): + """Construct dictionary of path replacements for workspace""" + workspace_path_replacements = { + "workspace_root": root, + "workspace": root, + "workspace_configs": os.path.join(root, workspace_config_path), + "workspace_software": os.path.join(root, workspace_software_path), + "workspace_logs": os.path.join(root, workspace_log_path), + "workspace_inputs": os.path.join(root, workspace_input_path), + "workspace_experiments": os.path.join(root, workspace_experiment_path), + "workspace_shared": os.path.join(root, workspace_shared_path), + "workspace_archives": os.path.join(root, workspace_archive_path), + "workspace_deployments": os.path.join(root, workspace_deployments_path), + } + + return workspace_path_replacements + def workspace_paths(self): """Dictionary of path replacements for workspace""" if not hasattr(self, "_workspace_path_replacements"): - self._workspace_path_replacements = { - "workspace_root": self.root, - "workspace": self.root, - "workspace_configs": self.config_dir, - "workspace_software": self.software_dir, - "workspace_logs": self.log_dir, - "workspace_inputs": self.input_dir, - "workspace_experiments": self.experiment_dir, - "workspace_shared": self.shared_dir, - "workspace_archives": self.archive_dir, - "workspace_deployments": self.deployments_dir, - } + self._workspace_path_replacements = self.get_workspace_paths(self.root) return self._workspace_path_replacements diff --git a/share/ramble/ramble-completion.bash b/share/ramble/ramble-completion.bash index 86d42b1ad..1f631e8a3 100755 --- a/share/ramble/ramble-completion.bash +++ b/share/ramble/ramble-completion.bash @@ -693,7 +693,7 @@ _ramble_workspace_info() { } _ramble_workspace_edit() { - RAMBLE_COMPREPLY="-h --help -c --config_only -t --template_only -l --license_only -p --print-file" + RAMBLE_COMPREPLY="-h --help -f --file -c --config_only -t --template_only -l --license_only --all -p --print-file" } _ramble_workspace_mirror() {