|
25 | 25 | import tabulate
|
26 | 26 | import requests
|
27 | 27 | import simvue as simvue_client
|
28 |
| -from simvue.api.objects import Alert, Run, Folder, S3Storage, Tag, Storage |
| 28 | +from simvue.api.objects import Alert, Run, Folder, S3Storage, Tag, Storage, Artifact |
29 | 29 | from simvue.api.objects.administrator import User, Tenant
|
30 | 30 | from simvue.exception import ObjectNotFoundError
|
31 | 31 |
|
@@ -910,10 +910,27 @@ def get_folder_json(folder_id: str) -> None:
|
910 | 910 | @simvue.group("tag")
|
911 | 911 | @click.pass_context
|
912 | 912 | def simvue_tag(ctx) -> None:
|
913 |
| - """Create or retrieve Simvue runs""" |
| 913 | + """Create or retrieve Simvue tags""" |
914 | 914 | pass
|
915 | 915 |
|
916 | 916 |
|
| 917 | +@simvue_tag.command("create") |
| 918 | +@click.pass_context |
| 919 | +@click.argument("name", type=SimvueName) |
| 920 | +@click.option( |
| 921 | + "--color", |
| 922 | + type=str, |
| 923 | + default=None, |
| 924 | + help="Color for this tag, e.g. '#fffff', 'blue', 'rgb(23, 54, 34)'", |
| 925 | +) |
| 926 | +@click.option("--description", type=str, default=None, help="Description for this tag.") |
| 927 | +def create_tag(ctx, **kwargs) -> None: |
| 928 | + """Create a tag""" |
| 929 | + result = simvue_cli.actions.create_simvue_tag(**kwargs) |
| 930 | + alert_id = result.id |
| 931 | + click.echo(alert_id if ctx.obj["plain"] else click.style(alert_id)) |
| 932 | + |
| 933 | + |
917 | 934 | @simvue_tag.command("list")
|
918 | 935 | @click.pass_context
|
919 | 936 | @click.option(
|
@@ -961,6 +978,7 @@ def tag_list(
|
961 | 978 | color: bool,
|
962 | 979 | **kwargs,
|
963 | 980 | ) -> None:
|
| 981 | + """Retrieve tags list from Simvue server.""" |
964 | 982 | tags = simvue_cli.actions.get_tag_list(**kwargs)
|
965 | 983 | if not tags:
|
966 | 984 | return
|
@@ -1007,6 +1025,60 @@ def get_tag_json(tag_id: str) -> None:
|
1007 | 1025 | click.echo(error_msg, fg="red", bold=True)
|
1008 | 1026 |
|
1009 | 1027 |
|
| 1028 | +@simvue_tag.command("remove") |
| 1029 | +@click.pass_context |
| 1030 | +@click.argument("tag_ids", type=str, nargs=-1, required=False) |
| 1031 | +@click.option( |
| 1032 | + "-i", |
| 1033 | + "--interactive", |
| 1034 | + help="Prompt for confirmation on removal", |
| 1035 | + type=bool, |
| 1036 | + default=False, |
| 1037 | + is_flag=True, |
| 1038 | +) |
| 1039 | +def delete_tag(ctx, tag_ids: list[str] | None, interactive: bool) -> None: |
| 1040 | + """Remove a tag from the Simvue server""" |
| 1041 | + if not tag_ids: |
| 1042 | + tag_ids = [] |
| 1043 | + for line in sys.stdin: |
| 1044 | + if not line.strip(): |
| 1045 | + continue |
| 1046 | + tag_ids += [k.strip() for k in line.split(" ")] |
| 1047 | + |
| 1048 | + for tag_id in tag_ids: |
| 1049 | + try: |
| 1050 | + simvue_cli.actions.get_tag(tag_id) |
| 1051 | + except (ObjectNotFoundError, RuntimeError): |
| 1052 | + error_msg = f"Tag '{tag_id}' not found" |
| 1053 | + if ctx.obj["plain"]: |
| 1054 | + print(error_msg) |
| 1055 | + else: |
| 1056 | + click.secho(error_msg, fg="red", bold=True) |
| 1057 | + sys.exit(1) |
| 1058 | + |
| 1059 | + if interactive: |
| 1060 | + remove = click.confirm(f"Remove tag '{tag_id}'?") |
| 1061 | + if not remove: |
| 1062 | + continue |
| 1063 | + |
| 1064 | + try: |
| 1065 | + simvue_cli.actions.delete_tag(tag_id) |
| 1066 | + except ValueError as e: |
| 1067 | + click.echo( |
| 1068 | + e.args[0] |
| 1069 | + if ctx.obj["plain"] |
| 1070 | + else click.style(e.args[0], fg="red", bold=True) |
| 1071 | + ) |
| 1072 | + sys.exit(1) |
| 1073 | + |
| 1074 | + response_message = f"Tag '{tag_id}' removed successfully." |
| 1075 | + |
| 1076 | + if ctx.obj["plain"]: |
| 1077 | + print(response_message) |
| 1078 | + else: |
| 1079 | + click.secho(response_message, bold=True, fg="green") |
| 1080 | + |
| 1081 | + |
1010 | 1082 | @simvue.group("admin")
|
1011 | 1083 | @click.pass_context
|
1012 | 1084 | def admin(ctx) -> None:
|
@@ -1619,15 +1691,23 @@ def list_storages(
|
1619 | 1691 | help="Specify target language",
|
1620 | 1692 | type=click.Choice(["python", "rust", "julia", "nodejs"]),
|
1621 | 1693 | )
|
1622 |
| -@click.option("--run", required=True, help="ID of run to clone environment from") |
| 1694 | +@click.option( |
| 1695 | + "--run", required=False, help="ID of run to clone environment from", default="" |
| 1696 | +) |
1623 | 1697 | @click.option(
|
1624 | 1698 | "--allow-existing",
|
1625 | 1699 | is_flag=True,
|
1626 | 1700 | help="Install dependencies in an existing environment",
|
1627 | 1701 | )
|
1628 | 1702 | @click.argument("venv_directory", type=click.Path(exists=False))
|
1629 | 1703 | def venv_setup(ctx, **kwargs) -> None:
|
1630 |
| - """Initialise virtual environments from run metadata.""" |
| 1704 | + """Initialise virtual environments from run metadata. |
| 1705 | +
|
| 1706 | + If a run ID is not provided via --run it is read from stdin. |
| 1707 | + """ |
| 1708 | + if not kwargs.get("run"): |
| 1709 | + kwargs["run"] = input() |
| 1710 | + |
1631 | 1711 | try:
|
1632 | 1712 | simvue_cli.actions.create_environment(**kwargs)
|
1633 | 1713 | except (FileExistsError, RuntimeError) as e:
|
@@ -1746,5 +1826,25 @@ def artifact_list(
|
1746 | 1826 | click.echo(table)
|
1747 | 1827 |
|
1748 | 1828 |
|
| 1829 | +@simvue_artifact.command("json") |
| 1830 | +@click.pass_context |
| 1831 | +@click.argument("artifact_id", required=False) |
| 1832 | +def get_artifact_json(ctx, artifact_id: str) -> None: |
| 1833 | + """Retrieve artifact information from Simvue server |
| 1834 | +
|
| 1835 | + If no ARTIFACT_ID is provided the input is read from stdin |
| 1836 | + """ |
| 1837 | + if not artifact_id: |
| 1838 | + artifact_id = input() |
| 1839 | + |
| 1840 | + try: |
| 1841 | + artifact: Artifact = simvue_cli.actions.get_artifact(artifact_id) |
| 1842 | + artifact_info = artifact.to_dict() |
| 1843 | + click.echo(json.dumps(dict(artifact_info.items()), indent=2)) |
| 1844 | + except ObjectNotFoundError as e: |
| 1845 | + error_msg = f"Failed to retrieve artifact '{artifact_id}': {e.args[0]}" |
| 1846 | + click.echo(error_msg, fg="red", bold=True) |
| 1847 | + |
| 1848 | + |
1749 | 1849 | if __name__ in "__main__":
|
1750 | 1850 | simvue()
|
0 commit comments