elemctl 0.43.0__tar.gz → 0.43.2__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.
- {elemctl-0.43.0 → elemctl-0.43.2}/PKG-INFO +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/README.md +1 -1
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/SPEC.md +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/SPEC.ru.md +3 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/changelog.md +16 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/changelog.ru.md +17 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/config.md +1 -1
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/config.ru.md +1 -1
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/__init__.py +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/build.py +14 -14
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/cli.py +29 -29
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/client.py +27 -27
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/config.py +8 -6
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/deploy.py +12 -12
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/errors.py +1 -1
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/i18n.py +12 -8
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/mcp_server.py +82 -82
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/plugins.py +18 -18
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/probe.py +14 -14
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/selfupdate.py +4 -3
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/transport.py +9 -9
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/versions.py +1 -1
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/PKG-INFO +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_build.py +8 -8
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_cli.py +43 -28
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_cli_docs.py +3 -3
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_client.py +10 -10
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_config.py +18 -3
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_deploy.py +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_i18n.py +6 -6
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_mcp.py +37 -37
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_plugins.py +4 -4
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_probe.py +4 -4
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_selfupdate.py +51 -7
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_transport.py +4 -4
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_user_lists.py +8 -8
- {elemctl-0.43.0 → elemctl-0.43.2}/tools/extract_adapter.py +2 -2
- {elemctl-0.43.0 → elemctl-0.43.2}/.env.example +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/LICENSE +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/MANIFEST.in +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/NOTICE +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/ORIGIN.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/cli.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/cli.ru.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/index.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/index.ru.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/library.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/library.ru.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/mcp.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/mcp.ru.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/platform.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/docs/platform.ru.md +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/pyproject.toml +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/setup.cfg +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/__main__.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/auth.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl/schema.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/SOURCES.txt +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/dependency_links.txt +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/entry_points.txt +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/requires.txt +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/src/elemctl.egg-info/top_level.txt +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_changelog_link.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_conventions.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_docs_coverage.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_extract_adapter.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_rebuild_docs.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_release_notes.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_schema.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_versions.py +0 -0
- {elemctl-0.43.0 → elemctl-0.43.2}/tests/test_workflows.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elemctl
|
|
3
|
-
Version: 0.43.
|
|
3
|
+
Version: 0.43.2
|
|
4
4
|
Summary: CLI, MCP server and library for the Console API v2 of the 1C:Enterprise.Element platform (1cmycloud): applications, builds from source, one-command deploy with verification, a compile probe
|
|
5
5
|
Author: KeyFire
|
|
6
6
|
License-Expression: MIT
|
|
@@ -98,7 +98,7 @@ elemctl takes the connection credentials from environment variables or from a `.
|
|
|
98
98
|
|
|
99
99
|
| Variable | Purpose |
|
|
100
100
|
|---|---|
|
|
101
|
-
| `ELEMENT_BASE_URL` | the platform base URL
|
|
101
|
+
| `ELEMENT_BASE_URL` | the platform base URL starting with `http://` or `https://`, e.g. `https://1cmycloud.com` |
|
|
102
102
|
| `ELEMENT_CLIENT_ID` | Client-Id used to obtain a token |
|
|
103
103
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret |
|
|
104
104
|
| `ELEMENT_APP_ID` | default application (optional) |
|
|
@@ -66,7 +66,7 @@ elemctl takes the connection credentials from environment variables or from a `.
|
|
|
66
66
|
|
|
67
67
|
| Variable | Purpose |
|
|
68
68
|
|---|---|
|
|
69
|
-
| `ELEMENT_BASE_URL` | the platform base URL
|
|
69
|
+
| `ELEMENT_BASE_URL` | the platform base URL starting with `http://` or `https://`, e.g. `https://1cmycloud.com` |
|
|
70
70
|
| `ELEMENT_CLIENT_ID` | Client-Id used to obtain a token |
|
|
71
71
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret |
|
|
72
72
|
| `ELEMENT_APP_ID` | default application (optional) |
|
|
@@ -26,7 +26,7 @@ Environment variables:
|
|
|
26
26
|
|
|
27
27
|
| Variable | Meaning | Required |
|
|
28
28
|
|---|---|---|
|
|
29
|
-
| `ELEMENT_BASE_URL` | platform base URL
|
|
29
|
+
| `ELEMENT_BASE_URL` | platform base URL starting with `http://` or `https://`, e.g. `https://1cmycloud.com` | yes |
|
|
30
30
|
| `ELEMENT_CLIENT_ID` | Client-Id for obtaining the token | yes |
|
|
31
31
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret | yes |
|
|
32
32
|
| `ELEMENT_APP_ID` | default application | no |
|
|
@@ -36,7 +36,7 @@ Environment variables:
|
|
|
36
36
|
| `ELEMENT_TLS_STRICT` | strict RFC 5280 certificate checks; `true` by default | no |
|
|
37
37
|
| `ELEMENT_TLS_VERIFY` | certificate and hostname verification; `true` by default | no |
|
|
38
38
|
|
|
39
|
-
.env format: `KEY=VALUE` lines. Empty lines and lines starting with `#` are skipped. A leading `export ` prefix is allowed, and the value may be wrapped in single or double quotes. The encoding is UTF-8 and a BOM is possible, so read the file as `utf-8-sig`. A trailing slash in `ELEMENT_BASE_URL` is trimmed.
|
|
39
|
+
.env format: `KEY=VALUE` lines. Empty lines and lines starting with `#` are skipped. A leading `export ` prefix is allowed, and the value may be wrapped in single or double quotes. The encoding is UTF-8 and a BOM is possible, so read the file as `utf-8-sig`. A trailing slash in `ELEMENT_BASE_URL` is trimmed. A nonempty base URL must start with `http://` or `https://`.
|
|
40
40
|
|
|
41
41
|
## 3. Authentication
|
|
42
42
|
|
|
@@ -37,7 +37,7 @@ README.md, .env.example и .gitignore заданы и не меняются.
|
|
|
37
37
|
|
|
38
38
|
| Переменная | Смысл | Обязательна |
|
|
39
39
|
|---|---|---|
|
|
40
|
-
| `ELEMENT_BASE_URL` | базовый URL
|
|
40
|
+
| `ELEMENT_BASE_URL` | базовый URL платформы с `http://` или `https://`, например `https://1cmycloud.com` | да |
|
|
41
41
|
| `ELEMENT_CLIENT_ID` | Client-Id для получения токена | да |
|
|
42
42
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret | да |
|
|
43
43
|
| `ELEMENT_APP_ID` | приложение по умолчанию | нет |
|
|
@@ -50,7 +50,8 @@ README.md, .env.example и .gitignore заданы и не меняются.
|
|
|
50
50
|
Формат .env: строки `KEY=VALUE`. Пустые строки и строки, начинающиеся с `#`,
|
|
51
51
|
пропускаются. Перед именем допускается префикс `export `, а значение можно взять
|
|
52
52
|
в одинарные или двойные кавычки. Кодировка UTF-8, возможен BOM, поэтому читать
|
|
53
|
-
надо как `utf-8-sig`. Хвостовой слэш у `ELEMENT_BASE_URL` обрезается.
|
|
53
|
+
надо как `utf-8-sig`. Хвостовой слэш у `ELEMENT_BASE_URL` обрезается. Непустой базовый URL
|
|
54
|
+
должен начинаться с `http://` или `https://`.
|
|
54
55
|
|
|
55
56
|
## 3. Аутентификация
|
|
56
57
|
|
|
@@ -21,6 +21,22 @@ entry either – say what the behaviour was, not which id or response field was
|
|
|
21
21
|
The link is written by `python scripts/changelog-link.py <number>`, which rebuilds the generated
|
|
22
22
|
pages of the site in the same run – writing it by hand is how the mirrors get left behind.
|
|
23
23
|
|
|
24
|
+
## 2026-09-23 – 0.43.2
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- Python comments and docstrings consistently use hyphens. Ordinary string literals remain unchanged.
|
|
28
|
+
([#40](https://github.com/keyfire/elemctl/pull/40))
|
|
29
|
+
|
|
30
|
+
## 2026-09-22 – 0.43.1
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- **`self-update` reports an incomplete PyPI response without touching the installed package.**
|
|
34
|
+
The simple index, metadata and wheel downloads missed HTTP parser failures, so an interrupted
|
|
35
|
+
response could end in a traceback. ([#38](https://github.com/keyfire/elemctl/pull/38))
|
|
36
|
+
- **Connection setup rejects a base URL without an HTTP scheme.** An address without `http://`
|
|
37
|
+
or `https://` used to reach `urllib` and fail with a raw `ValueError`.
|
|
38
|
+
([#38](https://github.com/keyfire/elemctl/pull/38))
|
|
39
|
+
|
|
24
40
|
## 2026-09-19 – 0.43.0
|
|
25
41
|
|
|
26
42
|
### Added
|
|
@@ -21,6 +21,23 @@ sidebar:
|
|
|
21
21
|
Ссылку пишет `python scripts/changelog-link.py <номер>` – он же тут же пересобирает
|
|
22
22
|
сгенерированные страницы сайта: правка руками как раз и оставляет зеркала позади.
|
|
23
23
|
|
|
24
|
+
## 23.09.2026 – 0.43.2
|
|
25
|
+
|
|
26
|
+
### Изменено
|
|
27
|
+
- В комментариях и документирующих строках Python используется обычный дефис. Остальные строковые литералы сохранены.
|
|
28
|
+
([#40](https://github.com/keyfire/elemctl/pull/40))
|
|
29
|
+
|
|
30
|
+
## 22.09.2026 – 0.43.1
|
|
31
|
+
|
|
32
|
+
### Исправлено
|
|
33
|
+
- **`self-update` сообщает об оборванном ответе PyPI и не затрагивает установленный пакет.**
|
|
34
|
+
Чтение индекса Simple, метаданных и колеса не ловило ошибки синтаксического анализатора HTTP,
|
|
35
|
+
поэтому оборванный ответ мог закончиться трассировкой.
|
|
36
|
+
([#38](https://github.com/keyfire/elemctl/pull/38))
|
|
37
|
+
- **Настройка подключения отказывает базовому URL без схемы HTTP.** Адрес без `http://` или
|
|
38
|
+
`https://` доходил до `urllib` и заканчивался необработанным `ValueError`.
|
|
39
|
+
([#38](https://github.com/keyfire/elemctl/pull/38))
|
|
40
|
+
|
|
24
41
|
## 19.09.2026 – 0.43.0
|
|
25
42
|
|
|
26
43
|
### Добавлено
|
|
@@ -13,7 +13,7 @@ elemctl takes the connection credentials from environment variables or from a `.
|
|
|
13
13
|
|
|
14
14
|
| Variable | Purpose |
|
|
15
15
|
|---|---|
|
|
16
|
-
| `ELEMENT_BASE_URL` | the platform base URL
|
|
16
|
+
| `ELEMENT_BASE_URL` | the platform base URL starting with `http://` or `https://`, e.g. `https://1cmycloud.com` |
|
|
17
17
|
| `ELEMENT_CLIENT_ID` | Client-Id used to obtain a token |
|
|
18
18
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret |
|
|
19
19
|
| `ELEMENT_APP_ID` | default application (optional) |
|
|
@@ -14,7 +14,7 @@ sidebar:
|
|
|
14
14
|
|
|
15
15
|
| Переменная | Назначение |
|
|
16
16
|
|---|---|
|
|
17
|
-
| `ELEMENT_BASE_URL` | базовый URL
|
|
17
|
+
| `ELEMENT_BASE_URL` | базовый URL платформы с `http://` или `https://`, например `https://1cmycloud.com` |
|
|
18
18
|
| `ELEMENT_CLIENT_ID` | Client-Id для получения токена |
|
|
19
19
|
| `ELEMENT_CLIENT_SECRET` | Client-Secret |
|
|
20
20
|
| `ELEMENT_APP_ID` | приложение по умолчанию (необязательно) |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""elemctl
|
|
1
|
+
"""elemctl - a CLI, an MCP server and a library for Console API v2 of the
|
|
2
2
|
1C:Enterprise.Element platform (1cmycloud).
|
|
3
3
|
|
|
4
4
|
Public API of the library:
|
|
@@ -18,7 +18,7 @@ from .errors import (
|
|
|
18
18
|
TransportError,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
__version__ = "0.43.
|
|
21
|
+
__version__ = "0.43.2"
|
|
22
22
|
|
|
23
23
|
__all__ = [
|
|
24
24
|
"ApiError",
|
|
@@ -60,7 +60,7 @@ SOAP_CLIENT_KINDS = ("КлиентSoapСервиса", "SoapServiceClient")
|
|
|
60
60
|
# by extension.
|
|
61
61
|
RESOURCES_DIR = "Ресурсы"
|
|
62
62
|
|
|
63
|
-
# Directories excluded entirely (plus every hidden one
|
|
63
|
+
# Directories excluded entirely (plus every hidden one - starting with a dot).
|
|
64
64
|
EXCLUDED_DIRS = {".git", ".claude", ".github", "__pycache__", "node_modules", ".venv"}
|
|
65
65
|
|
|
66
66
|
# Files excluded by exact name.
|
|
@@ -69,7 +69,7 @@ EXCLUDED_FILES = {".gitignore", ".env", ".DS_Store"}
|
|
|
69
69
|
# Files excluded by extension (prebuilt build archives).
|
|
70
70
|
EXCLUDED_SUFFIXES = (".xasm", ".xlib")
|
|
71
71
|
|
|
72
|
-
# The CI environment variables carrying the run number
|
|
72
|
+
# The CI environment variables carrying the run number - the source of the build
|
|
73
73
|
# version suffix when neither an explicit version nor a last build is given: every
|
|
74
74
|
# CI run happens in a clean working directory, so local numbering would always
|
|
75
75
|
# yield "-1".
|
|
@@ -105,9 +105,9 @@ class LibraryRef:
|
|
|
105
105
|
class BuildResult:
|
|
106
106
|
"""The result of a local archive build.
|
|
107
107
|
|
|
108
|
-
version_source
|
|
108
|
+
version_source - where the build version came from: "flag" (set explicitly),
|
|
109
109
|
"last-build" (auto-increment from the last build), the name of a CI variable
|
|
110
|
-
(the run number from the environment) or "default". dirty_files
|
|
110
|
+
(the run number from the environment) or "default". dirty_files - the files
|
|
111
111
|
with uncommitted changes in the project directory; None when git is
|
|
112
112
|
unavailable or the directory is not inside a repository.
|
|
113
113
|
"""
|
|
@@ -132,7 +132,7 @@ class BuildResult:
|
|
|
132
132
|
def parse_flat_yaml(text):
|
|
133
133
|
"""Parse the flat top-level "key: value" pairs of a YAML text.
|
|
134
134
|
|
|
135
|
-
Nested lines (the indented ones), blank lines and comments are skipped
|
|
135
|
+
Nested lines (the indented ones), blank lines and comments are skipped -
|
|
136
136
|
for Проект.yaml that is enough.
|
|
137
137
|
"""
|
|
138
138
|
values = {}
|
|
@@ -334,7 +334,7 @@ def collect_project_files(project_dir):
|
|
|
334
334
|
|
|
335
335
|
Outside the resource directories an allowlist of extensions applies; inside a
|
|
336
336
|
`Ресурсы` directory (at any level, including its subdirectories) files of any
|
|
337
|
-
extension are taken
|
|
337
|
+
extension are taken - a resource may be an arbitrary file: .pdf, .htm, .mxl etc.
|
|
338
338
|
"""
|
|
339
339
|
return collect_with_skipped(project_dir)[0]
|
|
340
340
|
|
|
@@ -432,7 +432,7 @@ def _detached_branch(environ=None):
|
|
|
432
432
|
def git_metadata(project_dir, environ=None):
|
|
433
433
|
"""The commit hash and the branch name of the git repository holding the project.
|
|
434
434
|
|
|
435
|
-
When git is unavailable (no command, not a repository)
|
|
435
|
+
When git is unavailable (no command, not a repository) - empty strings.
|
|
436
436
|
|
|
437
437
|
A detached checkout is answered by the CI, not by git: `rev-parse --abbrev-ref HEAD`
|
|
438
438
|
says the literal `HEAD` there, and that is what every assembly built on a runner used
|
|
@@ -452,7 +452,7 @@ def git_dirty_files(project_dir):
|
|
|
452
452
|
|
|
453
453
|
A build captures the disk as it is at the moment it starts, so a divergence
|
|
454
454
|
from HEAD has to be visible to the caller. Returned is the list of paths from
|
|
455
|
-
git status --porcelain limited to the directory; None
|
|
455
|
+
git status --porcelain limited to the directory; None - when git is unavailable
|
|
456
456
|
or the directory is not inside a repository (as opposed to an empty list,
|
|
457
457
|
meaning "clean").
|
|
458
458
|
"""
|
|
@@ -510,8 +510,8 @@ def build_assembly(
|
|
|
510
510
|
|
|
511
511
|
The version: the explicit version, otherwise an auto-increment from
|
|
512
512
|
last_build_version, otherwise a suffix taken from the CI run number (the
|
|
513
|
-
CI_BUILD_NUMBER_VARS variables), and with none of that
|
|
514
|
-
branch and commit override the git metadata (None
|
|
513
|
+
CI_BUILD_NUMBER_VARS variables), and with none of that - "{base version}-1".
|
|
514
|
+
branch and commit override the git metadata (None - take it from git). kind
|
|
515
515
|
overrides the project kind ("application"/"library").
|
|
516
516
|
"""
|
|
517
517
|
directory = find_project_dir(project_dir) if project_dir else find_project_dir()
|
|
@@ -643,10 +643,10 @@ def read_assembly_project(path):
|
|
|
643
643
|
|
|
644
644
|
|
|
645
645
|
def inspect_assembly(path):
|
|
646
|
-
"""Inspect a prebuilt assembly archive (.xasm/.xlib)
|
|
646
|
+
"""Inspect a prebuilt assembly archive (.xasm/.xlib) - the inverse of build_assembly.
|
|
647
647
|
|
|
648
648
|
Returns the manifest, the project properties, its subsystems and the types
|
|
649
|
-
available to the project that plugged it in (ОбластьВидимости: Глобально)
|
|
649
|
+
available to the project that plugged it in (ОбластьВидимости: Глобально) -
|
|
650
650
|
with their qualified names. The namespace of a type is
|
|
651
651
|
{vendor}::{name}::{subsystem}[::{package}], where a package is a nested
|
|
652
652
|
directory of a subsystem (a package has no descriptor file of its own).
|
|
@@ -686,7 +686,7 @@ def inspect_assembly(path):
|
|
|
686
686
|
"vendor": vendor,
|
|
687
687
|
"name": name,
|
|
688
688
|
"version": manifest.get("Version", ""),
|
|
689
|
-
# There is no ВерсияТехнологии in Проект.yaml
|
|
689
|
+
# There is no ВерсияТехнологии in Проект.yaml - compatibility is set by
|
|
690
690
|
# РежимСовместимости, and it is exactly what is matched against the target project.
|
|
691
691
|
"compatibility": descriptor_value(project, "РежимСовместимости", "CompatibilityMode"),
|
|
692
692
|
"representation": descriptor_value(project, "Представление", "Presentation"),
|
|
@@ -759,7 +759,7 @@ def _archive_elements(archive, names, prefix):
|
|
|
759
759
|
|
|
760
760
|
|
|
761
761
|
def _subsystems(elements, vendor, name):
|
|
762
|
-
"""The project's subsystems and their packages
|
|
762
|
+
"""The project's subsystems and their packages - from the directory layout.
|
|
763
763
|
|
|
764
764
|
A subsystem is a first-level directory; Подсистема.yaml is optional (a library
|
|
765
765
|
may have none at all), so it cannot be relied upon.
|
|
@@ -63,7 +63,7 @@ _answer_stream = None
|
|
|
63
63
|
def _emit(data):
|
|
64
64
|
"""Print the answer and flush it immediately.
|
|
65
65
|
|
|
66
|
-
Off a terminal Python block-buffers stdout, while stderr goes through right away
|
|
66
|
+
Off a terminal Python block-buffers stdout, while stderr goes through right away - a
|
|
67
67
|
caller who merges the streams (`2>&1`, or stderr=STDOUT, a plain way to capture "everything
|
|
68
68
|
the tool printed" for a log) then saw a later _progress line overtake an _emit that ran
|
|
69
69
|
first in the source, and a parser hunting for the first brace found a summary line instead.
|
|
@@ -80,7 +80,7 @@ def _json_only():
|
|
|
80
80
|
"""--json: only the answer reaches stdout, everything else goes to stderr.
|
|
81
81
|
|
|
82
82
|
The promise is kept by the streams themselves rather than by discipline: a
|
|
83
|
-
print of a plugin command, a warning of a library, a stray debug line
|
|
83
|
+
print of a plugin command, a warning of a library, a stray debug line - all of
|
|
84
84
|
them land on stderr, because for the duration of the call sys.stdout IS stderr.
|
|
85
85
|
_emit keeps writing to the real stdout, which is remembered here.
|
|
86
86
|
"""
|
|
@@ -95,7 +95,7 @@ def _json_only():
|
|
|
95
95
|
|
|
96
96
|
def _progress(message):
|
|
97
97
|
# stderr is already line-buffered on every supported Python, so this changes nothing in
|
|
98
|
-
# practice
|
|
98
|
+
# practice - it is here so the order _emit relies on is an explicit guarantee in the code,
|
|
99
99
|
# not an assumption about the interpreter's default that the next reader has to go verify.
|
|
100
100
|
print(message, file=sys.stderr)
|
|
101
101
|
sys.stderr.flush()
|
|
@@ -108,7 +108,7 @@ def _fail(payload):
|
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
def _reconfigure_streams():
|
|
111
|
-
"""Switch the console output to UTF-8
|
|
111
|
+
"""Switch the console output to UTF-8 - otherwise Cyrillic breaks on Windows."""
|
|
112
112
|
for stream in (sys.stdout, sys.stderr):
|
|
113
113
|
reconfigure = getattr(stream, "reconfigure", None)
|
|
114
114
|
if reconfigure is not None:
|
|
@@ -169,14 +169,14 @@ def _refuse_connection_options(args, command):
|
|
|
169
169
|
|
|
170
170
|
`build` and `inspect` never reach the platform: the archive is assembled from
|
|
171
171
|
the sources on disk, and no version number is reserved on the server. The
|
|
172
|
-
options used to be accepted and quietly dropped
|
|
172
|
+
options used to be accepted and quietly dropped - and a call that carries
|
|
173
173
|
`--env-file` LOOKS like a build bound to a stand, which twice left the reader
|
|
174
174
|
asking whether the build talks to the server after all.
|
|
175
175
|
|
|
176
176
|
A refusal rather than a warning, for three reasons. Nothing stops working:
|
|
177
177
|
the options changed nothing, so the only calls it breaks are the ones that
|
|
178
178
|
already meant something else. A warning would land on stderr, next to the
|
|
179
|
-
progress lines, where a CI log buries it
|
|
179
|
+
progress lines, where a CI log buries it - and silence of exactly that kind is
|
|
180
180
|
what caused the doubt. And the refusal answers the question the caller really
|
|
181
181
|
had: it says outright that a local build does not go to the platform, and
|
|
182
182
|
names the commands that do.
|
|
@@ -262,7 +262,7 @@ def cmd_apps_find(args):
|
|
|
262
262
|
|
|
263
263
|
The exit code is 0 in both cases: the found field carries the verdict. A non-zero exit
|
|
264
264
|
code means the request itself failed (no access, network, configuration) and comes with
|
|
265
|
-
JSON carrying an error field on stderr
|
|
265
|
+
JSON carrying an error field on stderr - otherwise the caller cannot tell "there is no
|
|
266
266
|
stand" from "we failed to ask".
|
|
267
267
|
|
|
268
268
|
Deleted applications (status Deleted) are skipped by default, so that the id found is fit
|
|
@@ -401,7 +401,7 @@ def _report_sign_in(card):
|
|
|
401
401
|
A stand nobody can get into is not a ready stand, and the way in is not
|
|
402
402
|
guessable: the accounts used elsewhere do not work in a fresh application
|
|
403
403
|
(client.sign_in_hint). The text goes to stderr, where the rest
|
|
404
|
-
of the progress goes, and the machine-readable twin goes into the JSON
|
|
404
|
+
of the progress goes, and the machine-readable twin goes into the JSON - an
|
|
405
405
|
agent reading only stdout must learn it too.
|
|
406
406
|
"""
|
|
407
407
|
hint = sign_in_hint(card)
|
|
@@ -500,8 +500,8 @@ def cmd_apps_ensure(args):
|
|
|
500
500
|
"""Idempotently bring an application with the given name into existence.
|
|
501
501
|
|
|
502
502
|
It looks the application up by the rules of apps find (deleted ones, in
|
|
503
|
-
status Deleted, do not count): if it is already there
|
|
504
|
-
returns created: false; if it is not
|
|
503
|
+
status Deleted, do not count): if it is already there - it does nothing and
|
|
504
|
+
returns created: false; if it is not - it creates one from the creation flags
|
|
505
505
|
and returns created: true. An existing application is never re-created:
|
|
506
506
|
delete + create give a new URL and break the external links to the previous
|
|
507
507
|
one. The exit code is 0 in both cases; a failed request is JSON with an error
|
|
@@ -690,9 +690,9 @@ def cmd_builds_list(args):
|
|
|
690
690
|
|
|
691
691
|
Neither cut is silent, and there are two of them. The tool's own is the limit.
|
|
692
692
|
The platform's is its housekeeping: it deletes the builds nobody uses, whatever
|
|
693
|
-
their age, so a listing is not the project's history
|
|
693
|
+
their age, so a listing is not the project's history - it is what survived. The
|
|
694
694
|
count line says which of the two the reader is looking at (builds_summary reads
|
|
695
|
-
that off the gaps in the build numbering), and it is printed always
|
|
695
|
+
that off the gaps in the build numbering), and it is printed always - after the
|
|
696
696
|
answer, the same order apps list uses: a listing without it was read as "the
|
|
697
697
|
project has exactly these builds", and a caller capturing the two streams as one
|
|
698
698
|
must still find the answer first.
|
|
@@ -707,7 +707,7 @@ def cmd_builds_list(args):
|
|
|
707
707
|
truncated = args.limit > 0 and len(assemblies) > args.limit
|
|
708
708
|
if truncated:
|
|
709
709
|
shown = assemblies[: args.limit]
|
|
710
|
-
# Counted before --brief reshapes the cards: the whole answer, not the cut one
|
|
710
|
+
# Counted before --brief reshapes the cards: the whole answer, not the cut one -
|
|
711
711
|
# what the platform left out is judged by the numbering of everything it did
|
|
712
712
|
# return, and the count of a card does not change when its fields do.
|
|
713
713
|
shown_count = len(shown)
|
|
@@ -733,8 +733,8 @@ def cmd_builds_get(args):
|
|
|
733
733
|
def _upload_target(args, config):
|
|
734
734
|
"""The target project of the upload and the source of that choice.
|
|
735
735
|
|
|
736
|
-
The sources: "flag"
|
|
737
|
-
the environment or the .env file, None
|
|
736
|
+
The sources: "flag" - the --project-id flag, "env" - ELEMENT_PROJECT_ID from
|
|
737
|
+
the environment or the .env file, None - no project is set, the platform will
|
|
738
738
|
create a new one. The --new-project flag switches the binding from the
|
|
739
739
|
environment off; together with --project-id it is contradictory, which is a
|
|
740
740
|
call error.
|
|
@@ -950,7 +950,7 @@ def _user_list_id(client, args):
|
|
|
950
950
|
"""The id of the target user list: from the argument or from the application.
|
|
951
951
|
|
|
952
952
|
Exactly one of the two is expected. --app takes the application's own list
|
|
953
|
-
(default-user-list of its card)
|
|
953
|
+
(default-user-list of its card) - that is the everyday case: the settings of
|
|
954
954
|
the checklist are made on the list of a particular application, and its
|
|
955
955
|
presentation is named after the application anyway.
|
|
956
956
|
"""
|
|
@@ -1026,8 +1026,8 @@ def _calculation_rules(args):
|
|
|
1026
1026
|
def cmd_user_lists_calculation_rules(args):
|
|
1027
1027
|
"""The rules that build a user from the provider's answer: show the target or write them.
|
|
1028
1028
|
|
|
1029
|
-
Without values the command does not pretend to show the rules
|
|
1030
|
-
return them
|
|
1029
|
+
Without values the command does not pretend to show the rules - the platform does not
|
|
1030
|
+
return them - it names the service they would go to and says why there is nothing to
|
|
1031
1031
|
show. Writing reports honestly what was confirmed and what could not be.
|
|
1032
1032
|
"""
|
|
1033
1033
|
client = make_client(_config(args))
|
|
@@ -1061,7 +1061,7 @@ def cmd_user_lists_calculation_rules(args):
|
|
|
1061
1061
|
|
|
1062
1062
|
|
|
1063
1063
|
def cmd_user_lists_password_login(args):
|
|
1064
|
-
"""Signing in with a login and a password
|
|
1064
|
+
"""Signing in with a login and a password - the account service of type Local.
|
|
1065
1065
|
|
|
1066
1066
|
Without a flag the command answers with the current state; the answer says
|
|
1067
1067
|
`enabled: null` when the list has no such service at all (nothing to sign in
|
|
@@ -1209,7 +1209,7 @@ def cmd_tech_set(args):
|
|
|
1209
1209
|
def cmd_debug_adapter(args):
|
|
1210
1210
|
"""The path to the platform debug adapter directory brought by the plugin.
|
|
1211
1211
|
|
|
1212
|
-
The directory holds a repo/ subdirectory with the jar files of the adapter
|
|
1212
|
+
The directory holds a repo/ subdirectory with the jar files of the adapter - that is
|
|
1213
1213
|
the ready value of the xbsl.debug.adapterPath setting for the VS Code extension. A
|
|
1214
1214
|
missing plugin is an answer (found: false, code 0), not an error: a non-zero code
|
|
1215
1215
|
would mean a failure.
|
|
@@ -1223,10 +1223,10 @@ def cmd_debug_adapter(args):
|
|
|
1223
1223
|
|
|
1224
1224
|
|
|
1225
1225
|
def cmd_plugins(args):
|
|
1226
|
-
"""Plugin diagnostics: what the plugins bring
|
|
1226
|
+
"""Plugin diagnostics: what the plugins bring - adapter directories and commands.
|
|
1227
1227
|
|
|
1228
1228
|
The adapter directories are listed jar-less ones included (that is exactly
|
|
1229
|
-
what a diagnostic is for), the commands
|
|
1229
|
+
what a diagnostic is for), the commands - with the entry point they arrived
|
|
1230
1230
|
through and whether they are exposed to MCP. The failures name the plugins
|
|
1231
1231
|
left out and the reason: a plugin that did not load, or a command that would
|
|
1232
1232
|
have taken over a name of the core.
|
|
@@ -1271,15 +1271,15 @@ def cmd_mcp(args):
|
|
|
1271
1271
|
from . import mcp_server
|
|
1272
1272
|
except ImportError:
|
|
1273
1273
|
raise ElemctlError(i18n.t("cli.mcp-extra-required"))
|
|
1274
|
-
# A bad --env-file still fails right here, before the server starts
|
|
1274
|
+
# A bad --env-file still fails right here, before the server starts - the same check
|
|
1275
1275
|
# Config.from_env would raise on the first call, just not deferred to it: a typo in a
|
|
1276
1276
|
# path given explicitly on this command line is worth knowing about immediately, not
|
|
1277
1277
|
# minutes into a session. Other default-stand configuration problems (a bad
|
|
1278
1278
|
# ELEMENT_TLS_VERIFY, credentials missing entirely) are NOT resolved here on purpose: not
|
|
1279
1279
|
# _config(args), which used to build a whole Config up front and hand it to mcp_server as
|
|
1280
|
-
# a ready object
|
|
1280
|
+
# a ready object - that pinned it for the life of the process, so the default stand's
|
|
1281
1281
|
# .env, edited after the server started, was never re-read. Only the genuine overrides
|
|
1282
|
-
# (the flags actually given
|
|
1282
|
+
# (the flags actually given - base URL, client id and the rest) and --env-file, if any,
|
|
1283
1283
|
# are passed instead; every call still without its own env_file rebuilds from the file on
|
|
1284
1284
|
# an edit, the overrides applied on top each time.
|
|
1285
1285
|
if args.env_file:
|
|
@@ -1348,7 +1348,7 @@ class _AliasedPositional(argparse.Action):
|
|
|
1348
1348
|
|
|
1349
1349
|
argparse hands an optional positional its own default when the command line carried
|
|
1350
1350
|
none, and that default would land on the dest the key form had just filled. Here the
|
|
1351
|
-
default is _MISSING, and seeing it means write nothing at all
|
|
1351
|
+
default is _MISSING, and seeing it means write nothing at all - the dest keeps what
|
|
1352
1352
|
the key form put there, or stays out of the namespace when neither form was given.
|
|
1353
1353
|
"""
|
|
1354
1354
|
|
|
@@ -1363,7 +1363,7 @@ class _AliasedPositional(argparse.Action):
|
|
|
1363
1363
|
def _add_aliased_positional(parser, argument):
|
|
1364
1364
|
"""A positional plugin argument and its CLI-only key synonym (Argument.cli_alias).
|
|
1365
1365
|
|
|
1366
|
-
The MCP tool keeps the one parameter it always had (see mcp_server._plugin_tool)
|
|
1366
|
+
The MCP tool keeps the one parameter it always had (see mcp_server._plugin_tool) -
|
|
1367
1367
|
the alias changes what THIS parser accepts, nothing about the declared arguments.
|
|
1368
1368
|
A mutually exclusive group lets either form fill the same dest: both at once is a
|
|
1369
1369
|
parser refusal ("not allowed with argument ..."), and required carries over to the
|
|
@@ -1371,7 +1371,7 @@ def _add_aliased_positional(parser, argument):
|
|
|
1371
1371
|
|
|
1372
1372
|
Neither half writes a default: an option left at its own implicit default of None
|
|
1373
1373
|
would win the namespace the moment the parser builds it (the option is added second,
|
|
1374
|
-
and it is not the positional's nargs="?" default that argparse falls back to first)
|
|
1374
|
+
and it is not the positional's nargs="?" default that argparse falls back to first) -
|
|
1375
1375
|
silently overriding a non-None default the plugin declared. With both halves quiet the
|
|
1376
1376
|
dest stays out of the namespace whenever neither form is given, and _plugin_handler
|
|
1377
1377
|
already falls back to Argument.value_default for exactly that case, the same way it
|
|
@@ -1612,7 +1612,7 @@ def build_parser():
|
|
|
1612
1612
|
version=f"elemctl {__version__}")
|
|
1613
1613
|
|
|
1614
1614
|
# title= renders the list under a "commands:" heading instead of argparse's default
|
|
1615
|
-
# "positional arguments: command"
|
|
1615
|
+
# "positional arguments: command" - the same heading the sibling tools use.
|
|
1616
1616
|
sub = parser.add_subparsers(
|
|
1617
1617
|
dest="command",
|
|
1618
1618
|
metavar=i18n.t("cli.help.command-metavar"),
|