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.

Files changed (119) hide show
  1. arkitekt_next/__init__.py +43 -0
  2. arkitekt_next/apps/__init__.py +3 -0
  3. arkitekt_next/apps/easy.py +99 -0
  4. arkitekt_next/apps/next.py +40 -0
  5. arkitekt_next/apps/qt.py +97 -0
  6. arkitekt_next/apps/service/__init__.py +3 -0
  7. arkitekt_next/apps/service/fakts.py +88 -0
  8. arkitekt_next/apps/service/fakts_next.py +79 -0
  9. arkitekt_next/apps/service/fakts_qt.py +82 -0
  10. arkitekt_next/apps/service/fluss_next.py +31 -0
  11. arkitekt_next/apps/service/grant_registry.py +27 -0
  12. arkitekt_next/apps/service/herre.py +24 -0
  13. arkitekt_next/apps/service/herre_qt.py +57 -0
  14. arkitekt_next/apps/service/kabinet.py +31 -0
  15. arkitekt_next/apps/service/mikro_next.py +81 -0
  16. arkitekt_next/apps/service/rekuest_next.py +53 -0
  17. arkitekt_next/apps/service/unlok_next.py +32 -0
  18. arkitekt_next/apps/types.py +53 -0
  19. arkitekt_next/builders.py +264 -0
  20. arkitekt_next/cli/__init__.py +0 -0
  21. arkitekt_next/cli/commands/call/__init__.py +0 -0
  22. arkitekt_next/cli/commands/call/local.py +132 -0
  23. arkitekt_next/cli/commands/call/main.py +22 -0
  24. arkitekt_next/cli/commands/call/remote.py +90 -0
  25. arkitekt_next/cli/commands/gen/__init__.py +0 -0
  26. arkitekt_next/cli/commands/gen/compile.py +45 -0
  27. arkitekt_next/cli/commands/gen/init.py +122 -0
  28. arkitekt_next/cli/commands/gen/main.py +29 -0
  29. arkitekt_next/cli/commands/gen/watch.py +32 -0
  30. arkitekt_next/cli/commands/init/__init__.py +0 -0
  31. arkitekt_next/cli/commands/init/main.py +194 -0
  32. arkitekt_next/cli/commands/inspect/__init__.py +0 -0
  33. arkitekt_next/cli/commands/inspect/definitions.py +53 -0
  34. arkitekt_next/cli/commands/inspect/main.py +22 -0
  35. arkitekt_next/cli/commands/inspect/variables.py +92 -0
  36. arkitekt_next/cli/commands/manifest/__init__.py +0 -0
  37. arkitekt_next/cli/commands/manifest/inspect.py +42 -0
  38. arkitekt_next/cli/commands/manifest/main.py +25 -0
  39. arkitekt_next/cli/commands/manifest/scopes.py +155 -0
  40. arkitekt_next/cli/commands/manifest/version.py +147 -0
  41. arkitekt_next/cli/commands/manifest/wizard.py +94 -0
  42. arkitekt_next/cli/commands/port/__init__.py +0 -0
  43. arkitekt_next/cli/commands/port/build.py +231 -0
  44. arkitekt_next/cli/commands/port/init.py +82 -0
  45. arkitekt_next/cli/commands/port/main.py +31 -0
  46. arkitekt_next/cli/commands/port/publish.py +102 -0
  47. arkitekt_next/cli/commands/port/stage.py +59 -0
  48. arkitekt_next/cli/commands/port/utils.py +47 -0
  49. arkitekt_next/cli/commands/port/validate.py +78 -0
  50. arkitekt_next/cli/commands/port/wizard.py +329 -0
  51. arkitekt_next/cli/commands/run/__init__.py +0 -0
  52. arkitekt_next/cli/commands/run/dev.py +349 -0
  53. arkitekt_next/cli/commands/run/main.py +22 -0
  54. arkitekt_next/cli/commands/run/prod.py +57 -0
  55. arkitekt_next/cli/commands/run/utils.py +10 -0
  56. arkitekt_next/cli/commands/server/__init__.py +0 -0
  57. arkitekt_next/cli/commands/server/down.py +56 -0
  58. arkitekt_next/cli/commands/server/init.py +74 -0
  59. arkitekt_next/cli/commands/server/inspect.py +59 -0
  60. arkitekt_next/cli/commands/server/main.py +33 -0
  61. arkitekt_next/cli/commands/server/open.py +66 -0
  62. arkitekt_next/cli/commands/server/remove.py +60 -0
  63. arkitekt_next/cli/commands/server/stop.py +56 -0
  64. arkitekt_next/cli/commands/server/up.py +70 -0
  65. arkitekt_next/cli/commands/server/utils.py +33 -0
  66. arkitekt_next/cli/configs/base.yaml +867 -0
  67. arkitekt_next/cli/constants.py +63 -0
  68. arkitekt_next/cli/dockerfiles/vanilla.dockerfile +8 -0
  69. arkitekt_next/cli/errors.py +4 -0
  70. arkitekt_next/cli/inspect.py +1 -0
  71. arkitekt_next/cli/io.py +255 -0
  72. arkitekt_next/cli/main.py +83 -0
  73. arkitekt_next/cli/options.py +166 -0
  74. arkitekt_next/cli/schemas/fluss.schema.graphql +2446 -0
  75. arkitekt_next/cli/schemas/gucker.schema.graphql +8908 -0
  76. arkitekt_next/cli/schemas/kabinet.schema.graphql +515 -0
  77. arkitekt_next/cli/schemas/kluster.schema.graphql +109 -0
  78. arkitekt_next/cli/schemas/konviktion.schema.graphql +70 -0
  79. arkitekt_next/cli/schemas/kuay.schema.graphql +356 -0
  80. arkitekt_next/cli/schemas/mikro.schema.graphql +8908 -0
  81. arkitekt_next/cli/schemas/mikro_next.schema.graphql +1639 -0
  82. arkitekt_next/cli/schemas/napari.schema.graphql +8908 -0
  83. arkitekt_next/cli/schemas/omero_ark.schema.graphql +100 -0
  84. arkitekt_next/cli/schemas/port.schema.graphql +356 -0
  85. arkitekt_next/cli/schemas/rekuest.schema.graphql +4630 -0
  86. arkitekt_next/cli/schemas/rekuest_next.schema.graphql +1159 -0
  87. arkitekt_next/cli/schemas/unlok.schema.graphql +1013 -0
  88. arkitekt_next/cli/templates/filter.py +26 -0
  89. arkitekt_next/cli/templates/simple.py +67 -0
  90. arkitekt_next/cli/texts.py +20 -0
  91. arkitekt_next/cli/types.py +365 -0
  92. arkitekt_next/cli/ui.py +111 -0
  93. arkitekt_next/cli/utils.py +15 -0
  94. arkitekt_next/cli/validators.py +17 -0
  95. arkitekt_next/cli/vars.py +39 -0
  96. arkitekt_next/cli/versions/v1.yaml +1 -0
  97. arkitekt_next/constants.py +6 -0
  98. arkitekt_next/model.py +110 -0
  99. arkitekt_next/qt/__init__.py +9 -0
  100. arkitekt_next/qt/assets/dark/gear.png +0 -0
  101. arkitekt_next/qt/assets/dark/green pulse.gif +0 -0
  102. arkitekt_next/qt/assets/dark/orange pulse.gif +0 -0
  103. arkitekt_next/qt/assets/dark/pink pulse.gif +0 -0
  104. arkitekt_next/qt/assets/dark/red pulse.gif +0 -0
  105. arkitekt_next/qt/assets/light/gear.png +0 -0
  106. arkitekt_next/qt/assets/light/green pulse.gif +0 -0
  107. arkitekt_next/qt/assets/light/orange pulse.gif +0 -0
  108. arkitekt_next/qt/assets/light/pink pulse.gif +0 -0
  109. arkitekt_next/qt/assets/light/red pulse.gif +0 -0
  110. arkitekt_next/qt/magic_bar.py +545 -0
  111. arkitekt_next/qt/utils.py +30 -0
  112. arkitekt_next/service_registry.py +51 -0
  113. arkitekt_next/tqdm.py +43 -0
  114. arkitekt_next/utils.py +38 -0
  115. arkitekt_next-0.7.8.dist-info/LICENSE +21 -0
  116. arkitekt_next-0.7.8.dist-info/METADATA +155 -0
  117. arkitekt_next-0.7.8.dist-info/RECORD +119 -0
  118. arkitekt_next-0.7.8.dist-info/WHEEL +4 -0
  119. 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)