RFC-014: Проект системы управления пакетами (общий документ)
Подчиненные RFC:
Резюме
Проектирование системы управления пакетами языка YaoXiang с поддержкой семантического версионирования, локальных зависимостей и зависимостей из GitHub, унифицированного синтаксиса импорта, файла конфигурации yaoxiang.toml и файла блокировки yaoxiang.lock.
Мотивация
Зачем нужна эта функциональность/изменение?
Управление пакетами — базовая инфраструктура экосистемы современного языка программирования. В настоящее время в языке YaoXiang отсутствуют:
- механизм объявления зависимостей
- возможности управления версиями
- стандартные каналы распространения
Текущая проблема
my-project/
├── src/
│ └── main.yx # код зависит от других модулей
├── lib/ # модули, скопированные вручную
│ ├── foo.yx
│ └── bar.yx
└── ??? # нет стандартного управления зависимостямиПредложение
Основной проект
Многоуровневая архитектура:
┌─────────────────────────────────────────────┐
│ Resolution Engine │ ← разрешение зависимостей
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Global Cache │ ← ~/.yaoxiang/cache/
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Source Trait │ ← расширяемые источники
├──────────┬──────────┬──────────┬────────────┤
│ Local │ Git │ Registry │ GitHub │
│ (локал.) │ (VCS) │ (открыт.)│ (Release) │
└──────────┴──────────┴──────────┴────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Vendor Directory │ ← .yaoxiang/vendor/
└─────────────────────────────────────────────┘Механизм расширения: для добавления нового типа Source достаточно реализовать trait, без изменения движка разрешения.
Пример
# 1. Создание проекта
yaoxiang init my-project
# 2. Редактирование yaoxiang.toml для добавления зависимостей
[dependencies]
foo = "^1.0.0"
bar = { git = "https://github.com/user/bar", version = "0.5.0" }
# 3. Установка зависимостей
yaoxiang add foo
# 4. Использование в коде
use foo;
use bar.baz;Структура проекта
my-project/
├── yaoxiang.toml # конфигурация пакета
├── yaoxiang.lock # файл блокировки (генерируется автоматически)
├── src/
│ └── main.yx
└── .yaoxiang/
└── vendor/ # локальные зависимости
├── foo-1.2.3/
└── bar-0.5.0/Детальный проект
Формат конфигурационного файла
yaoxiang.toml:
[package]
name = "my-package"
version = "0.1.0"
description = "A short description"
license = "MIT"
authors = ["Your Name <you@example.com>"]
repository = "https://github.com/you/my-package"
keywords = ["cli", "utility"]
[dependencies]
foo = "1.2.3" # точная версия
bar = "^1.0.0" # совместимая версия
baz = "~1.2.0" # версия с патчами
qux = { git = "...", version = "0.5.0" }
local_pkg = { path = "./local-module" }
[dev-dependencies]
test-utils = "0.1.0"
[build]
strategy = "none" # none | cargo | cmake | custom
[binaries]
"linux-x86_64" = { url = "...", sha256 = "..." }
[workspace.members] # только корень рабочего пространства
core = "packages/core/yaoxiang.toml"yaoxiang.lock:
version = 1
[[package]]
name = "foo"
version = "1.2.3"
source = "git"
resolved = "https://github.com/user/foo?tag=v1.2.3"
integrity = "sha256-xxxx"Порядок разрешения модулей
Решение от 2026-09-15: взаимоисключающая семантика основных источников пакетов (по типу Python venv / Node node_modules). Устаревшее описание «5-уровневой сквозной цепочки поиска» — либо vendor, либо глобальный кэш выступает единственным основным источником пакетов, std встроен в основной источник, локальные модули могут перекрывать всё остальное.
Определение основного источника пакетов (взаимоисключающее, никогда не смешивается):
- Если в проекте существует
.yaoxiang/vendor/→ vendor является единственным основным источником пакетов. Всеuseне-локальных модулей разрешаются только из vendor, отсутствие пакета в vendor приводит к ошибке (с подсказкойyaoxiang install), глобальный откат не выполняется. - Иначе → глобальный кэш является основным источником пакетов (директория установки std + глобальный кэш).
Не существует «по-пакетного проникновения» вида «если в vendor нет, откатываемся к глобальному кэшу» — смешивание двух источников и есть корень дрейфа версий и проблемы «у меня на машине работает».
Проектный режим (с yaoxiang.toml)
use foo.bar.baz;
Порядок поиска:
1. ./src/foo/bar/baz.yx локальный модуль — наивысший приоритет, может перекрывать одноимённый модуль в основном источнике
2. <основной источник>/foo/bar/baz.yx
· режим vendor: .yaoxiang/vendor/<pkg>-<ver>/src/foo/bar/baz.yx (std также находится в vendor)
· глобальный режим: <install-dir>/yx/<ver>/std/foo/bar/baz.yx + ~/.yaoxiang/cache/...
3. Специальный резерв для std.*: встроенный бинарный (только пространство имён std.*; переходный слой до появления файловой системы std, версия привязана к компилятору)
4. Ошибка (модуль не существует); в режиме vendor при отсутствии пакета — подсказка `yaoxiang install`Правила проектного режима:
yaoxiang add std@1.0.1устанавливает std как обычную зависимость в vendor и фиксирует версию; в этом случае встроенный бинарный std более не действует (std из vendor имеет приоритет)- При наличии vendor, несовместимого с
yaoxiang.lock, командыrun/buildвозвращают ошибку с подсказкойyaoxiang install(семантика Node: без автоматической тихой установки) - При перекрытии локальным модулем одноимённого модуля в основном источнике по умолчанию выдаётся диагностическое сообщение уровня W о затенении (
--deny-shadowingповышает до ошибки); при перекрытииstd.*текст диагностики явно предупреждает - Зависимость
pathрассматривается как расширение локального модуля и разрешается напрямую по пути, минуя основной источник пакетов
Режим одиночного файла (без yaoxiang.toml)
use foo.bar.baz;
Порядок поиска:
1. ./src/foo/bar/baz.yx локальный модуль
2. Глобальный основной источник: <install-dir>/yx/<version>/std/foo/bar/baz.yx
3. Резерв встроенного бинарного std
4. $YXPATH/foo/bar/baz.yx (глобальный путь, зарезервировано)Правила режима одиночного файла:
- Понятие проектных зависимостей отсутствует, std берётся напрямую из глобального; путь глобальной стандартной библиотеки привязан к версии компилятора:
<install-dir>/yx/<version>/std/ - В режиме одиночного файла
.yaoxiang/никогда не читается (понятие vendor отсутствует)
Структура каталога установки стандартной библиотеки
Глобальная стандартная библиотека
<yaoxiang-install-dir>/
├── yx/ # каталог языка YaoXiang
│ ├── 1.0.1/ # каталог версии
│ │ ├── std/
│ │ │ ├── test.yx # модуль чистой стандартной библиотеки YaoXiang
│ │ │ ├── math.yx # будущий самодостаточный модуль
│ │ │ └── ...
│ │ └── ...
│ └── 1.1.0/
│ └── std/
│ └── ...
└── bin/
└── yaoxiang # бинарный файл компилятораПроектная стандартная библиотека
Решение от 2026-09-15: отдельный каталог
.yaoxiang/std/более не создаётся. std — обычный пакет в основном источнике: послеyaoxiang add std@1.0.1он попадает в.yaoxiang/vendor/std-<version>/и управляется по тем же правилам, что и другие зависимости. Прежнее правило «при наличии проектного std глобальный std не действует» больше не требуется — взаимоисключающая природа основного источника пакетов гарантирует это естественным образом.
my-project/
├── yaoxiang.toml
├── yaoxiang.lock
├── .yaoxiang/
│ └── vendor/
│ ├── std-1.0.1/ # std как обычный пакет в vendor
│ └── foo-1.2.3/
├── src/
│ └── main.yxКлючевые моменты проектирования:
- Встроенный бинарный как слой совместимости: до полного появления файловой системы стандартной библиотеки модули std предоставляются через встроенный бинарный
- Изоляция по версиям:
yx/<version>/std/позволяет сосуществовать разным версиям стандартной библиотеки без взаимного влияния - std и обычные зависимости используют один механизм (add/lock/vendor), без специальных каталогов и уровней поиска
- В режиме одиночного файла — откат к глобальному std; при наличии vendor std должен поступать из vendor (либо явно зафиксирован через
add std@)
Основные структуры данных
// Источник зависимости (расширяемый)
enum Source {
Local { path: PathBuf },
Git { url: Url, version: Option<VersionConstraint> },
Registry { registry: String, namespace: Option<String> },
GitHub { owner: String, repo: String, ref_: GitRef }, // нативный GitHub
}
enum GitRef {
Tag(String),
Branch(String),
Rev(String),
DefaultBranch,
}
// Объявление зависимости
enum DependencySpec {
Version(VersionConstraint),
Git { url: Url, version: Option<VersionConstraint> },
Local { path: PathBuf },
Workspace { member: String }, // ссылка на члена рабочего пространства
}
// Разрешённая зависимость (решение от 2026-09-15: для целостности используется только одно поле integrity формата "sha256-<hex>", без дублирующего checksum)
struct ResolvedDependency {
name: String,
version: Version,
source: Source,
integrity: Option<String>,
}
// Стратегия сборки
enum BuildStrategy {
None, // чистый пакет .yx
Cargo, // вызов cargo build
Cmake, // вызов cmake
Custom, // выполнение скрипта build.yx
Precompiled, # непосредственное использование предкомпилированного артефаккта
}Проект CLI-команд
Используется унифицированный подход, объединяющий компилятор, менеджер пакетов и REPL в единый CLI-инструмент:
Режим одиночного файла vs. проектный режим
| Команда | Одиночный файл | Проектный режим | Описание |
|---|---|---|---|
yaoxiang run <file> | ✅ | ✅ | Запуск файла/точки входа проекта |
yaoxiang build | ❌ | ✅ | Сборка проекта |
yaoxiang build <file> | ✅ | ✅ | Сборка отдельного файла |
yaoxiang init <name> | ❌ | ✅ | Создание проекта |
yaoxiang add <dep> | ❌ | ✅ | Добавление зависимости |
yaoxiang update | ❌ | ✅ | Обновление зависимостей |
yaoxiang fmt | ✅ | ✅ | Форматирование |
yaoxiang check | ✅ | ✅ | Проверка типов |
yaoxiang (без аргументов) | ✅ | ✅ | Непосредственный вход в REPL |
Подробное описание команд
| Команда | Функция | Пример |
|---|---|---|
yaoxiang | Непосредственный вход в REPL | yaoxiang |
yaoxiang run <file> | Запуск одиночного файла/проекта | yaoxiang run main.yx |
yaoxiang init <name> | Создание нового проекта | yaoxiang init my-app |
yaoxiang build | Сборка проекта | yaoxiang build |
yaoxiang build <file> | Сборка отдельного файла | yaoxiang build foo.yx |
yaoxiang add <dep> | Добавление зависимости | yaoxiang add foo |
yaoxiang add -D <dep> | Добавление зависимости для разработки | yaoxiang add -D test |
yaoxiang rm <dep> | Удаление зависимости | yaoxiang rm foo |
yaoxiang update | Обновление всех зависимостей | yaoxiang update |
yaoxiang update foo | Обновление указанной зависимости | yaoxiang update foo |
yaoxiang install | Установка всех зависимостей | yaoxiang install |
yaoxiang list | Список зависимостей | yaoxiang list |
yaoxiang outdated | Проверка устаревших зависимостей | yaoxiang outdated |
yaoxiang fmt | Форматирование кода | yaoxiang fmt |
yaoxiang check | Проверка типов | yaoxiang check |
yaoxiang clean | Очистка артефактов сборки | yaoxiang clean |
yaoxiang task <name> | Выполнение пользовательской задачи | yaoxiang task lint |
yaoxiang publish | Публикация пакета в Registry | yaoxiang publish |
yaoxiang publish --github | Публикация и создание GitHub Release | yaoxiang publish --github |
yaoxiang yank <pkg>@<ver> | Удаление опубликованной версии (необратимо) | yaoxiang yank foo@1.2.3 |
yaoxiang login --registry <url> | Аутентификация в Registry | yaoxiang login --registry https://reg.example.com |
yaoxiang login --github | Аутентификация в GitHub | yaoxiang login --github |
yaoxiang logout --registry <url> | Выход | yaoxiang logout --registry https://reg.example.com |
yaoxiang cache clean | Очистка глобального кэша | yaoxiang cache clean |
yaoxiang workspace <cmd> | Операции с рабочим пространством | yaoxiang workspace list |
Пояснения к ограничениям команд
# Режим одиночного файла: yaoxiang.toml не требуется
yaoxiang run hello.yx # ✅ работает нормально
yaoxiang add foo # ❌ ошибка: это не каталог проекта
# Проектный режим: требуется yaoxiang.toml
cd my-project
yaoxiang run main.yx # ✅ запуск файла точки входа
yaoxiang build # ✅ сборка проекта
yaoxiang add foo # ✅ добавление зависимостиОбратная совместимость
- ✅ Существующий синтаксис
useполностью сохранён - ✅ Существующая логика разрешения модулей не изменена
- ✅ Новый каталог
.yaoxiang/vendorне влияет на существующие проекты
Глобальный кэш
Все загруженные зависимости кэшируются в ~/.yaoxiang/cache/, проектный каталог vendor копируется из кэша.
~/.yaoxiang/
├── cache/
│ ├── registry/
│ │ └── foo-1.2.3/
│ ├── git/
│ │ └── github.com-user-bar-abc123/
│ └── binaries/
│ └── foo-1.2.3-linux-x86_64.tar.gz
├── credentials.toml
└── config.toml# ~/.yaoxiang/config.toml
[cache]
dir = "~/.yaoxiang/cache"
max_size = "2GB"
ttl = "30d"Правила инвалидации кэша:
- Пакеты Registry: номер версии неизменяем, инвалидация не требуется
- Git-зависимости: кэшируются по tag/rev, при неизменном tag инвалидация не требуется
yaoxiang cache clean— ручная очистка
Аутентификация
# ~/.yaoxiang/credentials.toml
[github]
token = "ghp_xxxx"
[registries.my-company]
url = "https://yxreg.my-company.com"
token = "xxx"- Приоритет переменных окружения:
$YX_GITHUB_TOKEN,$YX_REGISTRY_TOKEN - Токен никогда не записывается в
yaoxiang.tomlилиyaoxiang.lock - Права доступа к файлу: 600
Семантика yank
yaoxiang yank foo@1.2.3 выполняет удаление + блокировку номера версии:
- Пакет полностью удаляется, восстановление невозможно
- Номер версии остаётся занят навсегда, повторная публикация той же версии невозможна
- Проекты, в чьих lockfile уже есть ссылка на эту версию, будут выдавать ошибку, требуя обновления
- Цель безопасности: предотвращение атак на цепочку поставок в стиле npm (когда злоумышленник перехватывает удалённый номер версии и внедряет вредоносный код)
Протокол Registry
Подробности см. в RFC-014a: Спецификация протокола Registry.
Основной проект: открытый протокол + адаптерный слой. Официальный Registry как основной, GitHub Release/main как вспомогательный, поддержка пользовательских Registry.
Система сборки
Подробности см. в RFC-014b: Система сборки и распространение бинарных файлов.
Основной проект: декларативная конфигурация [build], приоритет предкомпиляции / исходный код как запасной вариант, поддержка стратегий cargo/cmake/custom.
Рабочее пространство
Подробности см. в RFC-014c: Поддержка рабочих пространств.
Основной проект: декларация members в виде словаря, общий lockfile, зависимости по путям, интеграция с Cargo workspace.
Компромиссы
Преимущества
- Унифицированный синтаксис импорта, пользователю не нужно заботиться об источнике зависимости
- Детерминированная сборка, файл блокировки гарантирует согласованность
- Поддержка офлайн-режима, после загрузки возможна офлайн-разработка
- Source trait упрощает дальнейшее расширение
Недостатки
- Требуется дополнительное дисковое пространство (каталог
.yaoxiang/vendor) - Конфликты версий требуют ручного разрешения пользователем
Альтернативные варианты
| Вариант | Почему не выбран |
|---|---|
| Доступ к GitHub в реальном времени | Сложно гарантировать безопасность и повторное использование кэша |
| Глобальный кэш ($HOME/.yaoxiang) | Слабая изоляция, сложные конфликты версий |
| Поддержка только реестра | GitHub — текущая основная платформа хостинга кода |
Стратегия реализации
Этапы
| Этап | Содержание | Статус |
|---|---|---|
| Phase 1 | Разбор toml, локальные зависимости, генерация lock, базовые алгоритмы | ✅ Завершён |
| Phase 2 | Поддержка GitHub, управление .yaoxiang/vendor, инструменты загрузки | ✅ Завершён |
| Phase 3 | Глобальный кэш, замена semver crate, доработка CLI | Не начат |
| Phase 3.5 | Перевод Source trait на async, интеграция async-trait | Не начат |
| Phase 4 | Адаптерный слой GitHub, упаковка .yxpkg, publish --github (после сокращения объёма RFC-014a; официальный Registry/auth/yank отложены) | Не начат |
| Phase 5 | Система сборки, предкомпилированные бинарные файлы (RFC-014b) | Не начат |
| Phase 6 | Поддержка рабочих пространств (RFC-014c) | Не начат |
Корректировка порядка выполнения (2026-09-15): 3 → 3.5 → 6 → 4 → 5.
- Рабочее пространство (Phase 6) перенесено перед системой сборки — оно не зависит от сети и системы сборки (чисто локальное разрешение по путям + общий lockfile) и даёт наибольший эффект при разработке нескольких пакетов.
- Сокращение объёма Phase 4: сервер официального Registry, а также auth/yank откладываются на неопределённый срок; сначала поставляются адаптерный слой GitHub Release/Git + упаковка
.yxpkg+ `publish --github». Для холодного старта экосистемы достаточно каналов git/GitHub (аналогично раннему Go), затраты на эксплуатацию и управление сервером Registry на этапе отсутствия сторонних пакетов — чистый пассив. - Следствие: до запуска официального Registry
yaoxiang add <имя-без-источника>недоступно, добавление зависимости требует явного указания источника (--git/--path).
Зависимости
- Предварительных зависимостей нет
- Требуется интеграция с
ModuleGraph(middle/passes/module/)
Риски
| Риск | Мера по смягчению |
|---|---|
| Сложность алгоритма разрешения зависимостей | Сначала простая версия, затем обнаружение конфликтов |
| Нестабильность загрузки из Git | Механизмы повтора и кэширования |
| Проблемы производительности | Ленивая загрузка, инкрементальное разрешение |
Открытые вопросы
- [x] Синтаксис условной компиляции для
dev-dependencies? → Обрабатывается единообразно системой сборки в RFC-014b - [x] Алгоритм проверки целостности (SHA-256 / BLAKE3)? → SHA-256
- [x] Соглашение об именовании пакетов (поддержка namespace, например
@org/pkg)? → На начальном этапе плоские имена пакетов, без namespace;@org/pkgзарезервировано (решение от 2026-09-15) - [x] Стратегия версионирования Registry API? → Путь URL
/api/v1/+ версия протокола в заголовке ответа, при ломающих изменениях — параллельное сосуществование v2 (решение от 2026-09-15, см. RFC-014a) - [ ]
excludes— исключение определённых файлов из загрузки?
Зависимости (необходимо добавить в Cargo.toml)
| Назначение | crate | Описание |
|---|---|---|
| Семантическое версионирование | semver | Замена самописного парсера |
| HTTP-клиент | reqwest | Связь с Registry |
| SHA-256 | sha2 | Проверка целостности |
| Сжатие | flate2 + tar | Обработка формата пакетов |
