Skip to content

Commit fdf211c

Browse files
committed
CLI
1 parent 4c4225a commit fdf211c

4 files changed

Lines changed: 65 additions & 1 deletion

File tree

docs/docs/reference/cli/dstack/import.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,18 @@ $ dstack import list --help
1717
```
1818

1919
</div>
20+
21+
## dstack import delete
22+
23+
The `dstack import delete` command deletes the specified import. This makes the imported resources unavailable in your project, while they still exist in the host project.
24+
25+
##### Usage
26+
27+
<div class="termy">
28+
29+
```shell
30+
$ dstack import delete --help
31+
#GENERATE#
32+
```
33+
34+
</div>

src/dstack/_internal/cli/commands/import_.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from rich.table import Table
44

55
from dstack._internal.cli.commands import APIBaseCommand
6-
from dstack._internal.cli.utils.common import add_row_from_dict, console
6+
from dstack._internal.cli.services.completion import ImportNameCompleter
7+
from dstack._internal.cli.utils.common import add_row_from_dict, confirm_ask, console
78
from dstack._internal.core.models.imports import Import
89

910

@@ -21,6 +22,18 @@ def _register(self):
2122
)
2223
list_parser.set_defaults(subfunc=self._list)
2324

25+
delete_parser = subparsers.add_parser(
26+
"delete", help="Delete an import", formatter_class=self._parser.formatter_class
27+
)
28+
delete_parser.add_argument(
29+
"name",
30+
help="The import to delete, in `export-project/export-name` format",
31+
).completer = ImportNameCompleter() # type: ignore[attr-defined]
32+
delete_parser.add_argument(
33+
"-y", "--yes", help="Don't ask for confirmation", action="store_true"
34+
)
35+
delete_parser.set_defaults(subfunc=self._delete)
36+
2437
def _command(self, args: argparse.Namespace):
2538
super()._command(args)
2639
args.subfunc(args)
@@ -29,6 +42,27 @@ def _list(self, args: argparse.Namespace):
2942
imports = self.api.client.imports.list(self.api.project)
3043
print_imports_table(imports)
3144

45+
def _delete(self, args: argparse.Namespace):
46+
parts = args.name.split("/")
47+
if len(parts) != 2 or not parts[0] or not parts[1]:
48+
self._parser.error(
49+
f"Invalid format: {args.name!r}. Expected <export-project>/<export-name>"
50+
)
51+
export_project_name, export_name = parts
52+
53+
if not args.yes and not confirm_ask(f"Delete the import [code]{args.name}[/]?"):
54+
console.print("\nExiting...")
55+
return
56+
57+
with console.status("Deleting import..."):
58+
self.api.client.imports.delete(
59+
project_name=self.api.project,
60+
export_project_name=export_project_name,
61+
export_name=export_name,
62+
)
63+
64+
console.print(f"Import [code]{args.name}[/] deleted")
65+
3266

3367
def print_imports_table(imports: list[Import]):
3468
table = Table(box=None)

src/dstack/_internal/cli/services/completion.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ def fetch_resource_names(self, api: Client) -> Iterable[str]:
8585
return [r.name for r in api.client.exports.list(api.project)]
8686

8787

88+
class ImportNameCompleter(BaseAPINameCompleter):
89+
def fetch_resource_names(self, api: Client) -> Iterable[str]:
90+
return [
91+
f"{imp.export.project_name}/{imp.export.name}"
92+
for imp in api.client.imports.list(api.project)
93+
]
94+
95+
8896
class ProjectNameCompleter(BaseCompleter):
8997
"""
9098
Completer for local project names.

src/dstack/api/server/_imports.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@
33
from pydantic import parse_obj_as
44

55
from dstack._internal.core.models.imports import Import
6+
from dstack._internal.server.schemas.imports import DeleteImportRequest
67
from dstack.api.server._group import APIClientGroup
78

89

910
class ImportsAPIClient(APIClientGroup):
1011
def list(self, project_name: str) -> List[Import]:
1112
resp = self._request(f"/api/project/{project_name}/imports/list")
1213
return parse_obj_as(List[Import.__response__], resp.json())
14+
15+
def delete(self, *, project_name: str, export_project_name: str, export_name: str) -> None:
16+
body = DeleteImportRequest(
17+
export_project_name=export_project_name, export_name=export_name
18+
)
19+
self._request(f"/api/project/{project_name}/imports/delete", body=body.json())

0 commit comments

Comments
 (0)