taurido 1.0.0__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.
- taurido/__init__.py +2 -0
- taurido/cli.py +176 -0
- taurido/core.py +760 -0
- taurido/plan.py +32 -0
- taurido-1.0.0.dist-info/METADATA +752 -0
- taurido-1.0.0.dist-info/RECORD +8 -0
- taurido-1.0.0.dist-info/WHEEL +4 -0
- taurido-1.0.0.dist-info/entry_points.txt +2 -0
taurido/__init__.py
ADDED
taurido/cli.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Canonical command-line interface for every Dock2Tauri launcher."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional, Sequence, Tuple
|
|
10
|
+
|
|
11
|
+
from .core import Runner
|
|
12
|
+
from .plan import BuildPlan
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _load_env_file(path: Path) -> None:
|
|
16
|
+
"""Load simple KEY=VALUE settings without evaluating shell code."""
|
|
17
|
+
if not path.is_file():
|
|
18
|
+
return
|
|
19
|
+
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
|
20
|
+
line = raw_line.strip()
|
|
21
|
+
if not line or line.startswith("#") or "=" not in line:
|
|
22
|
+
continue
|
|
23
|
+
if line.startswith("export "):
|
|
24
|
+
line = line[7:].lstrip()
|
|
25
|
+
key, value = line.split("=", 1)
|
|
26
|
+
key = key.strip()
|
|
27
|
+
value = value.strip().strip("\"'")
|
|
28
|
+
if key.isidentifier():
|
|
29
|
+
os.environ.setdefault(key, value)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _copy_targets(value: Optional[str]) -> Tuple[str, ...]:
|
|
33
|
+
if not value:
|
|
34
|
+
return ()
|
|
35
|
+
return tuple(item.strip() for item in value.split(",") if item.strip())
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
39
|
+
config_root = Path(os.environ.get("TAURIDO_PROJECT_ROOT", Path.cwd()))
|
|
40
|
+
_load_env_file(config_root / ".env")
|
|
41
|
+
|
|
42
|
+
parser = argparse.ArgumentParser(
|
|
43
|
+
prog="taurido",
|
|
44
|
+
description="Package a Dockerized web application as a Tauri desktop app",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"image_or_dockerfile",
|
|
48
|
+
nargs="?",
|
|
49
|
+
default=os.environ.get("DOCKER_IMAGE", "nginx:alpine"),
|
|
50
|
+
help="Docker image or Dockerfile path (default: nginx:alpine)",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument("host_port", nargs="?", default="8088", help="Host port (default: 8088)")
|
|
53
|
+
parser.add_argument("container_port", nargs="?", default="80", help="Container port (default: 80)")
|
|
54
|
+
parser.add_argument("--build", "-b", action="store_true", help="Build Tauri release bundles")
|
|
55
|
+
parser.add_argument("--target", help="Target triple for cargo tauri build")
|
|
56
|
+
parser.add_argument("--health-url", dest="health_url", help="Override readiness URL")
|
|
57
|
+
parser.add_argument("--timeout", type=int, default=30, help="Readiness timeout seconds (default: 30)")
|
|
58
|
+
parser.add_argument("--cross", action="store_true", help="Attempt installed cross targets")
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--project-root",
|
|
61
|
+
help="Directory containing src-tauri; automatically detected when omitted",
|
|
62
|
+
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--export-dir",
|
|
65
|
+
"--output-dir",
|
|
66
|
+
dest="export_dir",
|
|
67
|
+
default=os.environ.get("OUTPUT_DIR"),
|
|
68
|
+
help="Bundle export directory (default: project-root/dist)",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"--app-name",
|
|
72
|
+
default=os.environ.get("CUSTOM_APP_NAME"),
|
|
73
|
+
help="Product name stored in the generated Tauri configuration",
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--filename",
|
|
77
|
+
dest="filename_prefix",
|
|
78
|
+
default=os.environ.get("CUSTOM_FILENAME"),
|
|
79
|
+
help="Prefix copied artifact filenames",
|
|
80
|
+
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--copy-to",
|
|
83
|
+
default=os.environ.get("ADDITIONAL_OUTPUT_DIRS"),
|
|
84
|
+
help="Comma-separated additional artifact directories",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument("--launch", action="store_true", help="Launch the built application")
|
|
87
|
+
parser.add_argument("--list-bundles", action="store_true", help="List generated bundle contents")
|
|
88
|
+
parser.add_argument("--debug", action="store_true", help="Enable diagnostic environment output")
|
|
89
|
+
parser.add_argument(
|
|
90
|
+
"--print-plan",
|
|
91
|
+
action="store_true",
|
|
92
|
+
help="Print the normalized JSON execution plan without running Docker or Tauri",
|
|
93
|
+
)
|
|
94
|
+
return parser
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
|
|
98
|
+
args = build_parser().parse_args(argv)
|
|
99
|
+
if os.path.isfile(args.image_or_dockerfile) and not args.build:
|
|
100
|
+
args.build = True
|
|
101
|
+
os.environ.setdefault("EXPORT_BUNDLES", "1")
|
|
102
|
+
if not args.print_plan:
|
|
103
|
+
print("\x1b[34mℹ️ Dockerfile input detected; defaulting to build and export bundles.\x1b[0m")
|
|
104
|
+
return args
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_plan(args: argparse.Namespace) -> BuildPlan:
|
|
108
|
+
return BuildPlan(
|
|
109
|
+
image_or_dockerfile=args.image_or_dockerfile,
|
|
110
|
+
host_port=str(args.host_port),
|
|
111
|
+
container_port=str(args.container_port),
|
|
112
|
+
build=args.build,
|
|
113
|
+
target=args.target,
|
|
114
|
+
health_url=args.health_url,
|
|
115
|
+
timeout=int(args.timeout),
|
|
116
|
+
cross=args.cross,
|
|
117
|
+
project_root=args.project_root,
|
|
118
|
+
export_dir=args.export_dir,
|
|
119
|
+
app_name=args.app_name,
|
|
120
|
+
filename_prefix=args.filename_prefix,
|
|
121
|
+
copy_to=_copy_targets(args.copy_to),
|
|
122
|
+
launch=args.launch,
|
|
123
|
+
list_bundles=args.list_bundles,
|
|
124
|
+
debug=args.debug,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def execute_plan(plan: BuildPlan) -> None:
|
|
129
|
+
if plan.debug:
|
|
130
|
+
os.environ["DOCK2TAURI_DEBUG"] = "1"
|
|
131
|
+
runner = Runner(
|
|
132
|
+
base_dir=Path(plan.project_root) if plan.project_root else None,
|
|
133
|
+
export_dir=Path(plan.export_dir) if plan.export_dir else None,
|
|
134
|
+
launch_after_build=plan.launch,
|
|
135
|
+
list_bundles=plan.list_bundles,
|
|
136
|
+
app_name=plan.app_name,
|
|
137
|
+
filename_prefix=plan.filename_prefix,
|
|
138
|
+
additional_output_dirs=[Path(item) for item in plan.copy_to],
|
|
139
|
+
)
|
|
140
|
+
try:
|
|
141
|
+
if plan.build:
|
|
142
|
+
runner.build_flow(
|
|
143
|
+
image_or_dockerfile=plan.image_or_dockerfile,
|
|
144
|
+
host_port=plan.host_port,
|
|
145
|
+
container_port=plan.container_port,
|
|
146
|
+
target=plan.target or "",
|
|
147
|
+
cross=plan.cross,
|
|
148
|
+
health_url=plan.health_url,
|
|
149
|
+
timeout=plan.timeout,
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
runner.dev_flow(
|
|
153
|
+
image_or_dockerfile=plan.image_or_dockerfile,
|
|
154
|
+
host_port=plan.host_port,
|
|
155
|
+
container_port=plan.container_port,
|
|
156
|
+
health_url=plan.health_url,
|
|
157
|
+
timeout=plan.timeout,
|
|
158
|
+
)
|
|
159
|
+
except KeyboardInterrupt:
|
|
160
|
+
pass
|
|
161
|
+
finally:
|
|
162
|
+
runner.cleanup()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
166
|
+
args = parse_args(argv)
|
|
167
|
+
plan = create_plan(args)
|
|
168
|
+
if args.print_plan:
|
|
169
|
+
print(json.dumps(plan.to_dict(), sort_keys=True))
|
|
170
|
+
return 0
|
|
171
|
+
execute_plan(plan)
|
|
172
|
+
return 0
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
if __name__ == "__main__":
|
|
176
|
+
raise SystemExit(main())
|