arkitekt-next 0.7.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arkitekt-next might be problematic. Click here for more details.
- arkitekt_next/__init__.py +43 -0
- arkitekt_next/apps/__init__.py +3 -0
- arkitekt_next/apps/easy.py +99 -0
- arkitekt_next/apps/next.py +40 -0
- arkitekt_next/apps/qt.py +97 -0
- arkitekt_next/apps/service/__init__.py +3 -0
- arkitekt_next/apps/service/fakts.py +88 -0
- arkitekt_next/apps/service/fakts_next.py +79 -0
- arkitekt_next/apps/service/fakts_qt.py +82 -0
- arkitekt_next/apps/service/fluss_next.py +31 -0
- arkitekt_next/apps/service/grant_registry.py +27 -0
- arkitekt_next/apps/service/herre.py +24 -0
- arkitekt_next/apps/service/herre_qt.py +57 -0
- arkitekt_next/apps/service/kabinet.py +31 -0
- arkitekt_next/apps/service/mikro_next.py +81 -0
- arkitekt_next/apps/service/rekuest_next.py +53 -0
- arkitekt_next/apps/service/unlok_next.py +32 -0
- arkitekt_next/apps/types.py +53 -0
- arkitekt_next/builders.py +264 -0
- arkitekt_next/cli/__init__.py +0 -0
- arkitekt_next/cli/commands/call/__init__.py +0 -0
- arkitekt_next/cli/commands/call/local.py +132 -0
- arkitekt_next/cli/commands/call/main.py +22 -0
- arkitekt_next/cli/commands/call/remote.py +90 -0
- arkitekt_next/cli/commands/gen/__init__.py +0 -0
- arkitekt_next/cli/commands/gen/compile.py +45 -0
- arkitekt_next/cli/commands/gen/init.py +122 -0
- arkitekt_next/cli/commands/gen/main.py +29 -0
- arkitekt_next/cli/commands/gen/watch.py +32 -0
- arkitekt_next/cli/commands/init/__init__.py +0 -0
- arkitekt_next/cli/commands/init/main.py +194 -0
- arkitekt_next/cli/commands/inspect/__init__.py +0 -0
- arkitekt_next/cli/commands/inspect/definitions.py +53 -0
- arkitekt_next/cli/commands/inspect/main.py +22 -0
- arkitekt_next/cli/commands/inspect/variables.py +92 -0
- arkitekt_next/cli/commands/manifest/__init__.py +0 -0
- arkitekt_next/cli/commands/manifest/inspect.py +42 -0
- arkitekt_next/cli/commands/manifest/main.py +25 -0
- arkitekt_next/cli/commands/manifest/scopes.py +155 -0
- arkitekt_next/cli/commands/manifest/version.py +147 -0
- arkitekt_next/cli/commands/manifest/wizard.py +94 -0
- arkitekt_next/cli/commands/port/__init__.py +0 -0
- arkitekt_next/cli/commands/port/build.py +231 -0
- arkitekt_next/cli/commands/port/init.py +82 -0
- arkitekt_next/cli/commands/port/main.py +31 -0
- arkitekt_next/cli/commands/port/publish.py +102 -0
- arkitekt_next/cli/commands/port/stage.py +59 -0
- arkitekt_next/cli/commands/port/utils.py +47 -0
- arkitekt_next/cli/commands/port/validate.py +78 -0
- arkitekt_next/cli/commands/port/wizard.py +329 -0
- arkitekt_next/cli/commands/run/__init__.py +0 -0
- arkitekt_next/cli/commands/run/dev.py +349 -0
- arkitekt_next/cli/commands/run/main.py +22 -0
- arkitekt_next/cli/commands/run/prod.py +57 -0
- arkitekt_next/cli/commands/run/utils.py +10 -0
- arkitekt_next/cli/commands/server/__init__.py +0 -0
- arkitekt_next/cli/commands/server/down.py +56 -0
- arkitekt_next/cli/commands/server/init.py +74 -0
- arkitekt_next/cli/commands/server/inspect.py +59 -0
- arkitekt_next/cli/commands/server/main.py +33 -0
- arkitekt_next/cli/commands/server/open.py +66 -0
- arkitekt_next/cli/commands/server/remove.py +60 -0
- arkitekt_next/cli/commands/server/stop.py +56 -0
- arkitekt_next/cli/commands/server/up.py +70 -0
- arkitekt_next/cli/commands/server/utils.py +33 -0
- arkitekt_next/cli/configs/base.yaml +867 -0
- arkitekt_next/cli/constants.py +63 -0
- arkitekt_next/cli/dockerfiles/vanilla.dockerfile +8 -0
- arkitekt_next/cli/errors.py +4 -0
- arkitekt_next/cli/inspect.py +1 -0
- arkitekt_next/cli/io.py +255 -0
- arkitekt_next/cli/main.py +83 -0
- arkitekt_next/cli/options.py +166 -0
- arkitekt_next/cli/schemas/fluss.schema.graphql +2446 -0
- arkitekt_next/cli/schemas/gucker.schema.graphql +8908 -0
- arkitekt_next/cli/schemas/kabinet.schema.graphql +515 -0
- arkitekt_next/cli/schemas/kluster.schema.graphql +109 -0
- arkitekt_next/cli/schemas/konviktion.schema.graphql +70 -0
- arkitekt_next/cli/schemas/kuay.schema.graphql +356 -0
- arkitekt_next/cli/schemas/mikro.schema.graphql +8908 -0
- arkitekt_next/cli/schemas/mikro_next.schema.graphql +1639 -0
- arkitekt_next/cli/schemas/napari.schema.graphql +8908 -0
- arkitekt_next/cli/schemas/omero_ark.schema.graphql +100 -0
- arkitekt_next/cli/schemas/port.schema.graphql +356 -0
- arkitekt_next/cli/schemas/rekuest.schema.graphql +4630 -0
- arkitekt_next/cli/schemas/rekuest_next.schema.graphql +1159 -0
- arkitekt_next/cli/schemas/unlok.schema.graphql +1013 -0
- arkitekt_next/cli/templates/filter.py +26 -0
- arkitekt_next/cli/templates/simple.py +67 -0
- arkitekt_next/cli/texts.py +20 -0
- arkitekt_next/cli/types.py +365 -0
- arkitekt_next/cli/ui.py +111 -0
- arkitekt_next/cli/utils.py +15 -0
- arkitekt_next/cli/validators.py +17 -0
- arkitekt_next/cli/vars.py +39 -0
- arkitekt_next/cli/versions/v1.yaml +1 -0
- arkitekt_next/constants.py +6 -0
- arkitekt_next/model.py +110 -0
- arkitekt_next/qt/__init__.py +9 -0
- arkitekt_next/qt/assets/dark/gear.png +0 -0
- arkitekt_next/qt/assets/dark/green pulse.gif +0 -0
- arkitekt_next/qt/assets/dark/orange pulse.gif +0 -0
- arkitekt_next/qt/assets/dark/pink pulse.gif +0 -0
- arkitekt_next/qt/assets/dark/red pulse.gif +0 -0
- arkitekt_next/qt/assets/light/gear.png +0 -0
- arkitekt_next/qt/assets/light/green pulse.gif +0 -0
- arkitekt_next/qt/assets/light/orange pulse.gif +0 -0
- arkitekt_next/qt/assets/light/pink pulse.gif +0 -0
- arkitekt_next/qt/assets/light/red pulse.gif +0 -0
- arkitekt_next/qt/magic_bar.py +545 -0
- arkitekt_next/qt/utils.py +30 -0
- arkitekt_next/service_registry.py +51 -0
- arkitekt_next/tqdm.py +43 -0
- arkitekt_next/utils.py +38 -0
- arkitekt_next-0.7.8.dist-info/LICENSE +21 -0
- arkitekt_next-0.7.8.dist-info/METADATA +155 -0
- arkitekt_next-0.7.8.dist-info/RECORD +119 -0
- arkitekt_next-0.7.8.dist-info/WHEEL +4 -0
- arkitekt_next-0.7.8.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from rich.panel import Panel
|
|
4
|
+
from rich.console import Group
|
|
5
|
+
from arkitekt_next.cli.vars import get_manifest, get_console
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.command()
|
|
9
|
+
@click.pass_context
|
|
10
|
+
def inspect(ctx) -> None:
|
|
11
|
+
"""Inspect the [i]current[/i] manifest of this app
|
|
12
|
+
|
|
13
|
+
The manifest is used to describe the app and its rights (scopes) and requirements, to be run on the platform.
|
|
14
|
+
This manifest is used to authenticate the app with the platform establishing its scopes and requirements.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
manifest = get_manifest(ctx)
|
|
19
|
+
|
|
20
|
+
table = Table.grid()
|
|
21
|
+
table.add_column()
|
|
22
|
+
table.add_column()
|
|
23
|
+
table.add_row("Identifier", manifest.identifier)
|
|
24
|
+
table.add_row("Version", manifest.version)
|
|
25
|
+
table.add_row("Author", manifest.author)
|
|
26
|
+
table.add_row("Logo", manifest.logo or "-")
|
|
27
|
+
table.add_row("Entrypoint", manifest.entrypoint)
|
|
28
|
+
table.add_row("Scopes", ", ".join(manifest.scopes) if manifest.scopes else "-")
|
|
29
|
+
table.add_row(
|
|
30
|
+
"Requirements",
|
|
31
|
+
", ".join(manifest.requirements) if manifest.requirements else "-",
|
|
32
|
+
)
|
|
33
|
+
table.add_row("Created at", str(manifest.created_at.strftime("%Y/%m/%d %H:%M")))
|
|
34
|
+
|
|
35
|
+
panel = Panel(
|
|
36
|
+
Group("[bold green]Manifest[/]", table),
|
|
37
|
+
title_align="center",
|
|
38
|
+
border_style="green",
|
|
39
|
+
style="white",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
get_console(ctx).print(panel)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
from .inspect import inspect
|
|
3
|
+
from .scopes import scopes_group
|
|
4
|
+
from .version import version
|
|
5
|
+
from .wizard import wizard
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group()
|
|
9
|
+
@click.pass_context
|
|
10
|
+
def manifest(ctx) -> None:
|
|
11
|
+
"""Updates the manifest of this app
|
|
12
|
+
|
|
13
|
+
The manifest is used to describe the app and its rights (scopes) and requirements, to be run on the platform.
|
|
14
|
+
This manifest is used to authenticate the app with the platform establishing its scopes and requirements.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
manifest.add_command(inspect, "inspect")
|
|
23
|
+
manifest.add_command(scopes_group, "scopes")
|
|
24
|
+
manifest.add_command(version, "version")
|
|
25
|
+
manifest.add_command(wizard, "wizard")
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from rich.panel import Panel
|
|
4
|
+
from rich.console import Group
|
|
5
|
+
from arkitekt_next.cli.vars import *
|
|
6
|
+
from arkitekt_next.cli.constants import *
|
|
7
|
+
from arkitekt_next.cli.io import write_manifest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group("scopes")
|
|
11
|
+
@click.pass_context
|
|
12
|
+
def scopes_group(ctx):
|
|
13
|
+
"""Inspect, add and remove scopes to this arkitekt_next app
|
|
14
|
+
|
|
15
|
+
Scopes are rights that are granted to any arkitekt_next application, and correspond
|
|
16
|
+
to rights that enable feature when interacting with the platform. These scopes
|
|
17
|
+
provide another element of access control to the arkitekt_next platform, and describe
|
|
18
|
+
on top of the users rights, what the application is allowed to do.
|
|
19
|
+
|
|
20
|
+
For more information, please visit the [link=https://jhnnsrs.github.io/doks]https://jhnnsrs.github.io/doks[/link]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@scopes_group.command("add")
|
|
28
|
+
@click.argument(
|
|
29
|
+
"SCOPE",
|
|
30
|
+
nargs=-1,
|
|
31
|
+
type=click.Choice(compile_scopes()),
|
|
32
|
+
)
|
|
33
|
+
@click.pass_context
|
|
34
|
+
def add_scopes(ctx, scope):
|
|
35
|
+
""" "Acd scopes
|
|
36
|
+
|
|
37
|
+
Scopes are rights that are granted to any arkitekt_next application, and correspond
|
|
38
|
+
to rights that enable feature when interacting with the platform. These scopes
|
|
39
|
+
provide another element of access control to the arkitekt_next platform, and describe
|
|
40
|
+
on top of the users rights, what the application is allowed to do.
|
|
41
|
+
|
|
42
|
+
For more information, please visit the [link=https://jhnnsrs.github.io/doks]https://jhnnsrs.github.io/doks[/link]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
if not scope:
|
|
47
|
+
raise click.ClickException("Please provide at least one scope")
|
|
48
|
+
|
|
49
|
+
manifest = get_manifest(ctx)
|
|
50
|
+
console = get_console(ctx)
|
|
51
|
+
|
|
52
|
+
if scope:
|
|
53
|
+
manifest.scopes = set(list(scope) + manifest.scopes)
|
|
54
|
+
write_manifest(manifest)
|
|
55
|
+
console.print(f"Scopes Updated to {manifest.scopes}")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@scopes_group.command("remove")
|
|
59
|
+
@click.argument(
|
|
60
|
+
"SCOPE",
|
|
61
|
+
nargs=-1,
|
|
62
|
+
type=click.Choice(compile_scopes()),
|
|
63
|
+
)
|
|
64
|
+
@click.pass_context
|
|
65
|
+
def remove_scopes(ctx, scope):
|
|
66
|
+
"""Remove scopes
|
|
67
|
+
|
|
68
|
+
Scopes are rights that are granted to any arkitekt_next application, and correspond
|
|
69
|
+
to rights that enable feature when interacting with the platform. These scopes
|
|
70
|
+
provide another element of access control to the arkitekt_next platform, and describe
|
|
71
|
+
on top of the users rights, what the application is allowed to do.
|
|
72
|
+
|
|
73
|
+
For more information, please visit the [link=https://jhnnsrs.github.io/doks]https://jhnnsrs.github.io/doks[/link]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
if not scope:
|
|
78
|
+
raise click.ClickException("Please provide at least one scope to remove")
|
|
79
|
+
|
|
80
|
+
manifest = get_manifest(ctx)
|
|
81
|
+
console = get_console(ctx)
|
|
82
|
+
|
|
83
|
+
if scope:
|
|
84
|
+
manifest.scopes = set(manifest.scopes) - set(scope)
|
|
85
|
+
write_manifest(manifest)
|
|
86
|
+
console.print(f"Scopes Updated to {manifest.scopes}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@scopes_group.command("list")
|
|
90
|
+
@click.pass_context
|
|
91
|
+
def list_scopes(ctx):
|
|
92
|
+
"""List all the [i] currently [/] active scopes
|
|
93
|
+
|
|
94
|
+
Scopes are rights that are granted to any arkitekt_next application, and correspond
|
|
95
|
+
to rights that enable feature when interacting with the platform. These scopes
|
|
96
|
+
provide another element of access control to the arkitekt_next platform, and describe
|
|
97
|
+
on top of the users rights, what the application is allowed to do.
|
|
98
|
+
|
|
99
|
+
For more information, please visit the [link=https://jhnnsrs.github.io/doks]https://jhnnsrs.github.io/doks[/link]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
manifest = get_manifest(ctx)
|
|
105
|
+
console = get_console(ctx)
|
|
106
|
+
|
|
107
|
+
table = Table.grid()
|
|
108
|
+
table.padding = (0, 1)
|
|
109
|
+
table.add_column("Scope")
|
|
110
|
+
table.add_column("Description")
|
|
111
|
+
for scope in manifest.scopes:
|
|
112
|
+
table.add_row(scope, "TODO: This should be a description")
|
|
113
|
+
|
|
114
|
+
panel = Panel(
|
|
115
|
+
Group("[bold green]Demanded Scopes[/]", table),
|
|
116
|
+
title_align="center",
|
|
117
|
+
border_style="green",
|
|
118
|
+
style="white",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
console.print(panel)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@scopes_group.command("available")
|
|
125
|
+
@click.pass_context
|
|
126
|
+
def list_available(ctx):
|
|
127
|
+
"""List all the [i] available [/] scopes
|
|
128
|
+
|
|
129
|
+
Scopes are rights that are granted to any arkitekt_next application, and correspond
|
|
130
|
+
to rights that enable feature when interacting with the platform. These scopes
|
|
131
|
+
provide another element of access control to the arkitekt_next platform, and describe
|
|
132
|
+
on top of the users rights, what the application is allowed to do.
|
|
133
|
+
|
|
134
|
+
For more information, please visit the [link=https://jhnnsrs.github.io/doks]https://jhnnsrs.github.io/doks[/link]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
console = get_console(ctx)
|
|
140
|
+
|
|
141
|
+
table = Table.grid()
|
|
142
|
+
table.padding = (0, 1)
|
|
143
|
+
table.add_column("Scope")
|
|
144
|
+
table.add_column("Description")
|
|
145
|
+
for scope in compile_scopes():
|
|
146
|
+
table.add_row(scope, "TODO")
|
|
147
|
+
|
|
148
|
+
panel = Panel(
|
|
149
|
+
Group("[bold green]Available Scopes[/]", table),
|
|
150
|
+
title_align="center",
|
|
151
|
+
border_style="green",
|
|
152
|
+
style="white",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
console.print(panel)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
from semver import (
|
|
3
|
+
parse as parse_semver,
|
|
4
|
+
bump_build,
|
|
5
|
+
bump_major,
|
|
6
|
+
bump_minor,
|
|
7
|
+
bump_patch,
|
|
8
|
+
bump_prerelease,
|
|
9
|
+
)
|
|
10
|
+
from arkitekt_next.cli.vars import get_console, get_manifest
|
|
11
|
+
from arkitekt_next.cli.io import write_manifest
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group()
|
|
15
|
+
@click.pass_context
|
|
16
|
+
def version(ctx):
|
|
17
|
+
"""Updates the version of the arkitekt_next app
|
|
18
|
+
|
|
19
|
+
ArkitektNext manifests versioning follow [link=https://semver.org]semver[/link] and are used to version the app.
|
|
20
|
+
This provides an orthogonal way to version the app, beyond node versioning. The version is used to
|
|
21
|
+
track changes and to provide a way to update the app in the platform. For more information, please visit
|
|
22
|
+
[link=https://arkitekt_next.live]https://arkitekt_next.live[/link]
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@version.command("set")
|
|
28
|
+
@click.argument("VERSION", type=str, required=False)
|
|
29
|
+
@click.pass_context
|
|
30
|
+
def set_version(ctx, version):
|
|
31
|
+
"""Sets the version of the arkitekt_next app
|
|
32
|
+
|
|
33
|
+
When setting the version, you can either provide a version, or you can let the cli
|
|
34
|
+
prompt you for a version. If you provide a version, it will be parsed and validated
|
|
35
|
+
against semver. If you let the cli prompt you, it will try to parse the current version
|
|
36
|
+
and suggest a new version based on that. If the current version is not a valid semver
|
|
37
|
+
version, it will prompt you for a new version without a suggestion.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
manifest = get_manifest(ctx)
|
|
41
|
+
get_console(ctx)
|
|
42
|
+
old_version = manifest.version
|
|
43
|
+
|
|
44
|
+
if not version:
|
|
45
|
+
try:
|
|
46
|
+
potential_new_version = bump_patch(old_version)
|
|
47
|
+
except Exception:
|
|
48
|
+
potential_new_version = None
|
|
49
|
+
|
|
50
|
+
new_version = click.prompt(
|
|
51
|
+
"Please provide a new version", default=potential_new_version, type=str
|
|
52
|
+
)
|
|
53
|
+
version = parse_semver(new_version)
|
|
54
|
+
version = new_version
|
|
55
|
+
|
|
56
|
+
manifest.version = version
|
|
57
|
+
write_manifest(manifest)
|
|
58
|
+
get_console().print(f"Version Updated from {old_version} to {version}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@version.command()
|
|
62
|
+
@click.pass_context
|
|
63
|
+
def patch(ctx):
|
|
64
|
+
""" "Patches the version of the arkitekt_next app
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Patches the version of the arkitekt_next app, by bumping the patch number.
|
|
68
|
+
E.g. from 1.0.1 to 1.0.2. This should be used for bugfixes and small changes.
|
|
69
|
+
"""
|
|
70
|
+
manifest = get_manifest(ctx)
|
|
71
|
+
console = get_console(ctx)
|
|
72
|
+
old_version = manifest.version
|
|
73
|
+
manifest.version = bump_patch(old_version)
|
|
74
|
+
write_manifest(manifest)
|
|
75
|
+
console.print(f"Version Updated from {old_version} to {manifest.version}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@version.command()
|
|
79
|
+
@click.pass_context
|
|
80
|
+
def minor(ctx):
|
|
81
|
+
"""Bumps the minor version number of the arkitekt_next app
|
|
82
|
+
|
|
83
|
+
Patches the version of the arkitekt_next app, by bumping the minor number.
|
|
84
|
+
E.g. from 1.0.1 to 1.1.1. This should be used for new features, that
|
|
85
|
+
are backwards compatible.
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
manifest = get_manifest(ctx)
|
|
89
|
+
console = get_console(ctx)
|
|
90
|
+
old_version = manifest.version
|
|
91
|
+
manifest.version = bump_minor(old_version)
|
|
92
|
+
write_manifest(manifest)
|
|
93
|
+
console.print(f"Version Updated from {old_version} to {manifest.version}")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@version.command()
|
|
97
|
+
@click.pass_context
|
|
98
|
+
def major(ctx):
|
|
99
|
+
"""Increase the major version of the arkitekt_next app"
|
|
100
|
+
|
|
101
|
+
Patches the version of the arkitekt_next app, by bumping the major number.
|
|
102
|
+
E.g. from 1.0.1 to 2.0.1, This should be used for breaking changes,
|
|
103
|
+
that are not backwards compatible (e.g. deleting a node).
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
manifest = get_manifest(ctx)
|
|
107
|
+
console = get_console(ctx)
|
|
108
|
+
old_version = manifest.version
|
|
109
|
+
manifest.version = bump_major(old_version)
|
|
110
|
+
write_manifest(manifest)
|
|
111
|
+
console.print(f"Version Updated from {old_version} to {manifest.version}")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@version.command()
|
|
115
|
+
@click.pass_context
|
|
116
|
+
def prerelease(ctx):
|
|
117
|
+
"""Patches the prerelease of the arkitekt_next app"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
Patches the version of the arkitekt_next app, by bumping the prerelease number.
|
|
121
|
+
E.g. from 1.0.1 to 1.0.1-alpha.1
|
|
122
|
+
"""
|
|
123
|
+
manifest = get_manifest(ctx)
|
|
124
|
+
console = get_console(ctx)
|
|
125
|
+
old_version = manifest.version
|
|
126
|
+
manifest.version = bump_prerelease(old_version)
|
|
127
|
+
write_manifest(manifest)
|
|
128
|
+
console.print(f"Version Updated from {old_version} to {manifest.version}")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@version.command("build")
|
|
132
|
+
@click.pass_context
|
|
133
|
+
def bump_build(ctx):
|
|
134
|
+
"""Patches the build of the arkitekt_next app
|
|
135
|
+
|
|
136
|
+
Patches the version of the arkitekt_next app, by bumping the build number.
|
|
137
|
+
E.g. from 1.0.1 to 1.0.1+1, This should be used for changes that are not
|
|
138
|
+
reflected in the version number, but are still important to track (e.g. a
|
|
139
|
+
hotfix).
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
manifest = get_manifest(ctx)
|
|
143
|
+
console = get_console(ctx)
|
|
144
|
+
old_version = manifest.version
|
|
145
|
+
manifest.version = bump_build(old_version)
|
|
146
|
+
write_manifest(manifest)
|
|
147
|
+
console.print(f"Version Updated from {old_version} to {manifest.version}")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import rich_click as click
|
|
3
|
+
from arkitekt_next.cli.types import Requirement, Framework
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.console import Group
|
|
7
|
+
from arkitekt_next.cli.vars import get_console
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def check_dl_frameworks():
|
|
11
|
+
import site
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
site_packages = site.getsitepackages()
|
|
15
|
+
site_packages.append(sys.prefix)
|
|
16
|
+
|
|
17
|
+
frameworks = {
|
|
18
|
+
"tensorflow": Framework.TENSORFLOW,
|
|
19
|
+
"torch": Framework.PYTORCH,
|
|
20
|
+
"torchvision": Framework.PYTORCH,
|
|
21
|
+
"tensorflow-gpu": Framework.TENSORFLOW,
|
|
22
|
+
"torch-gpu": Framework.PYTORCH,
|
|
23
|
+
"torchvision-gpu": Framework.PYTORCH,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
included_frameworks = set()
|
|
27
|
+
|
|
28
|
+
for key, value in frameworks.items():
|
|
29
|
+
for site_package in site_packages:
|
|
30
|
+
if os.path.exists(os.path.join(site_package, key)):
|
|
31
|
+
included_frameworks.add(value)
|
|
32
|
+
|
|
33
|
+
return included_frameworks
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def inspect_requirements(automatic=False):
|
|
37
|
+
"""Inspect the requirements and
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
return a list of requirements and reasons.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
automatic : bool, optional
|
|
45
|
+
Should we automically add all of the requirements, by default False
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
_type_
|
|
50
|
+
_description_
|
|
51
|
+
"""
|
|
52
|
+
requirements = []
|
|
53
|
+
reasons = []
|
|
54
|
+
frameworks = check_dl_frameworks()
|
|
55
|
+
if frameworks:
|
|
56
|
+
requirements.append(Requirement.GPU)
|
|
57
|
+
reasons.append(
|
|
58
|
+
"Deep learning framework detected ('{}')".format(", ".join(frameworks))
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return requirements, reasons
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@click.command()
|
|
65
|
+
@click.pass_context
|
|
66
|
+
def wizard(ctx) -> None:
|
|
67
|
+
"""Inspect the current project for requirements
|
|
68
|
+
|
|
69
|
+
Inspects the current project and provides a list of [i]suggest[/]ed requirements
|
|
70
|
+
that should be added to the manifest. You should run this command in the same
|
|
71
|
+
virtual environment as you are running your app, as it will detect the installed
|
|
72
|
+
packages and provide a list of requirements that should be added to the manifest.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
console = get_console(ctx)
|
|
77
|
+
requirements, reasons = inspect_requirements()
|
|
78
|
+
|
|
79
|
+
table = Table.grid()
|
|
80
|
+
table.padding = (0, 4, 0, 0)
|
|
81
|
+
table.add_column("Requirement")
|
|
82
|
+
table.add_column("Reason")
|
|
83
|
+
|
|
84
|
+
for item in zip(requirements, reasons):
|
|
85
|
+
table.add_row(str(item[0].value), item[1])
|
|
86
|
+
|
|
87
|
+
panel = Panel(
|
|
88
|
+
Group("[bold green]Manifest[/]", table),
|
|
89
|
+
title_align="center",
|
|
90
|
+
border_style="green",
|
|
91
|
+
style="white",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
console.print(panel)
|
|
File without changes
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
from arkitekt_next.cli.vars import get_console, get_manifest
|
|
3
|
+
import os
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
import subprocess
|
|
6
|
+
import uuid
|
|
7
|
+
from arkitekt_next.cli.io import generate_build
|
|
8
|
+
from click import Context
|
|
9
|
+
from arkitekt_next.cli.types import Flavour, Inspection
|
|
10
|
+
import yaml
|
|
11
|
+
from typing import Dict, Optional
|
|
12
|
+
import json
|
|
13
|
+
from arkitekt_next.utils import create_arkitekt_next_folder
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class InspectionError(Exception):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_flavour(flavour_name: str, flavour: Flavour) -> str:
|
|
21
|
+
"""Builds the flavour to docker
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
flavour : Flavour
|
|
26
|
+
The flavour to build
|
|
27
|
+
manifest : Manifest
|
|
28
|
+
The manifest of the app
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
|
|
33
|
+
tag: str
|
|
34
|
+
The tag of the built docker container
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
build_id = str(uuid.uuid4())
|
|
39
|
+
|
|
40
|
+
relative_dir = ".arkitekt_next/flavours/{}/".format(flavour_name)
|
|
41
|
+
|
|
42
|
+
command = flavour.generate_build_command(build_id, relative_dir)
|
|
43
|
+
|
|
44
|
+
docker_run = subprocess.run(" ".join(command), shell=True)
|
|
45
|
+
|
|
46
|
+
if docker_run.returncode != 0:
|
|
47
|
+
raise click.ClickException("Could not build docker container")
|
|
48
|
+
|
|
49
|
+
return build_id
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def inspect_docker_container(build_id: str) -> Inspection:
|
|
53
|
+
try:
|
|
54
|
+
# Run 'docker inspect' with the container ID or name
|
|
55
|
+
result = subprocess.run(
|
|
56
|
+
["docker", "inspect", build_id],
|
|
57
|
+
stdout=subprocess.PIPE,
|
|
58
|
+
text=True,
|
|
59
|
+
check=True,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Parse the JSON output
|
|
63
|
+
try:
|
|
64
|
+
container_info = json.loads(result.stdout)
|
|
65
|
+
except json.decoder.JSONDecodeError as e:
|
|
66
|
+
combined_error = result.stdout + result.stderr
|
|
67
|
+
raise InspectionError(
|
|
68
|
+
f"Could not decode JSON output of docker inspect. {combined_error}"
|
|
69
|
+
) from e
|
|
70
|
+
|
|
71
|
+
# Extract size information
|
|
72
|
+
try:
|
|
73
|
+
size = container_info[0][
|
|
74
|
+
"Size"
|
|
75
|
+
] # Size of files that have been written to the filesystem
|
|
76
|
+
size_root_fs = container_info[0][
|
|
77
|
+
"Size"
|
|
78
|
+
] # Total size of all the files in the container
|
|
79
|
+
except IndexError as e:
|
|
80
|
+
raise InspectionError("Container not found or invalid JSON output") from e
|
|
81
|
+
except KeyError as e:
|
|
82
|
+
raise InspectionError(
|
|
83
|
+
"Size information not found in the container details"
|
|
84
|
+
) from e
|
|
85
|
+
|
|
86
|
+
return size, size_root_fs
|
|
87
|
+
except subprocess.CalledProcessError as e:
|
|
88
|
+
combined_error = e.stdout + e.stderr
|
|
89
|
+
raise InspectionError(f"An error occurred: {e.stdout + e.stderr}") from e
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def inspect_definitions(build_id: str) -> Inspection:
|
|
93
|
+
try:
|
|
94
|
+
# Run 'docker inspect' with the container ID or name
|
|
95
|
+
result = subprocess.run(
|
|
96
|
+
["docker", "run", build_id, "arkitekt_next", "inspect", "definitions"],
|
|
97
|
+
stdout=subprocess.PIPE,
|
|
98
|
+
stderr=subprocess.PIPE,
|
|
99
|
+
check=True,
|
|
100
|
+
text=True,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Parse the JSON output
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
output = json.loads(result.stdout)
|
|
107
|
+
except json.decoder.JSONDecodeError as e:
|
|
108
|
+
combined_error = result.stdout + result.stderr
|
|
109
|
+
raise InspectionError(
|
|
110
|
+
f"Could not decode JSON output of docker inspect. {combined_error}"
|
|
111
|
+
) from e
|
|
112
|
+
|
|
113
|
+
if "definitions" not in output:
|
|
114
|
+
raise InspectionError(
|
|
115
|
+
"Container not found or invalid JSON output for definitions"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return output["definitions"]
|
|
119
|
+
except subprocess.CalledProcessError as e:
|
|
120
|
+
combined_error = e.stdout + e.stderr
|
|
121
|
+
|
|
122
|
+
if "No such command" in combined_error:
|
|
123
|
+
raise InspectionError(
|
|
124
|
+
"Could not find the command `arkitekt_next inspect definitions` in the container. Maybe"
|
|
125
|
+
+ "you forgot to install arkitekt_next in the container? "
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
raise InspectionError(f"An error occurred: {e.stdout + e.stderr}") from e
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def inspect_build(build_id: str) -> Inspection:
|
|
132
|
+
size, size_root_fs = inspect_docker_container(build_id)
|
|
133
|
+
definitions = inspect_definitions(build_id)
|
|
134
|
+
|
|
135
|
+
return Inspection(size=size, definitions=definitions)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_flavours(ctx: Context, select: Optional[str] = None) -> Dict[str, Flavour]:
|
|
139
|
+
"""Gets the flavours for this app"""
|
|
140
|
+
|
|
141
|
+
arkitekt_next_folder = create_arkitekt_next_folder()
|
|
142
|
+
|
|
143
|
+
flavours_folder = os.path.join(arkitekt_next_folder, "flavours")
|
|
144
|
+
|
|
145
|
+
if not os.path.exists(flavours_folder):
|
|
146
|
+
raise click.ClickException(
|
|
147
|
+
"We could not find the flavours folder. Please run `arkitekt_next port init` first to create a buildable flavour"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
flavours = {}
|
|
151
|
+
|
|
152
|
+
for dir_name in os.listdir(flavours_folder):
|
|
153
|
+
dir = os.path.join(flavours_folder, dir_name)
|
|
154
|
+
if os.path.isdir(dir):
|
|
155
|
+
if select is not None and select != dir_name:
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
if os.path.exists(os.path.join(dir, "config.yaml")):
|
|
159
|
+
with open(os.path.join(dir, "config.yaml")) as f:
|
|
160
|
+
valued = yaml.load(f, Loader=yaml.SafeLoader)
|
|
161
|
+
try:
|
|
162
|
+
flavour = Flavour(**valued)
|
|
163
|
+
flavour.check_relative_paths(dir)
|
|
164
|
+
flavours[dir_name] = flavour
|
|
165
|
+
|
|
166
|
+
except Exception as e:
|
|
167
|
+
get_console(ctx).print_exception()
|
|
168
|
+
raise click.ClickException(
|
|
169
|
+
f"Could not load flavour {dir_name} from {dir} ` config.yaml ` is invalid"
|
|
170
|
+
) from e
|
|
171
|
+
|
|
172
|
+
return flavours
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@click.command()
|
|
176
|
+
@click.option(
|
|
177
|
+
"--flavour",
|
|
178
|
+
"-f",
|
|
179
|
+
help="The flavour to build. By default all flavours are being built",
|
|
180
|
+
default=None,
|
|
181
|
+
required=False,
|
|
182
|
+
)
|
|
183
|
+
@click.option(
|
|
184
|
+
"--no-inspect",
|
|
185
|
+
"-n",
|
|
186
|
+
help="Should we skip the inspection of the app?",
|
|
187
|
+
is_flag=True,
|
|
188
|
+
default=False,
|
|
189
|
+
)
|
|
190
|
+
@click.pass_context
|
|
191
|
+
def build(ctx: Context, flavour: str, no_inspect: bool) -> None:
|
|
192
|
+
"""Builds the arkitekt_next app to docker"""
|
|
193
|
+
|
|
194
|
+
manifest = get_manifest(ctx)
|
|
195
|
+
console = get_console(ctx)
|
|
196
|
+
|
|
197
|
+
flavours = get_flavours(ctx, select=flavour)
|
|
198
|
+
|
|
199
|
+
md = Panel(
|
|
200
|
+
"Starting to Build Containers for App [bold]{}[/bold]".format(
|
|
201
|
+
manifest.identifier
|
|
202
|
+
),
|
|
203
|
+
subtitle="Selected Flavours: {}".format(", ".join(flavours.keys())),
|
|
204
|
+
)
|
|
205
|
+
console.print(md)
|
|
206
|
+
|
|
207
|
+
build_run = str(uuid.uuid4())
|
|
208
|
+
|
|
209
|
+
for key, flavour in flavours.items():
|
|
210
|
+
md = Panel(
|
|
211
|
+
"Building Flavour [bold]{}[/bold]".format(key),
|
|
212
|
+
subtitle="This may take a while...",
|
|
213
|
+
subtitle_align="right",
|
|
214
|
+
)
|
|
215
|
+
console.print(md)
|
|
216
|
+
|
|
217
|
+
build_tag = build_flavour(key, flavour)
|
|
218
|
+
|
|
219
|
+
inspection = None
|
|
220
|
+
if not no_inspect:
|
|
221
|
+
inspection = inspect_build(build_tag)
|
|
222
|
+
|
|
223
|
+
generate_build(build_run, build_tag, key, flavour, manifest, inspection)
|
|
224
|
+
|
|
225
|
+
md = Panel(
|
|
226
|
+
"Built Flavour [bold]{}[/bold]".format(key),
|
|
227
|
+
subtitle="Build ID: {}".format(build_run),
|
|
228
|
+
subtitle_align="right",
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
console.print(md)
|