zrb 1.15.3__py3-none-any.whl → 2.0.0a4__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 zrb might be problematic. Click here for more details.
- zrb/__init__.py +118 -133
- zrb/attr/type.py +10 -7
- zrb/builtin/__init__.py +55 -1
- zrb/builtin/git.py +12 -1
- zrb/builtin/group.py +31 -15
- zrb/builtin/llm/chat.py +147 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
- zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
- zrb/builtin/searxng/config/settings.yml +5671 -0
- zrb/builtin/searxng/start.py +21 -0
- zrb/builtin/shell/autocomplete/bash.py +4 -3
- zrb/builtin/shell/autocomplete/zsh.py +4 -3
- zrb/callback/callback.py +8 -1
- zrb/cmd/cmd_result.py +2 -1
- zrb/config/config.py +555 -169
- zrb/config/helper.py +84 -0
- zrb/config/web_auth_config.py +50 -35
- zrb/context/any_shared_context.py +20 -3
- zrb/context/context.py +39 -5
- zrb/context/print_fn.py +13 -0
- zrb/context/shared_context.py +17 -8
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +3 -3
- zrb/input/any_input.py +5 -1
- zrb/input/base_input.py +18 -6
- zrb/input/option_input.py +41 -1
- zrb/input/text_input.py +7 -24
- zrb/llm/agent/__init__.py +9 -0
- zrb/llm/agent/agent.py +215 -0
- zrb/llm/agent/summarizer.py +20 -0
- zrb/llm/app/__init__.py +10 -0
- zrb/llm/app/completion.py +281 -0
- zrb/llm/app/confirmation/allow_tool.py +66 -0
- zrb/llm/app/confirmation/handler.py +178 -0
- zrb/llm/app/confirmation/replace_confirmation.py +77 -0
- zrb/llm/app/keybinding.py +34 -0
- zrb/llm/app/layout.py +117 -0
- zrb/llm/app/lexer.py +155 -0
- zrb/llm/app/redirection.py +28 -0
- zrb/llm/app/style.py +16 -0
- zrb/llm/app/ui.py +733 -0
- zrb/llm/config/__init__.py +4 -0
- zrb/llm/config/config.py +122 -0
- zrb/llm/config/limiter.py +247 -0
- zrb/llm/history_manager/__init__.py +4 -0
- zrb/llm/history_manager/any_history_manager.py +23 -0
- zrb/llm/history_manager/file_history_manager.py +91 -0
- zrb/llm/history_processor/summarizer.py +108 -0
- zrb/llm/note/__init__.py +3 -0
- zrb/llm/note/manager.py +122 -0
- zrb/llm/prompt/__init__.py +29 -0
- zrb/llm/prompt/claude_compatibility.py +92 -0
- zrb/llm/prompt/compose.py +55 -0
- zrb/llm/prompt/default.py +51 -0
- zrb/llm/prompt/markdown/file_extractor.md +112 -0
- zrb/llm/prompt/markdown/mandate.md +23 -0
- zrb/llm/prompt/markdown/persona.md +3 -0
- zrb/llm/prompt/markdown/repo_extractor.md +112 -0
- zrb/llm/prompt/markdown/repo_summarizer.md +29 -0
- zrb/llm/prompt/markdown/summarizer.md +21 -0
- zrb/llm/prompt/note.py +41 -0
- zrb/llm/prompt/system_context.py +46 -0
- zrb/llm/prompt/zrb.py +41 -0
- zrb/llm/skill/__init__.py +3 -0
- zrb/llm/skill/manager.py +86 -0
- zrb/llm/task/__init__.py +4 -0
- zrb/llm/task/llm_chat_task.py +316 -0
- zrb/llm/task/llm_task.py +245 -0
- zrb/llm/tool/__init__.py +39 -0
- zrb/llm/tool/bash.py +75 -0
- zrb/llm/tool/code.py +266 -0
- zrb/llm/tool/file.py +419 -0
- zrb/llm/tool/note.py +70 -0
- zrb/{builtin/llm → llm}/tool/rag.py +33 -37
- zrb/llm/tool/search/brave.py +53 -0
- zrb/llm/tool/search/searxng.py +47 -0
- zrb/llm/tool/search/serpapi.py +47 -0
- zrb/llm/tool/skill.py +19 -0
- zrb/llm/tool/sub_agent.py +70 -0
- zrb/llm/tool/web.py +97 -0
- zrb/llm/tool/zrb_task.py +66 -0
- zrb/llm/util/attachment.py +101 -0
- zrb/llm/util/prompt.py +104 -0
- zrb/llm/util/stream_response.py +178 -0
- zrb/runner/cli.py +21 -20
- zrb/runner/common_util.py +24 -19
- zrb/runner/web_route/task_input_api_route.py +5 -5
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -9
- zrb/session/session.py +38 -17
- zrb/task/any_task.py +24 -3
- zrb/task/base/context.py +42 -22
- zrb/task/base/execution.py +67 -55
- zrb/task/base/lifecycle.py +14 -7
- zrb/task/base/monitoring.py +12 -7
- zrb/task/base_task.py +113 -50
- zrb/task/base_trigger.py +16 -6
- zrb/task/cmd_task.py +6 -0
- zrb/task/http_check.py +11 -5
- zrb/task/make_task.py +5 -3
- zrb/task/rsync_task.py +30 -10
- zrb/task/scaffolder.py +7 -4
- zrb/task/scheduler.py +7 -4
- zrb/task/tcp_check.py +6 -4
- zrb/util/ascii_art/art/bee.txt +17 -0
- zrb/util/ascii_art/art/cat.txt +9 -0
- zrb/util/ascii_art/art/ghost.txt +16 -0
- zrb/util/ascii_art/art/panda.txt +17 -0
- zrb/util/ascii_art/art/rose.txt +14 -0
- zrb/util/ascii_art/art/unicorn.txt +15 -0
- zrb/util/ascii_art/banner.py +92 -0
- zrb/util/attr.py +54 -39
- zrb/util/cli/markdown.py +32 -0
- zrb/util/cli/text.py +30 -0
- zrb/util/cmd/command.py +33 -10
- zrb/util/file.py +61 -33
- zrb/util/git.py +2 -2
- zrb/util/{llm/prompt.py → markdown.py} +2 -3
- zrb/util/match.py +78 -0
- zrb/util/run.py +3 -3
- zrb/util/string/conversion.py +1 -1
- zrb/util/truncate.py +23 -0
- zrb/util/yaml.py +204 -0
- zrb/xcom/xcom.py +10 -0
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/METADATA +41 -27
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/RECORD +129 -131
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +1 -1
- zrb/attr/__init__.py +0 -0
- zrb/builtin/llm/chat_session.py +0 -311
- zrb/builtin/llm/history.py +0 -71
- zrb/builtin/llm/input.py +0 -27
- zrb/builtin/llm/llm_ask.py +0 -187
- zrb/builtin/llm/previous-session.js +0 -21
- zrb/builtin/llm/tool/__init__.py +0 -0
- zrb/builtin/llm/tool/api.py +0 -71
- zrb/builtin/llm/tool/cli.py +0 -38
- zrb/builtin/llm/tool/code.py +0 -254
- zrb/builtin/llm/tool/file.py +0 -626
- zrb/builtin/llm/tool/sub_agent.py +0 -137
- zrb/builtin/llm/tool/web.py +0 -195
- zrb/builtin/project/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
- zrb/builtin/project/create/__init__.py +0 -0
- zrb/builtin/shell/__init__.py +0 -0
- zrb/builtin/shell/autocomplete/__init__.py +0 -0
- zrb/callback/__init__.py +0 -0
- zrb/cmd/__init__.py +0 -0
- zrb/config/default_prompt/file_extractor_system_prompt.md +0 -12
- zrb/config/default_prompt/interactive_system_prompt.md +0 -35
- zrb/config/default_prompt/persona.md +0 -1
- zrb/config/default_prompt/repo_extractor_system_prompt.md +0 -112
- zrb/config/default_prompt/repo_summarizer_system_prompt.md +0 -10
- zrb/config/default_prompt/summarization_prompt.md +0 -16
- zrb/config/default_prompt/system_prompt.md +0 -32
- zrb/config/llm_config.py +0 -243
- zrb/config/llm_context/config.py +0 -129
- zrb/config/llm_context/config_parser.py +0 -46
- zrb/config/llm_rate_limitter.py +0 -137
- zrb/content_transformer/__init__.py +0 -0
- zrb/context/__init__.py +0 -0
- zrb/dot_dict/__init__.py +0 -0
- zrb/env/__init__.py +0 -0
- zrb/group/__init__.py +0 -0
- zrb/input/__init__.py +0 -0
- zrb/runner/__init__.py +0 -0
- zrb/runner/web_route/__init__.py +0 -0
- zrb/runner/web_route/home_page/__init__.py +0 -0
- zrb/session/__init__.py +0 -0
- zrb/session_state_log/__init__.py +0 -0
- zrb/session_state_logger/__init__.py +0 -0
- zrb/task/__init__.py +0 -0
- zrb/task/base/__init__.py +0 -0
- zrb/task/llm/__init__.py +0 -0
- zrb/task/llm/agent.py +0 -243
- zrb/task/llm/config.py +0 -103
- zrb/task/llm/conversation_history.py +0 -128
- zrb/task/llm/conversation_history_model.py +0 -242
- zrb/task/llm/default_workflow/coding.md +0 -24
- zrb/task/llm/default_workflow/copywriting.md +0 -17
- zrb/task/llm/default_workflow/researching.md +0 -18
- zrb/task/llm/error.py +0 -95
- zrb/task/llm/history_summarization.py +0 -216
- zrb/task/llm/print_node.py +0 -101
- zrb/task/llm/prompt.py +0 -325
- zrb/task/llm/tool_wrapper.py +0 -220
- zrb/task/llm/typing.py +0 -3
- zrb/task/llm_task.py +0 -341
- zrb/task_status/__init__.py +0 -0
- zrb/util/__init__.py +0 -0
- zrb/util/cli/__init__.py +0 -0
- zrb/util/cmd/__init__.py +0 -0
- zrb/util/codemod/__init__.py +0 -0
- zrb/util/string/__init__.py +0 -0
- zrb/xcom/__init__.py +0 -0
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/entry_points.txt +0 -0
zrb/task/base_trigger.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import Any
|
|
|
5
5
|
from zrb.attr.type import fstring
|
|
6
6
|
from zrb.callback.any_callback import AnyCallback
|
|
7
7
|
from zrb.context.any_context import AnyContext
|
|
8
|
-
from zrb.context.
|
|
8
|
+
from zrb.context.print_fn import PrintFn
|
|
9
9
|
from zrb.context.shared_context import SharedContext
|
|
10
10
|
from zrb.dot_dict.dot_dict import DotDict
|
|
11
11
|
from zrb.env.any_env import AnyEnv
|
|
@@ -36,7 +36,7 @@ class BaseTrigger(BaseTask):
|
|
|
36
36
|
input: list[AnyInput | None] | AnyInput | None = None,
|
|
37
37
|
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
38
38
|
action: fstring | Callable[[AnyContext], Any] | None = None,
|
|
39
|
-
execute_condition: bool | str | Callable[[
|
|
39
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
40
40
|
queue_name: fstring | None = None,
|
|
41
41
|
callback: list[AnyCallback] | AnyCallback = [],
|
|
42
42
|
retries: int = 2,
|
|
@@ -50,6 +50,7 @@ class BaseTrigger(BaseTask):
|
|
|
50
50
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
51
51
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
52
52
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
53
|
+
print_fn: PrintFn | None = None,
|
|
53
54
|
):
|
|
54
55
|
"""
|
|
55
56
|
Initializes a new instance of the BaseTrigger class.
|
|
@@ -103,6 +104,7 @@ class BaseTrigger(BaseTask):
|
|
|
103
104
|
upstream=upstream,
|
|
104
105
|
fallback=fallback,
|
|
105
106
|
successor=successor,
|
|
107
|
+
print_fn=print_fn,
|
|
106
108
|
)
|
|
107
109
|
self._callbacks = callback
|
|
108
110
|
self._queue_name = queue_name
|
|
@@ -127,7 +129,7 @@ class BaseTrigger(BaseTask):
|
|
|
127
129
|
return self._callbacks
|
|
128
130
|
|
|
129
131
|
async def exec_root_tasks(self, session: AnySession):
|
|
130
|
-
exchange_xcom = self.
|
|
132
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
|
131
133
|
exchange_xcom.add_push_callback(lambda: self._exchange_push_callback(session))
|
|
132
134
|
return await super().exec_root_tasks(session)
|
|
133
135
|
|
|
@@ -136,8 +138,7 @@ class BaseTrigger(BaseTask):
|
|
|
136
138
|
session.defer_coro(coro)
|
|
137
139
|
|
|
138
140
|
async def _fanout_and_trigger_callback(self, session: AnySession):
|
|
139
|
-
|
|
140
|
-
data = exchange_xcom.pop()
|
|
141
|
+
data = self.pop_exchange_xcom(session)
|
|
141
142
|
coros = []
|
|
142
143
|
for callback in self.callbacks:
|
|
143
144
|
xcom_dict = DotDict({self.queue_name: Xcom([data])})
|
|
@@ -145,6 +146,7 @@ class BaseTrigger(BaseTask):
|
|
|
145
146
|
shared_ctx=SharedContext(
|
|
146
147
|
input=dict(session.shared_ctx.input),
|
|
147
148
|
xcom=xcom_dict,
|
|
149
|
+
print_fn=self._print_fn,
|
|
148
150
|
),
|
|
149
151
|
parent=session,
|
|
150
152
|
root_group=session.root_group,
|
|
@@ -156,8 +158,16 @@ class BaseTrigger(BaseTask):
|
|
|
156
158
|
)
|
|
157
159
|
await asyncio.gather(*coros)
|
|
158
160
|
|
|
159
|
-
def
|
|
161
|
+
def _get_exchange_xcom(self, session: AnySession) -> Xcom:
|
|
160
162
|
shared_ctx = session.shared_ctx
|
|
161
163
|
if self.queue_name not in shared_ctx.xcom:
|
|
162
164
|
shared_ctx.xcom[self.queue_name] = Xcom()
|
|
163
165
|
return shared_ctx.xcom[self.queue_name]
|
|
166
|
+
|
|
167
|
+
def push_exchange_xcom(self, session: AnySession, data: Any):
|
|
168
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
|
169
|
+
exchange_xcom.push(data)
|
|
170
|
+
|
|
171
|
+
def pop_exchange_xcom(self, session: AnySession) -> Any:
|
|
172
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
|
173
|
+
return exchange_xcom.pop()
|
zrb/task/cmd_task.py
CHANGED
|
@@ -6,6 +6,7 @@ from zrb.cmd.cmd_result import CmdResult
|
|
|
6
6
|
from zrb.cmd.cmd_val import AnyCmdVal, CmdVal, SingleCmdVal
|
|
7
7
|
from zrb.config.config import CFG
|
|
8
8
|
from zrb.context.any_context import AnyContext
|
|
9
|
+
from zrb.context.print_fn import PrintFn
|
|
9
10
|
from zrb.env.any_env import AnyEnv
|
|
10
11
|
from zrb.input.any_input import AnyInput
|
|
11
12
|
from zrb.task.any_task import AnyTask
|
|
@@ -48,6 +49,7 @@ class CmdTask(BaseTask):
|
|
|
48
49
|
warn_unrecommended_command: bool | None = None,
|
|
49
50
|
max_output_line: int = 1000,
|
|
50
51
|
max_error_line: int = 1000,
|
|
52
|
+
execution_timeout: int = 3600,
|
|
51
53
|
is_interactive: bool = False,
|
|
52
54
|
execute_condition: BoolAttr = True,
|
|
53
55
|
retries: int = 2,
|
|
@@ -61,6 +63,7 @@ class CmdTask(BaseTask):
|
|
|
61
63
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
62
64
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
63
65
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
66
|
+
print_fn: PrintFn | None = None,
|
|
64
67
|
):
|
|
65
68
|
super().__init__(
|
|
66
69
|
name=name,
|
|
@@ -82,6 +85,7 @@ class CmdTask(BaseTask):
|
|
|
82
85
|
upstream=upstream,
|
|
83
86
|
fallback=fallback,
|
|
84
87
|
successor=successor,
|
|
88
|
+
print_fn=print_fn,
|
|
85
89
|
)
|
|
86
90
|
self._shell = shell
|
|
87
91
|
self._render_shell = render_shell
|
|
@@ -103,6 +107,7 @@ class CmdTask(BaseTask):
|
|
|
103
107
|
self._render_cwd = render_cwd
|
|
104
108
|
self._max_output_line = max_output_line
|
|
105
109
|
self._max_error_line = max_error_line
|
|
110
|
+
self._execution_timeout = execution_timeout
|
|
106
111
|
self._should_plain_print = plain_print
|
|
107
112
|
self._should_warn_unrecommended_command = warn_unrecommended_command
|
|
108
113
|
self._is_interactive = is_interactive
|
|
@@ -142,6 +147,7 @@ class CmdTask(BaseTask):
|
|
|
142
147
|
register_pid_method=lambda pid: ctx.xcom.get(xcom_pid_key).push(pid),
|
|
143
148
|
max_output_line=self._max_output_line,
|
|
144
149
|
max_error_line=self._max_error_line,
|
|
150
|
+
timeout=self._execution_timeout,
|
|
145
151
|
is_interactive=self._is_interactive,
|
|
146
152
|
)
|
|
147
153
|
# Check for errors
|
zrb/task/http_check.py
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections.abc import Callable
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
from zrb.attr.type import StrAttr
|
|
5
6
|
from zrb.context.any_context import AnyContext
|
|
6
|
-
from zrb.context.
|
|
7
|
+
from zrb.context.print_fn import PrintFn
|
|
7
8
|
from zrb.env.any_env import AnyEnv
|
|
8
9
|
from zrb.input.any_input import AnyInput
|
|
9
10
|
from zrb.task.any_task import AnyTask
|
|
10
11
|
from zrb.task.base_task import BaseTask
|
|
11
12
|
from zrb.util.attr import get_str_attr
|
|
12
13
|
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from requests import Response
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class HttpCheck(BaseTask):
|
|
15
19
|
def __init__(
|
|
@@ -19,16 +23,17 @@ class HttpCheck(BaseTask):
|
|
|
19
23
|
icon: str | None = None,
|
|
20
24
|
description: str | None = None,
|
|
21
25
|
cli_only: bool = False,
|
|
22
|
-
input: list[AnyInput] | AnyInput | None = None,
|
|
23
|
-
env: list[AnyEnv] | AnyEnv | None = None,
|
|
26
|
+
input: list[AnyInput | None] | AnyInput | None = None,
|
|
27
|
+
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
24
28
|
url: StrAttr = "http://localhost",
|
|
25
29
|
render_url: bool = True,
|
|
26
30
|
http_method: StrAttr = "GET",
|
|
27
31
|
interval: int = 5,
|
|
28
|
-
execute_condition: bool | str | Callable[[
|
|
32
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
29
33
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
30
34
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
31
35
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
36
|
+
print_fn: PrintFn | None = None,
|
|
32
37
|
):
|
|
33
38
|
super().__init__(
|
|
34
39
|
name=name,
|
|
@@ -43,6 +48,7 @@ class HttpCheck(BaseTask):
|
|
|
43
48
|
upstream=upstream,
|
|
44
49
|
fallback=fallback,
|
|
45
50
|
successor=successor,
|
|
51
|
+
print_fn=print_fn,
|
|
46
52
|
)
|
|
47
53
|
self._url = url
|
|
48
54
|
self._render_url = render_url
|
|
@@ -57,7 +63,7 @@ class HttpCheck(BaseTask):
|
|
|
57
63
|
def _get_http_method(self, ctx: AnyContext) -> str:
|
|
58
64
|
return get_str_attr(ctx, self._http_method, "GET", auto_render=True).upper()
|
|
59
65
|
|
|
60
|
-
async def _exec_action(self, ctx: AnyContext) -> bool:
|
|
66
|
+
async def _exec_action(self, ctx: AnyContext) -> "bool | Response":
|
|
61
67
|
import requests
|
|
62
68
|
|
|
63
69
|
url = self._get_url(ctx)
|
zrb/task/make_task.py
CHANGED
|
@@ -2,7 +2,7 @@ from collections.abc import Callable
|
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
4
|
from zrb.context.any_context import AnyContext
|
|
5
|
-
from zrb.context.
|
|
5
|
+
from zrb.context.print_fn import PrintFn
|
|
6
6
|
from zrb.env.any_env import AnyEnv
|
|
7
7
|
from zrb.group.any_group import AnyGroup
|
|
8
8
|
from zrb.input.any_input import AnyInput
|
|
@@ -18,7 +18,7 @@ def make_task(
|
|
|
18
18
|
cli_only: bool = False,
|
|
19
19
|
input: list[AnyInput | None] | AnyInput | None = None,
|
|
20
20
|
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
21
|
-
execute_condition: bool | str | Callable[[
|
|
21
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
22
22
|
retries: int = 2,
|
|
23
23
|
retry_period: float = 0,
|
|
24
24
|
readiness_check: list[AnyTask] | AnyTask | None = None,
|
|
@@ -30,10 +30,11 @@ def make_task(
|
|
|
30
30
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
31
31
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
32
32
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
33
|
+
print_fn: PrintFn | None = None,
|
|
33
34
|
group: AnyGroup | None = None,
|
|
34
35
|
alias: str | None = None,
|
|
35
36
|
) -> Callable[[Callable[[AnyContext], Any]], AnyTask]:
|
|
36
|
-
def _make_task(fn: Callable[[AnyContext], Any]) ->
|
|
37
|
+
def _make_task(fn: Callable[[AnyContext], Any]) -> AnyTask:
|
|
37
38
|
task = BaseTask(
|
|
38
39
|
name=name,
|
|
39
40
|
color=color,
|
|
@@ -55,6 +56,7 @@ def make_task(
|
|
|
55
56
|
upstream=upstream,
|
|
56
57
|
fallback=fallback,
|
|
57
58
|
successor=successor,
|
|
59
|
+
print_fn=print_fn,
|
|
58
60
|
)
|
|
59
61
|
if group is not None:
|
|
60
62
|
return group.add_task(task, alias=alias)
|
zrb/task/rsync_task.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from zrb.attr.type import IntAttr, StrAttr
|
|
1
|
+
from zrb.attr.type import BoolAttr, IntAttr, StrAttr
|
|
4
2
|
from zrb.context.any_context import AnyContext
|
|
3
|
+
from zrb.context.print_fn import PrintFn
|
|
5
4
|
from zrb.env.any_env import AnyEnv
|
|
6
5
|
from zrb.input.any_input import AnyInput
|
|
7
6
|
from zrb.task.any_task import AnyTask
|
|
@@ -17,8 +16,8 @@ class RsyncTask(CmdTask):
|
|
|
17
16
|
icon: str | None = None,
|
|
18
17
|
description: str | None = None,
|
|
19
18
|
cli_only: bool = False,
|
|
20
|
-
input: list[AnyInput] | AnyInput | None = None,
|
|
21
|
-
env: list[AnyEnv] | AnyEnv | None = None,
|
|
19
|
+
input: list[AnyInput | None] | AnyInput | None = None,
|
|
20
|
+
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
22
21
|
shell: StrAttr | None = None,
|
|
23
22
|
auto_render_shell: bool = True,
|
|
24
23
|
remote_host: StrAttr | None = None,
|
|
@@ -39,18 +38,22 @@ class RsyncTask(CmdTask):
|
|
|
39
38
|
render_local_source_path: bool = True,
|
|
40
39
|
local_destination_path: StrAttr | None = None,
|
|
41
40
|
render_local_destination_path: bool = True,
|
|
41
|
+
exclude_from: StrAttr | None = None,
|
|
42
|
+
render_exclude_from: bool = True,
|
|
42
43
|
cwd: str | None = None,
|
|
43
44
|
render_cwd: bool = True,
|
|
44
45
|
plain_print: bool = False,
|
|
45
46
|
max_output_line: int = 1000,
|
|
46
47
|
max_error_line: int = 1000,
|
|
47
|
-
|
|
48
|
+
execution_timeout: int = 3600,
|
|
49
|
+
execute_condition: BoolAttr = True,
|
|
48
50
|
retries: int = 2,
|
|
49
51
|
retry_period: float = 0,
|
|
50
52
|
readiness_check: list[AnyTask] | AnyTask | None = None,
|
|
51
53
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
52
54
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
53
55
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
56
|
+
print_fn: PrintFn | None = None,
|
|
54
57
|
):
|
|
55
58
|
super().__init__(
|
|
56
59
|
name=name,
|
|
@@ -77,6 +80,7 @@ class RsyncTask(CmdTask):
|
|
|
77
80
|
plain_print=plain_print,
|
|
78
81
|
max_output_line=max_output_line,
|
|
79
82
|
max_error_line=max_error_line,
|
|
83
|
+
execution_timeout=execution_timeout,
|
|
80
84
|
execute_condition=execute_condition,
|
|
81
85
|
retries=retries,
|
|
82
86
|
retry_period=retry_period,
|
|
@@ -84,6 +88,7 @@ class RsyncTask(CmdTask):
|
|
|
84
88
|
upstream=upstream,
|
|
85
89
|
fallback=fallback,
|
|
86
90
|
successor=successor,
|
|
91
|
+
print_fn=print_fn,
|
|
87
92
|
)
|
|
88
93
|
self._remote_source_path = remote_source_path
|
|
89
94
|
self._render_remote_source_path = render_remote_source_path
|
|
@@ -93,6 +98,8 @@ class RsyncTask(CmdTask):
|
|
|
93
98
|
self._render_local_source_path = render_local_source_path
|
|
94
99
|
self._local_destination_path = local_destination_path
|
|
95
100
|
self._render_local_destination_path = render_local_destination_path
|
|
101
|
+
self._exclude_from = exclude_from
|
|
102
|
+
self._render_exclude_from = render_exclude_from
|
|
96
103
|
|
|
97
104
|
def _get_source_path(self, ctx: AnyContext) -> str:
|
|
98
105
|
local_source_path = self._get_local_source_path(ctx)
|
|
@@ -144,16 +151,29 @@ class RsyncTask(CmdTask):
|
|
|
144
151
|
auto_render=self._render_local_destination_path,
|
|
145
152
|
)
|
|
146
153
|
|
|
154
|
+
def _get_exclude_from_param(self, ctx: AnyContext) -> str:
|
|
155
|
+
exclude_from = get_str_attr(
|
|
156
|
+
ctx,
|
|
157
|
+
self._exclude_from,
|
|
158
|
+
"",
|
|
159
|
+
auto_render=self._render_exclude_from,
|
|
160
|
+
).strip()
|
|
161
|
+
if exclude_from == "":
|
|
162
|
+
return ""
|
|
163
|
+
return f"--exclude-from='{exclude_from}'"
|
|
164
|
+
|
|
147
165
|
def _get_cmd_script(self, ctx: AnyContext) -> str:
|
|
148
166
|
port = self._get_remote_port(ctx)
|
|
149
167
|
password = self._get_remote_password(ctx)
|
|
150
168
|
key = self._get_remote_ssh_key(ctx)
|
|
151
169
|
src = self._get_source_path(ctx)
|
|
152
170
|
dst = self._get_destination_path(ctx)
|
|
171
|
+
exclude_from = self._get_exclude_from_param(ctx)
|
|
172
|
+
exclude_from_with_space = f"{exclude_from} " if exclude_from != "" else ""
|
|
153
173
|
if key != "" and password != "":
|
|
154
|
-
return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -i {key} -p {port}" {src} {dst}' # noqa
|
|
174
|
+
return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -i {key} -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
|
|
155
175
|
if key != "":
|
|
156
|
-
return f'rsync --mkpath -avz -e "ssh -i {key} -p {port}" {src} {dst}'
|
|
176
|
+
return f'rsync --mkpath -avz -e "ssh -i {key} -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
|
|
157
177
|
if password != "":
|
|
158
|
-
return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -p {port}" {src} {dst}' # noqa
|
|
159
|
-
return f'rsync --mkpath -avz -e "ssh -p {port}" {src} {dst}'
|
|
178
|
+
return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
|
|
179
|
+
return f'rsync --mkpath -avz -e "ssh -p {port}" {exclude_from_with_space}{src} {dst}'
|
zrb/task/scaffolder.py
CHANGED
|
@@ -2,10 +2,11 @@ import os
|
|
|
2
2
|
import shutil
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
|
|
5
|
-
from zrb.attr.type import
|
|
5
|
+
from zrb.attr.type import StrAttr
|
|
6
6
|
from zrb.content_transformer.any_content_transformer import AnyContentTransformer
|
|
7
7
|
from zrb.content_transformer.content_transformer import ContentTransformer
|
|
8
8
|
from zrb.context.any_context import AnyContext
|
|
9
|
+
from zrb.context.print_fn import PrintFn
|
|
9
10
|
from zrb.env.any_env import AnyEnv
|
|
10
11
|
from zrb.input.any_input import AnyInput
|
|
11
12
|
from zrb.task.any_task import AnyTask
|
|
@@ -24,8 +25,8 @@ class Scaffolder(BaseTask):
|
|
|
24
25
|
icon: str | None = None,
|
|
25
26
|
description: str | None = None,
|
|
26
27
|
cli_only: bool = False,
|
|
27
|
-
input: list[AnyInput] | AnyInput | None = None,
|
|
28
|
-
env: list[AnyEnv] | AnyEnv | None = None,
|
|
28
|
+
input: list[AnyInput | None] | AnyInput | None = None,
|
|
29
|
+
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
29
30
|
source_path: StrAttr | None = None,
|
|
30
31
|
render_source_path: bool = True,
|
|
31
32
|
destination_path: StrAttr | None = None,
|
|
@@ -36,7 +37,7 @@ class Scaffolder(BaseTask):
|
|
|
36
37
|
list[AnyContentTransformer] | AnyContentTransformer | TransformConfig
|
|
37
38
|
) = [],
|
|
38
39
|
render_transform_content: bool = True,
|
|
39
|
-
execute_condition:
|
|
40
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
40
41
|
retries: int = 2,
|
|
41
42
|
retry_period: float = 0,
|
|
42
43
|
readiness_check: list[AnyTask] | AnyTask | None = None,
|
|
@@ -48,6 +49,7 @@ class Scaffolder(BaseTask):
|
|
|
48
49
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
49
50
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
50
51
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
52
|
+
print_fn: PrintFn | None = None,
|
|
51
53
|
):
|
|
52
54
|
super().__init__(
|
|
53
55
|
name=name,
|
|
@@ -69,6 +71,7 @@ class Scaffolder(BaseTask):
|
|
|
69
71
|
upstream=upstream,
|
|
70
72
|
fallback=fallback,
|
|
71
73
|
successor=successor,
|
|
74
|
+
print_fn=print_fn,
|
|
72
75
|
)
|
|
73
76
|
self._source_path = source_path
|
|
74
77
|
self._render_source_path = render_source_path
|
zrb/task/scheduler.py
CHANGED
|
@@ -6,6 +6,7 @@ from zrb.attr.type import StrAttr, fstring
|
|
|
6
6
|
from zrb.callback.any_callback import AnyCallback
|
|
7
7
|
from zrb.context.any_context import AnyContext
|
|
8
8
|
from zrb.context.any_shared_context import AnySharedContext
|
|
9
|
+
from zrb.context.print_fn import PrintFn
|
|
9
10
|
from zrb.env.any_env import AnyEnv
|
|
10
11
|
from zrb.input.any_input import AnyInput
|
|
11
12
|
from zrb.task.any_task import AnyTask
|
|
@@ -24,8 +25,8 @@ class Scheduler(BaseTrigger):
|
|
|
24
25
|
cli_only: bool = False,
|
|
25
26
|
input: list[AnyInput | None] | AnyInput | None = None,
|
|
26
27
|
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
27
|
-
schedule: StrAttr = None,
|
|
28
|
-
execute_condition: bool | str | Callable[[
|
|
28
|
+
schedule: StrAttr | None = None,
|
|
29
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
29
30
|
queue_name: fstring | None = None,
|
|
30
31
|
callback: list[AnyCallback] | AnyCallback = [],
|
|
31
32
|
retries: int = 2,
|
|
@@ -39,6 +40,7 @@ class Scheduler(BaseTrigger):
|
|
|
39
40
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
40
41
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
41
42
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
43
|
+
print_fn: PrintFn | None = None,
|
|
42
44
|
):
|
|
43
45
|
super().__init__(
|
|
44
46
|
name=name,
|
|
@@ -62,6 +64,7 @@ class Scheduler(BaseTrigger):
|
|
|
62
64
|
upstream=upstream,
|
|
63
65
|
fallback=fallback,
|
|
64
66
|
successor=successor,
|
|
67
|
+
print_fn=print_fn,
|
|
65
68
|
)
|
|
66
69
|
self._cron_pattern = schedule
|
|
67
70
|
|
|
@@ -76,6 +79,6 @@ class Scheduler(BaseTrigger):
|
|
|
76
79
|
ctx.print(f"Current time: {now}")
|
|
77
80
|
if match_cron(cron_pattern, now):
|
|
78
81
|
ctx.print(f"Matching {now} with pattern: {cron_pattern}")
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
if ctx.session is not None:
|
|
83
|
+
self.push_exchange_xcom(ctx.session, now)
|
|
81
84
|
await asyncio.sleep(60)
|
zrb/task/tcp_check.py
CHANGED
|
@@ -3,7 +3,7 @@ from collections.abc import Callable
|
|
|
3
3
|
|
|
4
4
|
from zrb.attr.type import IntAttr, StrAttr
|
|
5
5
|
from zrb.context.any_context import AnyContext
|
|
6
|
-
from zrb.context.
|
|
6
|
+
from zrb.context.print_fn import PrintFn
|
|
7
7
|
from zrb.env.any_env import AnyEnv
|
|
8
8
|
from zrb.input.any_input import AnyInput
|
|
9
9
|
from zrb.task.any_task import AnyTask
|
|
@@ -19,16 +19,17 @@ class TcpCheck(BaseTask):
|
|
|
19
19
|
icon: str | None = None,
|
|
20
20
|
description: str | None = None,
|
|
21
21
|
cli_only: bool = False,
|
|
22
|
-
input: list[AnyInput] | AnyInput | None = None,
|
|
23
|
-
env: list[AnyEnv] | AnyEnv | None = None,
|
|
22
|
+
input: list[AnyInput | None] | AnyInput | None = None,
|
|
23
|
+
env: list[AnyEnv | None] | AnyEnv | None = None,
|
|
24
24
|
host: StrAttr = "localhost",
|
|
25
25
|
render_host: bool = True,
|
|
26
26
|
port: IntAttr = 80,
|
|
27
27
|
interval: int = 5,
|
|
28
|
-
execute_condition: bool | str | Callable[[
|
|
28
|
+
execute_condition: bool | str | Callable[[AnyContext], bool] = True,
|
|
29
29
|
upstream: list[AnyTask] | AnyTask | None = None,
|
|
30
30
|
fallback: list[AnyTask] | AnyTask | None = None,
|
|
31
31
|
successor: list[AnyTask] | AnyTask | None = None,
|
|
32
|
+
print_fn: PrintFn | None = None,
|
|
32
33
|
):
|
|
33
34
|
super().__init__(
|
|
34
35
|
name=name,
|
|
@@ -43,6 +44,7 @@ class TcpCheck(BaseTask):
|
|
|
43
44
|
upstream=upstream,
|
|
44
45
|
fallback=fallback,
|
|
45
46
|
successor=successor,
|
|
47
|
+
print_fn=print_fn,
|
|
46
48
|
)
|
|
47
49
|
self._host = host
|
|
48
50
|
self._render_host = render_host
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⣉⡙⣿⣿⣿⣿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⣡⣴⣿⣿⠇⣾⣿⣿⣿⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢃⣴⣿⣿⣿⣿⡟⢰⣿⣿⣿⣿⣿⣿⣿⣿
|
|
4
|
+
⣿⣿⠟⢿⣿⣿⣿⣿⣿⡇⣸⣿⣿⣿⣿⡟⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
5
|
+
⣇⣀⡲⣦⢻⣿⣿⣿⣿⡇⣿⣿⣿⣿⡟⣰⣿⡿⠿⠿⢿⣿⣿⣿⣿⣿
|
|
6
|
+
⣿⣿⣧⠙⠸⣿⣿⣿⣿⡇⣿⣿⣿⢏⠼⣋⣥⣶⣿⣿⣦⣤⣉⡛⠻⢿
|
|
7
|
+
⣿⢟⡁⠀⠀⠀⠙⣿⣿⣇⢿⣿⠋⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠈
|
|
8
|
+
⡇⠀⡿⠀⠀⠀⠀⠈⠉⣹⣾⠕⠾⣿⣿⣿⣿⡿⠿⠿⠟⠛⢛⣉⣤⣾
|
|
9
|
+
⣇⠀⠀⢀⠀⠀⠠⢀⣴⣿⠏⠀⢀⣶⡶⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿
|
|
10
|
+
⣿⣶⣤⣤⣤⣦⣶⡿⠟⠁⠀⢠⣾⣿⠃⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
11
|
+
⣿⣿⣿⣿⣿⣿⡄⠀⣀⣠⣴⣿⠟⠁⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
12
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⠛⠛⠋⠁⠀⠀⣠⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
13
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣤⣤⣶⣿⡿⠋⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
14
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⡁⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
15
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
16
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
17
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⡿⢋⠹⣿⣿⣿⣿⣿⠟⢿⣿⣿⣿⣿⣿⣿⠃⠀⢨⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⠟⣠⣿⣧⣈⣉⣉⣉⣁⣶⡌⢻⣿⣿⣿⣿⣿⠘⠀⣿⣿⣿⣿⣿
|
|
4
|
+
⣿⣿⠏⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠛⠛⠛⠛⠛⠀⡀⠻⣿⣿⣿⣿
|
|
5
|
+
⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⣿⣿⣿⣿⣿⣿⣦⠈⢋⣉⠙
|
|
6
|
+
⣿⣿⡎⢿⣿⣶⣶⣿⣿⣿⣿⣤⣼⣿⡟⢠⣿⣿⣿⡿⠿⠟⠛⣀⣡⣤⣴
|
|
7
|
+
⠟⣁⣴⣦⠉⠛⠛⠛⠛⠛⠿⠟⠛⠁⠀⣋⣉⣥⣴⣶⣾⣿⣿⣿⣿⣿⣿
|
|
8
|
+
⣤⣭⣤⣶⣶⣿⣿⣿⠋⣠⡼⢋⣤⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
9
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⢋⣉⣉⣉⣉⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⣾⣿⣿⣿⣿⣿⣷⣦⡈⢻⣿⣿⣿⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⣿⣿⣿⡿⢁⣾⡟⠁⣨⣿⣿⡅⠈⢻⣿⣿⡄⢻⣿⣿⣿⣿⣿⣿
|
|
4
|
+
⣿⠏⣤⣤⣉⠛⠃⢸⣿⣷⣾⡟⠉⠉⢻⣶⣾⣿⣿⡇⢸⣿⣿⣿⣿⣿⣿
|
|
5
|
+
⣿⣧⠄⣹⣿⣿⣷⣬⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⡇⢸⡿⠿⠿⠿⢿⣿
|
|
6
|
+
⣿⠇⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣴⣿⣿⣿⣿⣿⣥⣤⣶⣶⣶⡶⠆⣹
|
|
7
|
+
⡏⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢰⣾⣿
|
|
8
|
+
⣧⠘⢿⡿⠟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⣿⣿
|
|
9
|
+
⣿⣷⣦⣴⠂⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⣿⣿
|
|
10
|
+
⣿⣿⣿⣿⡀⠻⠿⠋⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⢠⣈⠛⣁⣼⣿⣿
|
|
11
|
+
⣿⣿⣿⣿⣿⣿⣾⣿⣆⠘⣿⣿⣿⣿⣿⣿⡟⠙⠛⠃⣼⣿⣿⣿⣿⣿⣿
|
|
12
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡘⢿⣿⣿⣿⣿⡀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
13
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⡙⢿⣿⣿⣧⡈⠻⣿⣿⣿⣿⣿⣿⣿⣿
|
|
14
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣉⡙⠻⠿⣦⠙⢿⣿⣿⣿⣿⣿⣿
|
|
15
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣌⠡⠘⣿⣿⣿⣿⣿⣿
|
|
16
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣠⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠙⠿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⣿⣿⣿⡀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣮⣝⠻⢿⣿⣿⣿⣿⣿
|
|
4
|
+
⣿⣿⣿⣿⣿⡟⣡⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠙⢿
|
|
5
|
+
⣿⠿⣿⣿⡿⢰⣿⡿⠋⠉⠉⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⣸
|
|
6
|
+
⠁⠀⠀⠙⠃⢿⣿⡅⠀⠀⢀⣼⣿⣿⣿⣿⠟⠛⠻⣿⣿⣷⢀⣴⣿
|
|
7
|
+
⡀⠀⠀⠀⠀⠸⣿⣛⣳⣾⣿⢿⡍⢉⣻⡇⠰⠀⠀⣿⣿⣿⢸⣿⣿
|
|
8
|
+
⣷⡀⠀⠀⠀⠀⠈⠻⢿⣿⣿⣷⣶⣬⣽⣿⣦⣤⣤⣟⣿⢇⣾⣿⣿
|
|
9
|
+
⣿⣿⣄⠀⠀⠀⠀⠀⠀⠈⠙⠻⠿⣿⣿⣿⣿⣮⣿⠟⣡⣾⣿⣿⣿
|
|
10
|
+
⣿⣿⣿⡇⢰⣶⣤⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿
|
|
11
|
+
⣿⣿⣿⣇⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⡀⠀⠀⠀⠀⢻⣿⣿⣿⣿
|
|
12
|
+
⣿⣿⣿⡈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⢿⣿⣿⣿
|
|
13
|
+
⣿⣿⣿⡇⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⢸⣿⣿⣿
|
|
14
|
+
⣿⣿⣿⡇⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⢠⣄⣀⣠⣿⣿⣿⣿
|
|
15
|
+
⣿⣿⣿⣿⠀⠀⠀⠀⠉⣉⣛⣛⡛⠉⠁⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿
|
|
16
|
+
⣿⣿⣿⣿⣆⠀⠀⠀⣰⣿⣿⣿⣷⡀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿
|
|
17
|
+
⣿⣿⣿⣿⣿⣷⣶⣶⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⣿⣿⣿⣿⠁⠀⠉⠉⠛⠛⠛⠉⠛⢻⣿⣿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⣿⠟⠋⠁⠀⠀⠀⠈⠙⢧⣤⣤⡀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⢀⣠⡴⠾⠛⠛⠿⣷⣄⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿
|
|
4
|
+
⣿⣿⣿⠋⠀⠀⠀⠀⣠⣶⣿⠁⠀⠀⣀⡀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⣿⣿⣿⣿
|
|
5
|
+
⣿⣿⡏⠀⠀⠀⠀⣰⡿⠛⠙⠿⠛⠉⠛⠟⢿⣷⣄⣸⡇⠐⢦⣤⣤⠔⠛⠻⣿⣿
|
|
6
|
+
⣿⣿⡃⠀⠀⠀⠀⡟⠀⣠⠀⠀⠀⠀⢀⠀⠀⠹⠛⠛⣧⠀⠀⠙⠁⠀⠀⠀⠘⣿
|
|
7
|
+
⣿⣿⣷⡀⠀⠀⢸⠀⢰⣿⡀⠀⠀⠀⢹⣿⠀⢀⡆⠀⠘⣆⣴⣿⠀⠀⠀⠀⠀⠘
|
|
8
|
+
⣿⡟⠀⠙⣄⠀⢸⠀⠀⢻⣷⣄⠀⠤⠞⠋⣠⡾⠁⠀⢠⠟⠉⠻⡇⠀⠀⠀⠀⢰
|
|
9
|
+
⡿⠁⠀⠀⣿⣷⣾⣧⠀⠀⠈⠛⢳⠤⠒⠚⠉⠀⢀⡴⠃⠀⠀⠀⠃⠀⠀⠀⣠⣿
|
|
10
|
+
⡁⠀⠀⠀⣿⠀⠀⠹⣷⠄⢀⣠⣴⣿⣶⣤⣶⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿
|
|
11
|
+
⣷⡄⠀⠀⢻⠀⠀⠀⠘⢧⡀⠈⠉⠛⠛⠋⠉⠀⠀⠀⣀⣠⣴⣂⣀⠠⠊⢹⣿⣿
|
|
12
|
+
⣿⣿⣦⡀⢈⡄⠀⠀⠀⠀⠉⠙⠒⠒⠦⠤⠤⣶⣶⣿⣿⠿⠛⠋⠁⠀⢀⣾⣿⣿
|
|
13
|
+
⣿⣿⣿⣿⣿⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠋⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿
|
|
14
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⡀⠀⠀⢀⣀⣠⣴⣾⣿⣶⣤⣠⣴⣿⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
2
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⠉⢠⡟⠋⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
3
|
+
⣿⣿⣿⣿⣿⣿⠿⠛⠋⠉⠑⠁⠀⠀⠈⠀⣼⣿⣿⣿⣿⠿⠟⢛⣫⣽⣶
|
|
4
|
+
⣿⣿⣿⡿⠋⠁⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⢁⣠⣴⣾⣿⣿⣿⣿
|
|
5
|
+
⣿⣿⣯⡴⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿
|
|
6
|
+
⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠈⠁⢻⣿⣿⣿⣿⣿⣿⣿⣿
|
|
7
|
+
⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣧⡀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿
|
|
8
|
+
⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣷⣶⣦⡀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿
|
|
9
|
+
⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢿⣷⠀⡀⠀⢸⣿⣿⣿⣿⣿⣿⣿
|
|
10
|
+
⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣧⣷⣤⣾⣿⣿⣿⣿⣿⣿⣿
|
|
11
|
+
⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
12
|
+
⣿⣿⣿⣿⣦⣄⡀⠀⠀⠈⢦⡀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
13
|
+
⣿⣿⣿⣿⣿⣿⣿⣧⣤⣀⠀⣿⡀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
14
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
15
|
+
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import random
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def create_banner(art: str | None = None, text: str | None = None) -> str:
|
|
6
|
+
# First get art using _get_art_only
|
|
7
|
+
art_content = _get_art_only(art)
|
|
8
|
+
|
|
9
|
+
# If no text provided, just return the art
|
|
10
|
+
if text is None or text.strip() == "":
|
|
11
|
+
return art_content
|
|
12
|
+
|
|
13
|
+
# Find the longest line in the art, make every line has the same length
|
|
14
|
+
art_lines = art_content.splitlines()
|
|
15
|
+
if not art_lines:
|
|
16
|
+
return text
|
|
17
|
+
|
|
18
|
+
# Find the maximum line length in the art
|
|
19
|
+
max_art_length = max(len(line) for line in art_lines)
|
|
20
|
+
|
|
21
|
+
# Pad all art lines to the same length
|
|
22
|
+
padded_art_lines = [line.ljust(max_art_length) for line in art_lines]
|
|
23
|
+
|
|
24
|
+
# Split text into lines
|
|
25
|
+
text_lines = text.splitlines()
|
|
26
|
+
|
|
27
|
+
# Combine art and text lines
|
|
28
|
+
combined_lines = []
|
|
29
|
+
|
|
30
|
+
# Determine the maximum number of lines we need
|
|
31
|
+
max_lines = max(len(padded_art_lines), len(text_lines))
|
|
32
|
+
|
|
33
|
+
# Calculate vertical offsets for centering
|
|
34
|
+
art_offset = (max_lines - len(padded_art_lines)) // 2
|
|
35
|
+
text_offset = (max_lines - len(text_lines)) // 2
|
|
36
|
+
|
|
37
|
+
for i in range(max_lines):
|
|
38
|
+
# Get art line (or empty string if we've run out of art lines)
|
|
39
|
+
art_index = i - art_offset
|
|
40
|
+
if 0 <= art_index < len(padded_art_lines):
|
|
41
|
+
art_line = padded_art_lines[art_index]
|
|
42
|
+
else:
|
|
43
|
+
art_line = " " * max_art_length
|
|
44
|
+
|
|
45
|
+
# Get text line (or empty string if we've run out of text lines)
|
|
46
|
+
text_index = i - text_offset
|
|
47
|
+
if 0 <= text_index < len(text_lines):
|
|
48
|
+
text_line = text_lines[text_index]
|
|
49
|
+
else:
|
|
50
|
+
text_line = ""
|
|
51
|
+
|
|
52
|
+
# Combine art and text lines
|
|
53
|
+
combined_line = art_line + " " + text_line
|
|
54
|
+
combined_lines.append(combined_line)
|
|
55
|
+
|
|
56
|
+
# Return the combined result
|
|
57
|
+
return "\n".join(combined_lines)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _get_art_only(art: str | None = None) -> str:
|
|
61
|
+
# If name is provided
|
|
62
|
+
if art is not None:
|
|
63
|
+
# 1) name is a file, load the content of the file, return
|
|
64
|
+
expanded_name = os.path.expanduser(art)
|
|
65
|
+
if os.path.isfile(expanded_name):
|
|
66
|
+
with open(expanded_name, "r") as f:
|
|
67
|
+
return f.read()
|
|
68
|
+
|
|
69
|
+
# 2) name is a string, but not a file
|
|
70
|
+
# Check if art/name.txt exists in the script directory
|
|
71
|
+
cwd = os.path.dirname(__file__)
|
|
72
|
+
art_path = os.path.join(cwd, "art", f"{art}.txt")
|
|
73
|
+
if os.path.isfile(art_path):
|
|
74
|
+
with open(art_path, "r") as f:
|
|
75
|
+
return f.read()
|
|
76
|
+
|
|
77
|
+
# 3) otherwise load random file from art/ directory
|
|
78
|
+
cwd = os.path.dirname(__file__)
|
|
79
|
+
art_dir = os.path.join(cwd, "art")
|
|
80
|
+
# Get all .txt files in the art directory
|
|
81
|
+
try:
|
|
82
|
+
art_files = [f for f in os.listdir(art_dir) if f.endswith(".txt")]
|
|
83
|
+
except FileNotFoundError:
|
|
84
|
+
# If art directory doesn't exist, return empty string
|
|
85
|
+
return ""
|
|
86
|
+
if not art_files:
|
|
87
|
+
return ""
|
|
88
|
+
# Select a random file
|
|
89
|
+
random_file = random.choice(art_files)
|
|
90
|
+
random_file_path = os.path.join(art_dir, random_file)
|
|
91
|
+
with open(random_file_path, "r") as f:
|
|
92
|
+
return f.read()
|