cave-cli 3.5.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.
- cave_cli/__init__.py +3 -0
- cave_cli/cli.py +469 -0
- cave_cli/commands/__init__.py +0 -0
- cave_cli/commands/create.py +168 -0
- cave_cli/commands/kill.py +23 -0
- cave_cli/commands/list_cmd.py +37 -0
- cave_cli/commands/list_versions.py +93 -0
- cave_cli/commands/prettify.py +27 -0
- cave_cli/commands/purge.py +70 -0
- cave_cli/commands/reset.py +43 -0
- cave_cli/commands/run.py +189 -0
- cave_cli/commands/sync_cmd.py +79 -0
- cave_cli/commands/test.py +38 -0
- cave_cli/commands/uninstall.py +39 -0
- cave_cli/commands/update.py +38 -0
- cave_cli/commands/upgrade.py +70 -0
- cave_cli/commands/version.py +64 -0
- cave_cli/utils/__init__.py +0 -0
- cave_cli/utils/cache.py +235 -0
- cave_cli/utils/constants.py +43 -0
- cave_cli/utils/docker.py +530 -0
- cave_cli/utils/env.py +267 -0
- cave_cli/utils/git.py +240 -0
- cave_cli/utils/logger.py +77 -0
- cave_cli/utils/net.py +85 -0
- cave_cli/utils/subprocess.py +129 -0
- cave_cli/utils/sync.py +89 -0
- cave_cli/utils/validate.py +218 -0
- cave_cli-3.5.0.dist-info/METADATA +149 -0
- cave_cli-3.5.0.dist-info/RECORD +35 -0
- cave_cli-3.5.0.dist-info/WHEEL +5 -0
- cave_cli-3.5.0.dist-info/entry_points.txt +2 -0
- cave_cli-3.5.0.dist-info/licenses/LICENSE +201 -0
- cave_cli-3.5.0.dist-info/licenses/NOTICE.md +7 -0
- cave_cli-3.5.0.dist-info/top_level.txt +1 -0
cave_cli/__init__.py
ADDED
cave_cli/cli.py
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CAVE CLI entry point.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
cave <command> [options]
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
cave create my_app
|
|
9
|
+
cave create my_app --version v3.1.0
|
|
10
|
+
cave run
|
|
11
|
+
cave run -it
|
|
12
|
+
cave run 192.168.1.1:8000
|
|
13
|
+
cave reset -y
|
|
14
|
+
cave upgrade --version v3.1.0
|
|
15
|
+
cave sync --url git@github.com:mit-cave/cave_app_aws.git
|
|
16
|
+
cave test
|
|
17
|
+
cave prettify
|
|
18
|
+
cave list
|
|
19
|
+
cave kill
|
|
20
|
+
cave purge my_app
|
|
21
|
+
cave list-versions
|
|
22
|
+
cave lv --all --pattern v3*
|
|
23
|
+
cave update
|
|
24
|
+
cave version
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import sys
|
|
29
|
+
from importlib.metadata import version
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_global_args(parser: argparse.ArgumentParser) -> None:
|
|
33
|
+
"""Args shared by all commands."""
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"-v",
|
|
36
|
+
"--verbose",
|
|
37
|
+
action="store_true",
|
|
38
|
+
default=False,
|
|
39
|
+
help="Enable verbose logging output (shorthand for --loglevel DEBUG)",
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--loglevel",
|
|
43
|
+
"--ll",
|
|
44
|
+
default="INFO",
|
|
45
|
+
metavar="LEVEL",
|
|
46
|
+
help=(
|
|
47
|
+
"Specify a log level: DEBUG, INFO, WARN, ERROR, SILENT "
|
|
48
|
+
"(default: INFO)"
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-y",
|
|
53
|
+
"--yes",
|
|
54
|
+
action="store_true",
|
|
55
|
+
default=False,
|
|
56
|
+
help="Automatically answer confirmation prompts with yes",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main():
|
|
61
|
+
__version__ = version("cave_cli")
|
|
62
|
+
parser = argparse.ArgumentParser(
|
|
63
|
+
prog="cave",
|
|
64
|
+
description=(
|
|
65
|
+
f"CAVE CLI ({__version__}): "
|
|
66
|
+
"Create and manage Docker-based CAVE web applications."
|
|
67
|
+
),
|
|
68
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
69
|
+
epilog=__doc__,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"-V",
|
|
74
|
+
"--version",
|
|
75
|
+
action="version",
|
|
76
|
+
version=f"CAVE_CLI={__version__}",
|
|
77
|
+
help="Show the version number and exit",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
subparsers = parser.add_subparsers(dest="command", metavar="command")
|
|
81
|
+
|
|
82
|
+
# ------------------------------------------------------------------ #
|
|
83
|
+
# create #
|
|
84
|
+
# ------------------------------------------------------------------ #
|
|
85
|
+
p_create = subparsers.add_parser(
|
|
86
|
+
"create",
|
|
87
|
+
help="Create a new CAVE app from the template repository",
|
|
88
|
+
)
|
|
89
|
+
add_global_args(p_create)
|
|
90
|
+
p_create.add_argument(
|
|
91
|
+
"name",
|
|
92
|
+
metavar="app-name",
|
|
93
|
+
help="Name for the new CAVE app",
|
|
94
|
+
)
|
|
95
|
+
p_create.add_argument(
|
|
96
|
+
"--version",
|
|
97
|
+
default=None,
|
|
98
|
+
metavar="VERSION",
|
|
99
|
+
help="CAVE app version (git tag or branch name)",
|
|
100
|
+
)
|
|
101
|
+
p_create.add_argument(
|
|
102
|
+
"--url",
|
|
103
|
+
default=None,
|
|
104
|
+
metavar="URL",
|
|
105
|
+
help="Git URL for the app template repository",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# ------------------------------------------------------------------ #
|
|
109
|
+
# run / start #
|
|
110
|
+
# ------------------------------------------------------------------ #
|
|
111
|
+
p_run = subparsers.add_parser(
|
|
112
|
+
"run",
|
|
113
|
+
aliases=["start"],
|
|
114
|
+
help="Build and run the CAVE app in the current directory",
|
|
115
|
+
)
|
|
116
|
+
add_global_args(p_run)
|
|
117
|
+
p_run.add_argument(
|
|
118
|
+
"ip_port",
|
|
119
|
+
nargs="?",
|
|
120
|
+
default=None,
|
|
121
|
+
metavar="ip:port",
|
|
122
|
+
help="IP and port for LAN hosting (e.g. 192.168.1.1:8000)",
|
|
123
|
+
)
|
|
124
|
+
p_run.add_argument(
|
|
125
|
+
"--entrypoint",
|
|
126
|
+
default=None,
|
|
127
|
+
metavar="CMD",
|
|
128
|
+
help="Entrypoint script to run (default: ./utils/run_server.sh)",
|
|
129
|
+
)
|
|
130
|
+
p_run.add_argument(
|
|
131
|
+
"--docker-args",
|
|
132
|
+
default="",
|
|
133
|
+
metavar="ARGS",
|
|
134
|
+
help="Additional arguments to pass to docker run",
|
|
135
|
+
)
|
|
136
|
+
p_run.add_argument(
|
|
137
|
+
"-it",
|
|
138
|
+
"-interactive",
|
|
139
|
+
"--interactive",
|
|
140
|
+
dest="interactive",
|
|
141
|
+
action="store_true",
|
|
142
|
+
default=False,
|
|
143
|
+
help="Run in interactive mode (entrypoint set to bash)",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# ------------------------------------------------------------------ #
|
|
147
|
+
# reset #
|
|
148
|
+
# ------------------------------------------------------------------ #
|
|
149
|
+
p_reset = subparsers.add_parser(
|
|
150
|
+
"reset",
|
|
151
|
+
aliases=["reset-db"],
|
|
152
|
+
help=(
|
|
153
|
+
"Remove Docker containers and volumes, "
|
|
154
|
+
"then rebuild from scratch"
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
add_global_args(p_reset)
|
|
158
|
+
|
|
159
|
+
# ------------------------------------------------------------------ #
|
|
160
|
+
# upgrade #
|
|
161
|
+
# ------------------------------------------------------------------ #
|
|
162
|
+
p_upgrade = subparsers.add_parser(
|
|
163
|
+
"upgrade",
|
|
164
|
+
help="Upgrade the CAVE app in the current directory",
|
|
165
|
+
)
|
|
166
|
+
add_global_args(p_upgrade)
|
|
167
|
+
p_upgrade.add_argument(
|
|
168
|
+
"--version",
|
|
169
|
+
default=None,
|
|
170
|
+
metavar="VERSION",
|
|
171
|
+
help="CAVE app version to upgrade to (git tag or branch name)",
|
|
172
|
+
)
|
|
173
|
+
p_upgrade.add_argument(
|
|
174
|
+
"--url",
|
|
175
|
+
default=None,
|
|
176
|
+
metavar="URL",
|
|
177
|
+
help="Git URL for the app template repository",
|
|
178
|
+
)
|
|
179
|
+
p_upgrade.add_argument(
|
|
180
|
+
"--skip-env-upgrade",
|
|
181
|
+
action="store_true",
|
|
182
|
+
default=False,
|
|
183
|
+
help="Skip upgrading the project .env file",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# ------------------------------------------------------------------ #
|
|
187
|
+
# sync #
|
|
188
|
+
# ------------------------------------------------------------------ #
|
|
189
|
+
p_sync = subparsers.add_parser(
|
|
190
|
+
"sync",
|
|
191
|
+
help="Merge files from another repository into the CAVE app",
|
|
192
|
+
)
|
|
193
|
+
add_global_args(p_sync)
|
|
194
|
+
p_sync.add_argument(
|
|
195
|
+
"--url",
|
|
196
|
+
required=True,
|
|
197
|
+
metavar="URL",
|
|
198
|
+
help="Git URL of the repository to sync from",
|
|
199
|
+
)
|
|
200
|
+
p_sync.add_argument(
|
|
201
|
+
"--branch",
|
|
202
|
+
default=None,
|
|
203
|
+
metavar="BRANCH",
|
|
204
|
+
help="Branch of the repository to sync from",
|
|
205
|
+
)
|
|
206
|
+
p_sync.add_argument(
|
|
207
|
+
"--include",
|
|
208
|
+
nargs="+",
|
|
209
|
+
default=None,
|
|
210
|
+
metavar="PATTERN",
|
|
211
|
+
help="File patterns to include (overrides excludes)",
|
|
212
|
+
)
|
|
213
|
+
p_sync.add_argument(
|
|
214
|
+
"--exclude",
|
|
215
|
+
nargs="+",
|
|
216
|
+
default=None,
|
|
217
|
+
metavar="PATTERN",
|
|
218
|
+
help="File patterns to exclude",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# ------------------------------------------------------------------ #
|
|
222
|
+
# test #
|
|
223
|
+
# ------------------------------------------------------------------ #
|
|
224
|
+
p_test = subparsers.add_parser(
|
|
225
|
+
"test",
|
|
226
|
+
help="Run tests in cave_api/tests/",
|
|
227
|
+
)
|
|
228
|
+
add_global_args(p_test)
|
|
229
|
+
p_test.add_argument(
|
|
230
|
+
"remaining",
|
|
231
|
+
nargs="*",
|
|
232
|
+
help="Additional arguments passed to the test runner",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# ------------------------------------------------------------------ #
|
|
236
|
+
# prettify #
|
|
237
|
+
# ------------------------------------------------------------------ #
|
|
238
|
+
p_prettify = subparsers.add_parser(
|
|
239
|
+
"prettify",
|
|
240
|
+
help="Format code with autoflake and black",
|
|
241
|
+
)
|
|
242
|
+
add_global_args(p_prettify)
|
|
243
|
+
|
|
244
|
+
# ------------------------------------------------------------------ #
|
|
245
|
+
# list #
|
|
246
|
+
# ------------------------------------------------------------------ #
|
|
247
|
+
p_list = subparsers.add_parser(
|
|
248
|
+
"list",
|
|
249
|
+
help="List running CAVE apps",
|
|
250
|
+
)
|
|
251
|
+
add_global_args(p_list)
|
|
252
|
+
p_list.add_argument(
|
|
253
|
+
"-a",
|
|
254
|
+
"--all",
|
|
255
|
+
action="store_true",
|
|
256
|
+
default=False,
|
|
257
|
+
help="Show all CAVE app containers with full names",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# ------------------------------------------------------------------ #
|
|
261
|
+
# kill #
|
|
262
|
+
# ------------------------------------------------------------------ #
|
|
263
|
+
p_kill = subparsers.add_parser(
|
|
264
|
+
"kill",
|
|
265
|
+
help="Stop Docker containers for a CAVE app",
|
|
266
|
+
)
|
|
267
|
+
add_global_args(p_kill)
|
|
268
|
+
p_kill.add_argument(
|
|
269
|
+
"-a",
|
|
270
|
+
"--all",
|
|
271
|
+
action="store_true",
|
|
272
|
+
default=False,
|
|
273
|
+
help="Kill all running CAVE apps",
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# ------------------------------------------------------------------ #
|
|
277
|
+
# purge #
|
|
278
|
+
# ------------------------------------------------------------------ #
|
|
279
|
+
p_purge = subparsers.add_parser(
|
|
280
|
+
"purge",
|
|
281
|
+
help="Remove a CAVE app and all its Docker resources",
|
|
282
|
+
)
|
|
283
|
+
add_global_args(p_purge)
|
|
284
|
+
p_purge.add_argument(
|
|
285
|
+
"path",
|
|
286
|
+
metavar="app-path",
|
|
287
|
+
help="Path to the CAVE app directory to purge",
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# ------------------------------------------------------------------ #
|
|
291
|
+
# list-versions / lv #
|
|
292
|
+
# ------------------------------------------------------------------ #
|
|
293
|
+
p_lv = subparsers.add_parser(
|
|
294
|
+
"list-versions",
|
|
295
|
+
aliases=["lv"],
|
|
296
|
+
help="List available CAVE app versions",
|
|
297
|
+
)
|
|
298
|
+
add_global_args(p_lv)
|
|
299
|
+
p_lv.add_argument(
|
|
300
|
+
"--all",
|
|
301
|
+
action="store_true",
|
|
302
|
+
default=False,
|
|
303
|
+
help="Show all versions (default: 5 most recent per major version)",
|
|
304
|
+
)
|
|
305
|
+
p_lv.add_argument(
|
|
306
|
+
"--pattern",
|
|
307
|
+
default=None,
|
|
308
|
+
metavar="PATTERN",
|
|
309
|
+
help="Glob pattern to filter versions (e.g. v3.*, v3.4.*)",
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# ------------------------------------------------------------------ #
|
|
313
|
+
# update #
|
|
314
|
+
# ------------------------------------------------------------------ #
|
|
315
|
+
p_update = subparsers.add_parser(
|
|
316
|
+
"update",
|
|
317
|
+
help="Update the CAVE CLI itself",
|
|
318
|
+
)
|
|
319
|
+
add_global_args(p_update)
|
|
320
|
+
p_update.add_argument(
|
|
321
|
+
"--version",
|
|
322
|
+
default=None,
|
|
323
|
+
metavar="VERSION",
|
|
324
|
+
help="Specific CAVE CLI version to install (git tag or branch)",
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# ------------------------------------------------------------------ #
|
|
328
|
+
# uninstall #
|
|
329
|
+
# ------------------------------------------------------------------ #
|
|
330
|
+
p_uninstall = subparsers.add_parser(
|
|
331
|
+
"uninstall",
|
|
332
|
+
help="Remove the CAVE CLI",
|
|
333
|
+
)
|
|
334
|
+
add_global_args(p_uninstall)
|
|
335
|
+
|
|
336
|
+
# ------------------------------------------------------------------ #
|
|
337
|
+
# version #
|
|
338
|
+
# ------------------------------------------------------------------ #
|
|
339
|
+
p_version = subparsers.add_parser(
|
|
340
|
+
"version",
|
|
341
|
+
help="Print version information",
|
|
342
|
+
)
|
|
343
|
+
add_global_args(p_version)
|
|
344
|
+
|
|
345
|
+
# ------------------------------------------------------------------ #
|
|
346
|
+
# Dispatch #
|
|
347
|
+
# ------------------------------------------------------------------ #
|
|
348
|
+
args = parser.parse_args()
|
|
349
|
+
|
|
350
|
+
if args.command is None:
|
|
351
|
+
parser.print_help()
|
|
352
|
+
sys.exit(0)
|
|
353
|
+
|
|
354
|
+
# Normalize aliases
|
|
355
|
+
_COMMAND_ALIASES: dict[str, str] = {
|
|
356
|
+
"start": "run",
|
|
357
|
+
"reset-db": "reset",
|
|
358
|
+
"lv": "list-versions",
|
|
359
|
+
}
|
|
360
|
+
args.command = _COMMAND_ALIASES.get(args.command, args.command)
|
|
361
|
+
|
|
362
|
+
# Configure logging
|
|
363
|
+
from cave_cli.utils.logger import logger
|
|
364
|
+
|
|
365
|
+
if args.verbose:
|
|
366
|
+
logger.set_level("DEBUG")
|
|
367
|
+
else:
|
|
368
|
+
logger.set_level(args.loglevel)
|
|
369
|
+
|
|
370
|
+
# ------------------------------------------------------------------ #
|
|
371
|
+
# Command dispatch #
|
|
372
|
+
# ------------------------------------------------------------------ #
|
|
373
|
+
if args.command == "create":
|
|
374
|
+
from cave_cli.utils.docker import check_docker
|
|
375
|
+
from cave_cli.commands.create import create
|
|
376
|
+
|
|
377
|
+
check_docker()
|
|
378
|
+
create(args)
|
|
379
|
+
|
|
380
|
+
elif args.command == "run":
|
|
381
|
+
from cave_cli.utils.docker import check_docker
|
|
382
|
+
from cave_cli.commands.run import run
|
|
383
|
+
|
|
384
|
+
check_docker()
|
|
385
|
+
run(args)
|
|
386
|
+
|
|
387
|
+
elif args.command == "reset":
|
|
388
|
+
from cave_cli.utils.docker import check_docker
|
|
389
|
+
from cave_cli.commands.reset import reset
|
|
390
|
+
|
|
391
|
+
check_docker()
|
|
392
|
+
reset(args)
|
|
393
|
+
|
|
394
|
+
elif args.command == "upgrade":
|
|
395
|
+
from cave_cli.utils.docker import check_docker
|
|
396
|
+
from cave_cli.commands.upgrade import upgrade
|
|
397
|
+
|
|
398
|
+
check_docker()
|
|
399
|
+
upgrade(args)
|
|
400
|
+
|
|
401
|
+
elif args.command == "sync":
|
|
402
|
+
from cave_cli.utils.docker import check_docker
|
|
403
|
+
from cave_cli.commands.sync_cmd import sync_cmd
|
|
404
|
+
|
|
405
|
+
check_docker()
|
|
406
|
+
sync_cmd(args)
|
|
407
|
+
|
|
408
|
+
elif args.command == "test":
|
|
409
|
+
from cave_cli.utils.docker import check_docker
|
|
410
|
+
from cave_cli.commands.test import test
|
|
411
|
+
|
|
412
|
+
check_docker()
|
|
413
|
+
test(args)
|
|
414
|
+
|
|
415
|
+
elif args.command == "prettify":
|
|
416
|
+
from cave_cli.utils.docker import check_docker
|
|
417
|
+
from cave_cli.commands.prettify import prettify
|
|
418
|
+
|
|
419
|
+
check_docker()
|
|
420
|
+
prettify(args)
|
|
421
|
+
|
|
422
|
+
elif args.command == "list":
|
|
423
|
+
from cave_cli.utils.docker import check_docker
|
|
424
|
+
from cave_cli.commands.list_cmd import list_cmd
|
|
425
|
+
|
|
426
|
+
check_docker()
|
|
427
|
+
list_cmd(args)
|
|
428
|
+
|
|
429
|
+
elif args.command == "kill":
|
|
430
|
+
from cave_cli.utils.docker import check_docker
|
|
431
|
+
from cave_cli.commands.kill import kill
|
|
432
|
+
|
|
433
|
+
check_docker()
|
|
434
|
+
kill(args)
|
|
435
|
+
|
|
436
|
+
elif args.command == "purge":
|
|
437
|
+
from cave_cli.utils.docker import check_docker
|
|
438
|
+
from cave_cli.commands.purge import purge
|
|
439
|
+
|
|
440
|
+
check_docker()
|
|
441
|
+
purge(args)
|
|
442
|
+
|
|
443
|
+
elif args.command == "list-versions":
|
|
444
|
+
from cave_cli.commands.list_versions import list_versions
|
|
445
|
+
|
|
446
|
+
list_versions(args)
|
|
447
|
+
|
|
448
|
+
elif args.command == "update":
|
|
449
|
+
from cave_cli.commands.update import update
|
|
450
|
+
|
|
451
|
+
update(args)
|
|
452
|
+
|
|
453
|
+
elif args.command == "uninstall":
|
|
454
|
+
from cave_cli.commands.uninstall import uninstall
|
|
455
|
+
|
|
456
|
+
uninstall(args)
|
|
457
|
+
|
|
458
|
+
elif args.command == "version":
|
|
459
|
+
from cave_cli.commands.version import version as version_cmd
|
|
460
|
+
|
|
461
|
+
version_cmd(args)
|
|
462
|
+
|
|
463
|
+
else:
|
|
464
|
+
parser.print_help()
|
|
465
|
+
sys.exit(1)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
if __name__ == "__main__":
|
|
469
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import stat
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from cave_cli.commands.reset import reset
|
|
9
|
+
from cave_cli.commands.run import run_cave
|
|
10
|
+
from cave_cli.utils.constants import HTTPS_URL
|
|
11
|
+
from cave_cli.utils.docker import build_image, check_docker, generate_secret_key
|
|
12
|
+
from cave_cli.utils.env import create_env_interactive
|
|
13
|
+
from cave_cli.utils.git import add, branch_rename, clone, commit, init
|
|
14
|
+
from cave_cli.utils.logger import logger
|
|
15
|
+
from cave_cli.utils.validate import validate_app_name
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create(args: argparse.Namespace) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Usage:
|
|
21
|
+
|
|
22
|
+
- Creates a new CAVE app from the template repository
|
|
23
|
+
"""
|
|
24
|
+
app_name = args.name
|
|
25
|
+
error = validate_app_name(app_name)
|
|
26
|
+
if error:
|
|
27
|
+
logger.error(error)
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
if os.path.isdir(app_name):
|
|
31
|
+
logger.error(
|
|
32
|
+
f"Cannot create app '{app_name}': "
|
|
33
|
+
"This folder already exists in the current directory"
|
|
34
|
+
)
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
clone_url = getattr(args, "url", None) or HTTPS_URL
|
|
38
|
+
version = getattr(args, "version", None)
|
|
39
|
+
|
|
40
|
+
logger.header("App Creation:")
|
|
41
|
+
logger.info("Downloading the app template...")
|
|
42
|
+
|
|
43
|
+
success = clone(clone_url, app_name, branch=version)
|
|
44
|
+
if not success or not os.path.isdir(app_name):
|
|
45
|
+
logger.error("Clone failed. Ensure you used a valid version.")
|
|
46
|
+
logger.error(
|
|
47
|
+
f"The version must be a tag (or branch) listed at {clone_url}."
|
|
48
|
+
)
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
logger.info("Done")
|
|
52
|
+
|
|
53
|
+
app_dir = os.path.abspath(app_name)
|
|
54
|
+
remove_licence_info(app_dir)
|
|
55
|
+
|
|
56
|
+
Path(os.path.join(app_dir, ".env")).touch()
|
|
57
|
+
|
|
58
|
+
example_env = os.path.join(app_dir, "example.env")
|
|
59
|
+
env_path = os.path.join(app_dir, ".env")
|
|
60
|
+
|
|
61
|
+
build_image(app_name, app_dir)
|
|
62
|
+
secret_key = generate_secret_key(app_name)
|
|
63
|
+
|
|
64
|
+
create_env_interactive(
|
|
65
|
+
app_name=app_name,
|
|
66
|
+
env_path=env_path,
|
|
67
|
+
template_path=example_env,
|
|
68
|
+
docker_secret_key=secret_key,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
reset_args = argparse.Namespace(
|
|
72
|
+
yes=True,
|
|
73
|
+
verbose=getattr(args, "verbose", False),
|
|
74
|
+
loglevel=getattr(args, "loglevel", "INFO"),
|
|
75
|
+
)
|
|
76
|
+
reset(reset_args, app_dir=app_dir, app_name=app_name)
|
|
77
|
+
|
|
78
|
+
logger.header("Version Control:")
|
|
79
|
+
logger.info("Configuring git repository...")
|
|
80
|
+
git_dir = os.path.join(app_dir, ".git")
|
|
81
|
+
if os.path.isdir(git_dir):
|
|
82
|
+
rmtree_force(git_dir)
|
|
83
|
+
init(app_dir)
|
|
84
|
+
|
|
85
|
+
gitignore_path = os.path.join(app_dir, ".gitignore")
|
|
86
|
+
if os.path.isfile(gitignore_path):
|
|
87
|
+
content = Path(gitignore_path).read_text()
|
|
88
|
+
content = content.replace(".env", "")
|
|
89
|
+
Path(gitignore_path).write_text(content)
|
|
90
|
+
|
|
91
|
+
if os.path.isfile(gitignore_path):
|
|
92
|
+
content = Path(gitignore_path).read_text()
|
|
93
|
+
if "media" not in content:
|
|
94
|
+
content += "\n# Media\nmedia\n"
|
|
95
|
+
Path(gitignore_path).write_text(content)
|
|
96
|
+
|
|
97
|
+
add(app_dir)
|
|
98
|
+
commit(app_dir, "Initialize CAVE App")
|
|
99
|
+
branch_rename(app_dir, "main")
|
|
100
|
+
logger.info("Done.")
|
|
101
|
+
|
|
102
|
+
logger.info("Generating LLM Docs...")
|
|
103
|
+
docs_args = argparse.Namespace(
|
|
104
|
+
entrypoint="./utils/generate_docs.sh",
|
|
105
|
+
interactive=False,
|
|
106
|
+
it=False,
|
|
107
|
+
docker_args="",
|
|
108
|
+
ip_port=None,
|
|
109
|
+
yes=True,
|
|
110
|
+
verbose=getattr(args, "verbose", False),
|
|
111
|
+
loglevel=getattr(args, "loglevel", "INFO"),
|
|
112
|
+
)
|
|
113
|
+
run_cave(app_dir, app_name, docs_args)
|
|
114
|
+
logger.info("Done.")
|
|
115
|
+
|
|
116
|
+
logger.header("App Creation Status:")
|
|
117
|
+
logger.info(f"App '{app_name}' created successfully!")
|
|
118
|
+
logger.info(
|
|
119
|
+
f"Created variables and additional configuration options "
|
|
120
|
+
f"are available in {app_name}/.env"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def force_remove(func, path, exc):
|
|
125
|
+
os.chmod(path, stat.S_IWRITE)
|
|
126
|
+
func(path)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def rmtree_force(path: str) -> None:
|
|
130
|
+
if sys.version_info >= (3, 12):
|
|
131
|
+
shutil.rmtree(path, onexc=force_remove)
|
|
132
|
+
else:
|
|
133
|
+
shutil.rmtree(path, onerror=force_remove)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def remove_licence_info(app_dir: str) -> None:
|
|
137
|
+
license_path = os.path.join(app_dir, "LICENSE")
|
|
138
|
+
if os.path.isfile(license_path):
|
|
139
|
+
os.remove(license_path)
|
|
140
|
+
|
|
141
|
+
readme_path = os.path.join(app_dir, "README.md")
|
|
142
|
+
if os.path.isfile(readme_path):
|
|
143
|
+
lines = Path(readme_path).read_text().splitlines()
|
|
144
|
+
for i, line in enumerate(lines):
|
|
145
|
+
if line.strip() == "## License Notice":
|
|
146
|
+
lines = lines[:i]
|
|
147
|
+
break
|
|
148
|
+
Path(readme_path).write_text("\n".join(lines) + "\n")
|
|
149
|
+
|
|
150
|
+
notice_path = os.path.join(app_dir, "NOTICE.md")
|
|
151
|
+
if os.path.isfile(notice_path):
|
|
152
|
+
lines = Path(notice_path).read_text().splitlines()
|
|
153
|
+
for i, line in enumerate(lines):
|
|
154
|
+
if line.startswith("Licensed under"):
|
|
155
|
+
lines = lines[:i]
|
|
156
|
+
break
|
|
157
|
+
Path(notice_path).write_text("\n".join(lines) + "\n")
|
|
158
|
+
|
|
159
|
+
setup_path = os.path.join(app_dir, "cave_api", "setup.py")
|
|
160
|
+
if os.path.isfile(setup_path):
|
|
161
|
+
content = Path(setup_path).read_text()
|
|
162
|
+
import re
|
|
163
|
+
|
|
164
|
+
content = re.sub(r'^\s*license="MIT",\s*\n', "", content, flags=re.M)
|
|
165
|
+
content = re.sub(
|
|
166
|
+
r'^\s*"License.*MIT License",\s*\n', "", content, flags=re.M
|
|
167
|
+
)
|
|
168
|
+
Path(setup_path).write_text(content)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from cave_cli.utils.docker import get_running_apps, remove_containers
|
|
4
|
+
from cave_cli.utils.logger import logger
|
|
5
|
+
from cave_cli.utils.validate import get_app
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def kill(args: argparse.Namespace) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Usage:
|
|
11
|
+
|
|
12
|
+
- Stops Docker containers for CAVE apps
|
|
13
|
+
"""
|
|
14
|
+
kill_all = getattr(args, "all", False)
|
|
15
|
+
|
|
16
|
+
if kill_all:
|
|
17
|
+
for app_name in get_running_apps():
|
|
18
|
+
remove_containers(app_name)
|
|
19
|
+
logger.info(f"Killed: {app_name}")
|
|
20
|
+
else:
|
|
21
|
+
_, app_name = get_app()
|
|
22
|
+
remove_containers(app_name)
|
|
23
|
+
logger.info(f"Killed: {app_name}")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from cave_cli.utils.docker import (
|
|
4
|
+
get_container_env,
|
|
5
|
+
get_container_host_port,
|
|
6
|
+
get_all_containers,
|
|
7
|
+
get_running_apps,
|
|
8
|
+
)
|
|
9
|
+
from cave_cli.utils.logger import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def list_cmd(args: argparse.Namespace) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Usage:
|
|
15
|
+
|
|
16
|
+
- Lists running CAVE apps or all CAVE app containers
|
|
17
|
+
"""
|
|
18
|
+
show_all = getattr(args, "all", False)
|
|
19
|
+
|
|
20
|
+
if show_all:
|
|
21
|
+
logger.header("CAVE App Containers (All):")
|
|
22
|
+
for suffix in ("_django", "_db_host", "_redis_host", "_nginx_host"):
|
|
23
|
+
for name in get_all_containers(suffix):
|
|
24
|
+
logger.info(name)
|
|
25
|
+
else:
|
|
26
|
+
logger.header("CAVE Apps (Running):")
|
|
27
|
+
apps = get_running_apps()
|
|
28
|
+
for app_name in apps:
|
|
29
|
+
nginx_containers = get_all_containers("_nginx_host")
|
|
30
|
+
nginx_name = f"{app_name}_nginx_host"
|
|
31
|
+
if nginx_name in nginx_containers:
|
|
32
|
+
ip = get_container_env(nginx_name, "CAVE_IP")
|
|
33
|
+
port = get_container_env(nginx_name, "CAVE_PORT")
|
|
34
|
+
logger.info(f"{app_name} (https://{ip}:{port})")
|
|
35
|
+
else:
|
|
36
|
+
port = get_container_host_port(f"{app_name}_django")
|
|
37
|
+
logger.info(f"{app_name} (http://localhost:{port})")
|