yal-cmd 0.1.0__tar.gz
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.
- yal_cmd-0.1.0/LICENSE +21 -0
- yal_cmd-0.1.0/PKG-INFO +119 -0
- yal_cmd-0.1.0/README.md +104 -0
- yal_cmd-0.1.0/pyproject.toml +26 -0
- yal_cmd-0.1.0/setup.cfg +4 -0
- yal_cmd-0.1.0/yal/__init__.py +0 -0
- yal_cmd-0.1.0/yal/cli.py +60 -0
- yal_cmd-0.1.0/yal/commands/create.py +92 -0
- yal_cmd-0.1.0/yal/commands/update.py +119 -0
- yal_cmd-0.1.0/yal/github.py +158 -0
- yal_cmd-0.1.0/yal/i18n.py +100 -0
- yal_cmd-0.1.0/yal/store.py +126 -0
- yal_cmd-0.1.0/yal/template_config.py +198 -0
- yal_cmd-0.1.0/yal/templates/book_handler.py +180 -0
- yal_cmd-0.1.0/yal/templates/registry.py +69 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/PKG-INFO +119 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/SOURCES.txt +19 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/dependency_links.txt +1 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/entry_points.txt +2 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/requires.txt +6 -0
- yal_cmd-0.1.0/yal_cmd.egg-info/top_level.txt +2 -0
yal_cmd-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Я́лла Нкарда́з д͏е Туде́рий
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
yal_cmd-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yal-cmd
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Yalla Nkardaz’s personal CLI toolkit
|
|
5
|
+
Author-email: Yalla Nkardaz <dev_nkardaz@proton.me>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: requests
|
|
11
|
+
Requires-Dist: pyyaml
|
|
12
|
+
Requires-Dist: ruamel.yaml
|
|
13
|
+
Requires-Dist: tomli; python_version < "3.11"
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# YAL
|
|
17
|
+
|
|
18
|
+
**YAL** is a command-line utility for project initialization and updates based on templates.
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
- `yal create <kind>[:<name>][@<ref>]` — uses a template to create a new project (currently supports only `book` kind)
|
|
23
|
+
- `yal update <kind>[:<name>]` — updates an existing project (currently supports only `book` kind)
|
|
24
|
+
|
|
25
|
+
## Install utility
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install yal
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Create a project
|
|
32
|
+
Downloads the template (if not cached locally) and initiates the configuration process.
|
|
33
|
+
```bash
|
|
34
|
+
# Basic usage
|
|
35
|
+
yal create book
|
|
36
|
+
|
|
37
|
+
# Using a specific template
|
|
38
|
+
yal create book:template-name
|
|
39
|
+
|
|
40
|
+
# Using a specific version (tag or commit hash)
|
|
41
|
+
yal create book@version
|
|
42
|
+
|
|
43
|
+
# Combined usage
|
|
44
|
+
yal create book:template-name@version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## yal.toml
|
|
48
|
+
|
|
49
|
+
A configuration file used as a prompt when creating a project from a template. The `yal.toml` file is located in the root of the template and may have a structure like the following:
|
|
50
|
+
|
|
51
|
+
```toml
|
|
52
|
+
[meta]
|
|
53
|
+
yal-min-version = "0.1.0"
|
|
54
|
+
|
|
55
|
+
[[fields]]
|
|
56
|
+
id = "book-name"
|
|
57
|
+
type = "text"
|
|
58
|
+
required = true
|
|
59
|
+
default = "{placeholder}"
|
|
60
|
+
is-folder-name = true
|
|
61
|
+
|
|
62
|
+
[[fields]]
|
|
63
|
+
id = "book-author"
|
|
64
|
+
type = "text"
|
|
65
|
+
required = false
|
|
66
|
+
default = ""
|
|
67
|
+
|
|
68
|
+
[[fields]]
|
|
69
|
+
id = "book-lang"
|
|
70
|
+
type = "select"
|
|
71
|
+
options = ["ru", "en", "de"]
|
|
72
|
+
default = "ru"
|
|
73
|
+
|
|
74
|
+
[messages.ru]
|
|
75
|
+
book-name.prompt = "Введите название книги"
|
|
76
|
+
book-name.placeholder = "Книга без названия"
|
|
77
|
+
book-author.prompt = "Введите имя автора"
|
|
78
|
+
book-author.placeholder = "Аноним"
|
|
79
|
+
book-lang.prompt = "Выберите язык книги в формате ISO-639"
|
|
80
|
+
|
|
81
|
+
[messages.en]
|
|
82
|
+
book-name.prompt = "Enter book title"
|
|
83
|
+
book-name.placeholder = "Untitled book"
|
|
84
|
+
book-author.prompt = "Enter author name"
|
|
85
|
+
book-author.placeholder = "Anonymous"
|
|
86
|
+
book-lang.prompt = "Select book language in ISO-639 format"
|
|
87
|
+
|
|
88
|
+
[[targets]]
|
|
89
|
+
file = "/meta/book.yml"
|
|
90
|
+
format = "yaml"
|
|
91
|
+
|
|
92
|
+
[[targets.fields]]
|
|
93
|
+
field = "book-name"
|
|
94
|
+
key = "book.title"
|
|
95
|
+
|
|
96
|
+
[[targets.fields]]
|
|
97
|
+
field = "book-author"
|
|
98
|
+
key = "author[0].name"
|
|
99
|
+
|
|
100
|
+
[[targets.fields]]
|
|
101
|
+
field = "book-lang"
|
|
102
|
+
key = "property.language[ISO-639]"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## Built-in templates
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
### \<Book\> Typst Book Template
|
|
110
|
+
|
|
111
|
+
- **Repo:** https://github.com/DemerNkardaz/Typst-Book-Template
|
|
112
|
+
- **Name:** default
|
|
113
|
+
|
|
114
|
+
A template for creating a book using [Typst](https://typst.app/), including a prebuilt structure, plugins, styles, settings, and a build system that combines Typst and Python tools.
|
|
115
|
+
|
|
116
|
+
Requires installation of the [Typst compiler](https://github.com/typst/typst/releases) and the Python packages `pyyaml`, `pikepdf`, and `pillow`.
|
|
117
|
+
```bash
|
|
118
|
+
pip install pyyaml pikepdf pillow
|
|
119
|
+
```
|
yal_cmd-0.1.0/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# YAL
|
|
2
|
+
|
|
3
|
+
**YAL** is a command-line utility for project initialization and updates based on templates.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
- `yal create <kind>[:<name>][@<ref>]` — uses a template to create a new project (currently supports only `book` kind)
|
|
8
|
+
- `yal update <kind>[:<name>]` — updates an existing project (currently supports only `book` kind)
|
|
9
|
+
|
|
10
|
+
## Install utility
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install yal
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Create a project
|
|
17
|
+
Downloads the template (if not cached locally) and initiates the configuration process.
|
|
18
|
+
```bash
|
|
19
|
+
# Basic usage
|
|
20
|
+
yal create book
|
|
21
|
+
|
|
22
|
+
# Using a specific template
|
|
23
|
+
yal create book:template-name
|
|
24
|
+
|
|
25
|
+
# Using a specific version (tag or commit hash)
|
|
26
|
+
yal create book@version
|
|
27
|
+
|
|
28
|
+
# Combined usage
|
|
29
|
+
yal create book:template-name@version
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## yal.toml
|
|
33
|
+
|
|
34
|
+
A configuration file used as a prompt when creating a project from a template. The `yal.toml` file is located in the root of the template and may have a structure like the following:
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
[meta]
|
|
38
|
+
yal-min-version = "0.1.0"
|
|
39
|
+
|
|
40
|
+
[[fields]]
|
|
41
|
+
id = "book-name"
|
|
42
|
+
type = "text"
|
|
43
|
+
required = true
|
|
44
|
+
default = "{placeholder}"
|
|
45
|
+
is-folder-name = true
|
|
46
|
+
|
|
47
|
+
[[fields]]
|
|
48
|
+
id = "book-author"
|
|
49
|
+
type = "text"
|
|
50
|
+
required = false
|
|
51
|
+
default = ""
|
|
52
|
+
|
|
53
|
+
[[fields]]
|
|
54
|
+
id = "book-lang"
|
|
55
|
+
type = "select"
|
|
56
|
+
options = ["ru", "en", "de"]
|
|
57
|
+
default = "ru"
|
|
58
|
+
|
|
59
|
+
[messages.ru]
|
|
60
|
+
book-name.prompt = "Введите название книги"
|
|
61
|
+
book-name.placeholder = "Книга без названия"
|
|
62
|
+
book-author.prompt = "Введите имя автора"
|
|
63
|
+
book-author.placeholder = "Аноним"
|
|
64
|
+
book-lang.prompt = "Выберите язык книги в формате ISO-639"
|
|
65
|
+
|
|
66
|
+
[messages.en]
|
|
67
|
+
book-name.prompt = "Enter book title"
|
|
68
|
+
book-name.placeholder = "Untitled book"
|
|
69
|
+
book-author.prompt = "Enter author name"
|
|
70
|
+
book-author.placeholder = "Anonymous"
|
|
71
|
+
book-lang.prompt = "Select book language in ISO-639 format"
|
|
72
|
+
|
|
73
|
+
[[targets]]
|
|
74
|
+
file = "/meta/book.yml"
|
|
75
|
+
format = "yaml"
|
|
76
|
+
|
|
77
|
+
[[targets.fields]]
|
|
78
|
+
field = "book-name"
|
|
79
|
+
key = "book.title"
|
|
80
|
+
|
|
81
|
+
[[targets.fields]]
|
|
82
|
+
field = "book-author"
|
|
83
|
+
key = "author[0].name"
|
|
84
|
+
|
|
85
|
+
[[targets.fields]]
|
|
86
|
+
field = "book-lang"
|
|
87
|
+
key = "property.language[ISO-639]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Built-in templates
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
### \<Book\> Typst Book Template
|
|
95
|
+
|
|
96
|
+
- **Repo:** https://github.com/DemerNkardaz/Typst-Book-Template
|
|
97
|
+
- **Name:** default
|
|
98
|
+
|
|
99
|
+
A template for creating a book using [Typst](https://typst.app/), including a prebuilt structure, plugins, styles, settings, and a build system that combines Typst and Python tools.
|
|
100
|
+
|
|
101
|
+
Requires installation of the [Typst compiler](https://github.com/typst/typst/releases) and the Python packages `pyyaml`, `pikepdf`, and `pillow`.
|
|
102
|
+
```bash
|
|
103
|
+
pip install pyyaml pikepdf pillow
|
|
104
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "yal-cmd"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Yalla Nkardaz", email = "dev_nkardaz@proton.me" }
|
|
10
|
+
]
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
description = "Yalla Nkardaz’s personal CLI toolkit"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
license = "MIT"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"requests",
|
|
17
|
+
"pyyaml",
|
|
18
|
+
"ruamel.yaml",
|
|
19
|
+
"tomli; python_version < '3.11'",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
yal = "yal.cli:main"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["."]
|
yal_cmd-0.1.0/setup.cfg
ADDED
|
File without changes
|
yal_cmd-0.1.0/yal/cli.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""yal — точка входа CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from yal.commands import create as cmd_create
|
|
9
|
+
from yal.commands import update as cmd_update
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="yal",
|
|
15
|
+
description="Yalla Nkardaz’s personal CLI toolkit",
|
|
16
|
+
)
|
|
17
|
+
sub = parser.add_subparsers(dest="command", metavar="<command>")
|
|
18
|
+
|
|
19
|
+
# ── create ───────────────────────────────────────────────────────────────
|
|
20
|
+
p_create = sub.add_parser("create", help="Create project from template")
|
|
21
|
+
p_create.add_argument(
|
|
22
|
+
"what",
|
|
23
|
+
help=(
|
|
24
|
+
"What to create. Format: <kind>[:<name>][@<ref>]\n"
|
|
25
|
+
"Example: book | book@1.7.1 | book@c651f7d | book:default@latest"
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
p_create.add_argument(
|
|
29
|
+
"-o", "--output",
|
|
30
|
+
default=".",
|
|
31
|
+
metavar="DIR",
|
|
32
|
+
help="Where to save the result (default: current directory)",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# ── update ───────────────────────────────────────────────────────────────
|
|
36
|
+
p_update = sub.add_parser("update", help="Update template")
|
|
37
|
+
p_update.add_argument(
|
|
38
|
+
"what",
|
|
39
|
+
help=(
|
|
40
|
+
"What to update. Format: <kind>[:<name>]\n"
|
|
41
|
+
"Example: book | book:default"
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return parser
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def main() -> None:
|
|
49
|
+
parser = build_parser()
|
|
50
|
+
args = parser.parse_args()
|
|
51
|
+
|
|
52
|
+
if args.command is None:
|
|
53
|
+
parser.print_help()
|
|
54
|
+
sys.exit(0)
|
|
55
|
+
|
|
56
|
+
if args.command == "create":
|
|
57
|
+
cmd_create.run(args)
|
|
58
|
+
|
|
59
|
+
if args.command == "update":
|
|
60
|
+
cmd_update.run(args)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Команда: yal create <kind>[:<name>][@<ref>]
|
|
3
|
+
|
|
4
|
+
Примеры:
|
|
5
|
+
yal create book
|
|
6
|
+
yal create book@latest
|
|
7
|
+
yal create book@1.7.1
|
|
8
|
+
yal create book@c651f7d
|
|
9
|
+
yal create book:default@1.7.1
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from yal.i18n import t
|
|
20
|
+
from yal.templates.registry import get_entry, list_kinds
|
|
21
|
+
from yal.templates.book_handler import BookHandler
|
|
22
|
+
from yal import store, template_config
|
|
23
|
+
|
|
24
|
+
_HANDLERS = {
|
|
25
|
+
"book": BookHandler(),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run(args: argparse.Namespace) -> None:
|
|
30
|
+
kind, name, ref = _parse_spec(args.what)
|
|
31
|
+
|
|
32
|
+
handler = _HANDLERS.get(kind)
|
|
33
|
+
if handler is None:
|
|
34
|
+
print(f"[yal] {t('errors.unknown-kind', kind=kind, available=', '.join(list_kinds()))}")
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
entry = get_entry(kind, name)
|
|
39
|
+
except ValueError as e:
|
|
40
|
+
print(f"[yal] {e}")
|
|
41
|
+
sys.exit(1)
|
|
42
|
+
|
|
43
|
+
output_dir = Path(args.output).resolve()
|
|
44
|
+
|
|
45
|
+
# 1. Получаем версию и загружаем конфигурацию до создания папок
|
|
46
|
+
version = handler._resolve_version(entry, name, ref)
|
|
47
|
+
src_dir = store.template_dir(kind, version)
|
|
48
|
+
config = template_config.load(src_dir)
|
|
49
|
+
|
|
50
|
+
values = {}
|
|
51
|
+
folder_name = None
|
|
52
|
+
|
|
53
|
+
# 2. Собираем значения и определяем имя папки
|
|
54
|
+
if config is not None:
|
|
55
|
+
values = template_config.collect(config)
|
|
56
|
+
folder_name = template_config.get_folder_name(config, values)
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
# 3. Создаем структуру проекта с учетом имени
|
|
60
|
+
result = handler.create(
|
|
61
|
+
entry=entry,
|
|
62
|
+
name=name,
|
|
63
|
+
output_dir=output_dir,
|
|
64
|
+
ref=ref,
|
|
65
|
+
custom_folder_name=folder_name
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# 4. Применяем настройки (запись значений в файлы)
|
|
69
|
+
if config is not None:
|
|
70
|
+
template_config.apply(config, values, result.dest)
|
|
71
|
+
else:
|
|
72
|
+
print(f"[yal] {t('config.no-config')}")
|
|
73
|
+
|
|
74
|
+
print(f"[yal] {t('create.created', path=result.dest)}")
|
|
75
|
+
|
|
76
|
+
except (ValueError, RuntimeError) as e:
|
|
77
|
+
print(f"[yal] {t('create.error', error=e)}")
|
|
78
|
+
sys.exit(1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _parse_spec(spec: str) -> tuple[str, str, str | None]:
|
|
82
|
+
pattern = r"^(?P<kind>[^:@]+)(?::(?P<name>[^@]+))?(?:@(?P<ref>.+))?$"
|
|
83
|
+
m = re.match(pattern, spec.strip())
|
|
84
|
+
if not m:
|
|
85
|
+
print(f"[yal] {t('errors.parse-spec', spec=spec)}")
|
|
86
|
+
print(f" {t('errors.parse-spec-hint', fmt='<kind>[:<name>][@<ref>]')}")
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
kind = m.group("kind").lower()
|
|
90
|
+
name = (m.group("name") or "default").lower()
|
|
91
|
+
ref = m.group("ref") or None
|
|
92
|
+
return kind, name, ref
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Команда: yal update <kind>[:<name>]
|
|
3
|
+
|
|
4
|
+
Примеры:
|
|
5
|
+
yal update book
|
|
6
|
+
yal update book:default
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import re
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from yal import github, store
|
|
16
|
+
from yal.i18n import t
|
|
17
|
+
from yal.templates.registry import get_entry, list_kinds
|
|
18
|
+
from yal.templates.book_handler import BookHandler, _confirm_download, _fetch_releases_safe
|
|
19
|
+
|
|
20
|
+
_HANDLERS = {
|
|
21
|
+
"book": BookHandler(),
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run(args: argparse.Namespace) -> None:
|
|
26
|
+
kind, name = _parse_spec(args.what)
|
|
27
|
+
|
|
28
|
+
if kind not in _HANDLERS:
|
|
29
|
+
print(f"[yal] {t('errors.unknown-kind', kind=kind, available=', '.join(list_kinds()))}")
|
|
30
|
+
sys.exit(1)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
entry = get_entry(kind, name)
|
|
34
|
+
except ValueError as e:
|
|
35
|
+
print(f"[yal] {e}")
|
|
36
|
+
sys.exit(1)
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
_update(kind, name, entry)
|
|
40
|
+
except (ValueError, RuntimeError) as e:
|
|
41
|
+
print(f"[yal] {t('create.error', error=e)}")
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _update(kind: str, name: str, entry) -> None:
|
|
46
|
+
releases = _fetch_releases_safe(entry.repo)
|
|
47
|
+
if releases:
|
|
48
|
+
_update_release(kind, name, entry, releases)
|
|
49
|
+
else:
|
|
50
|
+
_update_commit(kind, name, entry)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _update_release(
|
|
54
|
+
kind: str,
|
|
55
|
+
name: str,
|
|
56
|
+
entry,
|
|
57
|
+
releases: list[github.ReleaseInfo],
|
|
58
|
+
) -> None:
|
|
59
|
+
latest = releases[0]
|
|
60
|
+
version = latest.tag.lstrip("vV")
|
|
61
|
+
|
|
62
|
+
if store.is_installed(kind, version):
|
|
63
|
+
print(f"[yal] {t('update.already-latest', version=version)}")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
local = store.latest_release_version(kind)
|
|
67
|
+
if local:
|
|
68
|
+
print(f"[yal] {t('update.upgrading', kind=kind, name=name, old=local, new=version)}")
|
|
69
|
+
else:
|
|
70
|
+
print(f"[yal] {t('update.installing', kind=kind, name=name, version=version)}")
|
|
71
|
+
|
|
72
|
+
if not _confirm_download(kind, name, version, t("download.release"), entry.repo):
|
|
73
|
+
raise RuntimeError(t("errors.cancelled", action=t("update.action")))
|
|
74
|
+
|
|
75
|
+
dest = store.template_dir(kind, version)
|
|
76
|
+
print(f"[yal] {t('download.release-downloading', tag=latest.tag)}")
|
|
77
|
+
github.download_release(latest, dest)
|
|
78
|
+
store.save_meta(kind, version, "release", entry.repo)
|
|
79
|
+
print(f"[yal] {t('update.installed', path=dest)}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _update_commit(kind: str, name: str, entry) -> None:
|
|
83
|
+
try:
|
|
84
|
+
info = github.get_latest_commit(entry.repo)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise RuntimeError(t("update.commit-fail", error=e)) from e
|
|
87
|
+
|
|
88
|
+
version = info.sha7
|
|
89
|
+
|
|
90
|
+
if store.is_installed(kind, version):
|
|
91
|
+
print(f"[yal] {t('update.already-latest-commit', version=version)}")
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
local_versions = store.installed_versions(kind)
|
|
95
|
+
if local_versions:
|
|
96
|
+
print(f"[yal] {t('update.upgrading-commit', kind=kind, name=name, old=local_versions[-1], new=version)}")
|
|
97
|
+
else:
|
|
98
|
+
print(f"[yal] {t('update.installing-commit', kind=kind, name=name, version=version)}")
|
|
99
|
+
|
|
100
|
+
if not _confirm_download(kind, name, version, t("download.commit"), entry.repo):
|
|
101
|
+
raise RuntimeError(t("errors.cancelled", action=t("update.action")))
|
|
102
|
+
|
|
103
|
+
dest = store.template_dir(kind, version)
|
|
104
|
+
print(f"[yal] {t('download.commit-cloning', version=version)}")
|
|
105
|
+
github.clone_repo(entry.repo, dest, ref=info.sha)
|
|
106
|
+
store.save_meta(kind, version, "commit", entry.repo)
|
|
107
|
+
print(f"[yal] {t('update.installed', path=dest)}")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _parse_spec(spec: str) -> tuple[str, str]:
|
|
111
|
+
m = re.match(r"^(?P<kind>[^:@]+)(?::(?P<name>[^@]+))?$", spec.strip())
|
|
112
|
+
if not m:
|
|
113
|
+
print(f"[yal] {t('errors.parse-spec', spec=spec)}")
|
|
114
|
+
print(f" {t('errors.parse-spec-hint', fmt='<kind>[:<name>]')}")
|
|
115
|
+
sys.exit(1)
|
|
116
|
+
|
|
117
|
+
kind = m.group("kind").lower()
|
|
118
|
+
name = (m.group("name") or "default").lower()
|
|
119
|
+
return kind, name
|