Команда ya project служит для создания или изменения файла ya.make проекта.
ya project <subcommand>
create— создает новый проект.update— обновляет типовой проект.fix-peerdirs— добавляет недостающие и удаляет неиспользуемыеpeerdirsв проекте.macro— добавляет или удаляет макрос в файлеya.make.
Команда ya project create используется для создания нового типового проекта. Команда может создавать и модифицировать файлы описания сборки ya.make, а также любые другие файлы, включая исходный код и документацию.
ya project create <project-type> [dest_path] [options]
<project-type>(обязательный) — тип создаваемого проекта. Список встроенных типов проектов описан ниже. Полный список доступных типов проектов (включая шаблонные) можно получить с помощью командыya project create --help.dest_path(необязательный) — путь к каталогу, в котором будет создан новый проект. Если параметр не указан, проект будет создан в текущем каталоге.options(необязательный) — дополнительные параметры для настройки создаваемого проекта. Список доступных опций можно получить с помощью командыya project create <project-type> --help.
Команда ya project create поддерживает следующие встроенные типы проектов (<project-type>):
| Имя | Описание |
|---|---|
library |
Простая C++ библиотека. |
program |
Простая C++ программа. |
unittest |
Тест для C++ на фреймворке unittest. С параметром --for создает тесты для указанной библиотеки (с исходным код тестов в ней). |
mkdocs_theme |
Python-библиотека темы mkdocs. Требует указания параметра --name — имя шаблона и наличия __init__.py в текущей директории. |
recurse |
Создать ya.make для сборки вложенных целей с помощью RECURSE(). |
Большинство встроенных проектов поддерживают следующие опции:
-h,--help— справка по опциям для конкретного проекта.--set-owner— установить владельцем пользователя или группу.--rewrite— перезаписатьya.make.-r,--recursive— создать проекты рекурсивно по дереву директорий.
Команда ya project create поддерживает расширяемую генерацию проектов по шаблонам, что позволяет пользователям создавать проекты с использованием собственных шаблонов.
Чтобы начать использовать эту функцию, вам необходимо создать шаблон проекта и зарегистрировать его для использования с ya project create.
Информацию о создании и регистрации шаблонов можно найти в документации по шаблонам ya.
Шаблоны проектов хранятся в репозитории и зачитываются непосредственно в момент запуска команды. Полный список доступных типов проектов доступен по команде ya project create --help. Список включает как встроенные, так и шаблонные типы.
На момент написания документации доступны следующие шаблонные проекты:
| Имя | Описание |
|---|---|
| docs | Проект документации. |
| project_template | Шаблон для создания шаблона проекта. |
| py_library | Пустая Python 3 библиотека с тестами. |
| py_program | Пустая Python 3 программа с тестами. |
| py_quick | Программа на Python 3 из всех .py-файлов в директории. |
| ts_library | Шаблон для библиотеки на TypeScript. |
Генерация проекта по шаблону не слишком отличается от генерации встроенных проектов, есть лишь небольшое отличие в работе с опциями. Шаблоны могут поддерживать свои опции.
При указании целевой директории шаблонные опции необходимо писать строго после нее.
Если опция шаблона совпадает со встроенной, то передать в шаблон опцию можно после --.
Пример
ya project create docs --help
Create docs project
Usage:
ya project create docs [OPTION]... [TAIL_ARGS]...
Options:
Ya operation options
-h, --help Print help
Bullet-proof options
--set-owner=SET_OWNER
Set owner of project(default owner is current user)
--rewrite Rewrite existing ya.makeПри совпадении опции
ya project create docs -- --help
usage: Docs project generator [-h] [--name NAME]
optional arguments:
-h, --help show this help message and exit
--name NAME Docs project nameШаблон проекта представляет собой две функции на Python 3 (get_params(context), postprocess(context, env)) и набор необязательных jinja-шаблонов.
Шаблон должен находиться в поддиректории devtools/ya/handlers/project/templates и быть зарегистрирован в файле devtools/ya/handlers/project/templates/templates.yaml.
Создать основу для шаблона проекта можно с помощью команды ya project create project_template, которая сама является примером использования шаблонной генерации.
Выглядит это так:
/devtools/ya/handlers/project/templates
mkdir my_project
ya project create project_templateПолучится следующая структура директорий:
devtools/ya/handlers/project/templates/my_project
├── template
│ └── place-your-files-here
├── README.md
└── template.pytemplate.py будет содержать заготовки для двух функций:
def get_params(context):
"""
Calculate all template parameters here and return them as dictionary.
"""
env = {}
return env
def postprocess(context, env):
"""
Perform any post-processing here. This is called after templates are applied.
"""
passВ функции get_params нужно получить данные, необходимые для создания шаблона проекта и сформировать словарь env, который будет использоваться для подстановки в jinja-шаблоны и передан в prostprocess.
Параметры можно получить из переданного контекста (параметр context), разбором опций, переданных в контексте или интерактивным запросом у пользователя.
Параметр context — это namedtuple типа Context из template_tools.common. В нем доступно четыре свойства:
path— относительный путь от корня репозитория до создаваемого проекта.root— абсолютный путь корня репозитория.args— список неразобранных аргументов, переданных в конце вызоваya project create <project_name> [path] [args].backup— объект изtemplate_tools.common, позволяющий сохранять оригинальные файлы перед их редактированием. Файлы будут восстановлены в случае исключений во время геренерации проекта, а также будут сохранены в~/.ya/tmpна случай если что-то пойдет не так (сохраняются файлы от последних 5 сейссий).
Код для get_params может выглядеть, например, так:
python
from __future__ import absolute_import
from __future__ import print_function
from pathlib2 import Path
from template_tools.common import get_current_user
def get_params(context):
"""
Calculate all template parameters here and return them as dictionary
"""
print("Generating sample project")
path_in_project = Path(context.path)
env = {
"user": context.owner or get_current_user(),
"project_name": str(path_in_project.parts[-1]),
}
return envДля аккуратного выхода из генерации во время подготовки параметров вместо env можно вернуть объект класса template_tools.common.ExitSetup.
В поддиректории template необходимо разместить jinja-шаблоны генерируемых файлов. В этих шаблонах можно использовать подстановки из словаря env.
Генерируемые файлы будут создаваться на основе этих шаблонов и сохраняться под теми же именами в целевой директории. Обычно среди шаблонов будет, по крайней мере, один для ya.make и несколько для исходного кода.
Например, для проекта можем создать следующие шаблоны:
Файл ya.make
PROGRAM(not_var{{project_name}})
SRCS(
main.cpp
)
END()
Файл main.cpp
#include <util/stream/output.h>
int main() {
Cout << "Hello from not_var{{user}}!" << Endl;
}
Не забудьте удалить файл place-your-files-here.
Если проект не использует шаблоны, а, например, генерирует код напрямую в postprocess, то в директорию template следует добавить файл .empty.notemplate.
Это будет означать, что для данного проекта шаблоны не предусмотрены и не были забыты.
Если у вашего типа проекта есть не только шаблон создания, но и шаблон обновления, то вы можете добавить вот такой шаблон:
.ya_project.default
name: not_var{{__PROJECT_TYPE__}}Этот файл установит тип проекта по умолчанию для данной директории, и команду ya project update можно будет запускать без явного указания типа проекта.
Можно задать тип проекта по умолчанию для всего дерева директорий:
.ya_project.default
recursive:
name: not_var{{__PROJECT_TYPE__}}После генерации проекта будет вызвана функция postprocess. В этой функции можно выполнить окончательные доработки, внести изменения или вывести сообщения. Например, с помощью вызова add_recurse(context) из модуля template_tools.common можно добавить новый проект в родительскую директорию.
python
def postprocess(context, env):
"""
Perform any post-processing here. This is called after templates are applied.
"""
from template_tools.common import add_recurse
add_recurse(context)
print("You are get to go. Build your project and have fun:)")
passВ этой же функции можно разместить вообще всю генерацию, если не хочется использовать шаблоны.
Чтобы шаблон стал доступен в ya project create, его нужно зарегистрировать в файле devtools/ya/handlers/project/templates/templates.yaml.
Надо добавить в этот файл примерно следующее:
yaml
- name: my_project # Имя типа проекта, которое надо указывать в команде
description: Create test project # Описание для ya project create --help
create: # Шаблон для `ya project create` (есть еще update)
path: my_project # Относительный путь до директории с шаблономТеперь можно протестировать шаблон. Он будет автоматически использован при запуске команды ya project create, никаких дополнительных сборок не потребуется.
ya project create --help
Create project
Usage: ya project create <subcommand>
Available subcommands:
docs Create docs project
library Create simple library project
mkdocs_theme Create simple mkdocs theme library
my_project Create test project <<<< Это наш шаблон
program Create simple program project
project_template Create project template
py_library Create python 3 library with tests
py_program Create python 3 program with tests
py_quick Quick create python 3 program from existing sources without tests
recurse Create simple recurse project
unittest Create simple unittest projectДля проверки создайте ya.make в родительской директории:
cat project/user/tst/ya.makeЗапустите:
ya project create my_project project/user/tst/myprj
Generating sample project
You are get to go. Build your project and have fun:)Соберите через родительский ya.make и запустите:
ya make project/user/tst
project/user/tst/myprj/myprj
Hello from user!Структура директорий:
project/user/tst
├── myprj
│ ├── main.cpp
│ ├── myprj
│ └── ya.make
└── ya.makeФайлы:
project/user/tst/ya.make
RECURSE(
myprj
)project/user/tst/myprj/ya.make
PROGRAM(myprj)
SRCS(
main.cpp
)
END()project/user/tst/myprj/main.cpp
#include <util/stream/output.h>
int main() {
Cout << "Hello from user!" << Endl;
}Обычно файлы из шаблона переносятся в генерируемый проект с сохранением своих имен. Однако есть несколько дополнительных правил, призванных помочь обойти сложные и необычные случаи.
-
Файл
.empty.notemplateпозволяет создать пустую директорию. Все файлы в директории, содержащей такой файл, будут проигнорированы. -
Файлы с расширением
.notemplateигнорируются. Это позволяет иметь в директории шаблона служебные файлы, которые не будут считаться шаблонами и не попадут в проект. -
Файлы с расширением
.templateпосле подстановки данных шаблона записываются в проект без расширения.template. Это позволяет иметь в шаблоне файлы, которые могут быть специально обработаны под своими обычными именами. Например, в шаблоне нельзя иметь файлa.yaml, но можно использоватьa.yaml.template, и после подстановки данных он станетa.yamlв целевом проекте.
Примеры:
- Чтобы добавить в проект файл
x.template, положите для него шаблон с именемx.template.template. - Чтобы добавить в проект файл
x.notemplate, положите для него шаблон с именемx.notemplate.template.
Рекомендуется запускать команду ya project create в пустой директории. Хотя команда обычно не перезаписывает существующие файлы и завершится с ошибкой, это поведение не гарантирует защиту от возможных ошибок в коде.
На данный момент встроенные хендлеры не создают директории для проекта, если они отсутствуют, в то время как шаблонные хендлеры создают необходимые директории автоматически.
Команда ya project update предназначена для обновления типового проекта. Она может создавать и изменять как файлы описания сборки ya.make, так и любые другие файлы, включая исходный код и/или документацию. В отличие от команды ya project create, команда ya project update предназначена для дополнения или актуализации существующего проекта.
ya project update [project-type] [dest_path] [options]
project-type— тип проекта, который необходимо обновить.dest_path— путь к директории проекта, который необходимо обновить.options— дополнительные параметры для команды.
ya project update поддерживает небольшой набор встроенных типов проектов и расширяемое обновление проектов по шаблонам. Чтобы увидеть полный список доступных типов проектов (включая шаблонные), используйте команду:
ya project update --helpНекоторые типы проектов можно использовать как в командах ya project create, так и ya project update, в то время как другие подходят только для одной из этих команд.
Доступно обновление для следующих встроенных типов проектов:
| Имя | Описание |
|---|---|
recurce |
Дописать в ya.make недостающие RECURSE на дочерние проекты. |
resources |
Обновить информацию об автообновляемых ресурсах. |
-h,--help— справка по опциям для конкретного проекта.-r,--recursive— обновить проекты рекурсивно по дереву директорий.--dry-run— дляresourcesне делать обновление, а лишь показать, что будет обновлено.
Если тип проекта не указан, ya project update попробует найти файл с именем .ya_project.default. Это файл в формате yaml, в котором команда будет искать ключ name. Значение этого ключа будет использовано как тип проекта. Такой файл может создавать команда ya project create.
Примеры использования
project/user/libX
├── bin
│ ├── __main__.py
│ └── ya.make
├── dummy
│ └── file.X
├── lib
│ ├── tests
│ │ ├── test.py
│ │ └── ya.make
│ ├── app.py
│ └── ya.make
└── ya.makeПредположим, что в двух файлах не хватает RECURSE.
project/user/libX/ya.make
RECURSE(
bin
)project/user/libX/lib/ya.make
PY3_LIBRARY()
PY_SRCS(app.py)
END()При запуске
ya project update recurse project/user/libX --recursive
Warn: No suitable directories in project/user/libX/dummy
Info: project/user/libX/lib/ya.make, RECURSE was updated
Info: project/user/libX/ya.make, RECURSE was updatedПри проверке:
project/user/libX/ya.make(обратите внимание, чтоRECURSEнаdummyне нужен, поскольку там нетya.make)
RECURSE(
bin
lib
)project/user/libX/lib/ya.make
PY3_LIBRARY()
PY_SRCS(app.py)
END()
RECURSE(
tests
)Помимо описанных выше встроенных типов проектов, команда ya project update поддерживает расширение функциональности за счет использования шаблонов. Шаблоны проектов хранятся в репозитории и загружаются непосредственно во время выполнения команды.
Полный список доступных типов проектов, включая как встроенные, так и шаблонные, можно получить с помощью команды:
ya project update --helpНа момент написания документации для обновления доступны следующие шаблонные проекты:
| Имя | Описание |
|---|---|
py_library |
Добавить отсутствующие .py-файлы в PY_SCRS проекта. |
py_program |
Добавить отсутствующие .py-файлы в PY_SCRS проекта. |
py_quick |
Добавить отсутствующие .py-файлы в PY_SCRS проекта. |
Все эти шаблоны используют один и тот же механизм, добавляющий отсутствующие файлы.
Процесс обновления проекта по шаблону аналогичен генерации встроенных проектов, за исключением отличий в работе с опциями. Количество общих опций сведено к минимуму, однако шаблоны могут поддерживать свои собственные опции.
При указании целевой директории необходимо указывать опции шаблона строго после нее. Если опция шаблона совпадает со встроенной, ее можно передать в шаблон после --.
Для примера, обновление проектов для Python поддерживает следующие опции:
project update py_quick -- --help
usage: Python project updater [-h] [--recursive]
optional arguments:
-h, --help Показать справку
--recursive Добавить файлы из поддиректорий тожеОтметим, что опция --recursive имеет разный смысл во встроенных и шаблонных проектах.
Для встроенных проектов --recursive означает рекурсивное обновление по дереву директорий.
Однако для обновления по шаблону рекурсивная работа не поддерживается, и --recursive является опцией самого шаблона, указывающей на необходимость рекурсивного поиска .py-файлов в поддиректориях и их добавления в обновляемый проект.
Процесс добавления шаблона для обновления проектов практически идентичен добавлению шаблона для создания проектов с некоторыми особенностями. Эти различия направлены на обеспечение безопасного и надежного обновления файлов проекта.
Обработка существующих файлов
- При создании файла по шаблону, если целевой файл уже существует, команда
ya project createзавершится с ошибкой. - В отличие от этого, команда
ya project updateперезапишет существующий файл. Оригинальный файл при этом будет сохранен, и в случае ошибки он будет восстановлен. - Дополнительно, оригинальные файлы хранятся в директории
.ya/tmpс данными от последних 5 запусков на случай, если что-то пойдет не так. - При модификации файлов из кода шаблона рекомендуется также использовать объект
backup, передаваемый в контексте.
Для регистрации шаблона обновления необходимо указать путь в секции update файла конфигурации yaml. Пример конфигурации:
- name: my_project # Имя типа проекта, которое надо указывать в команде
description: Create test project # Описание для ya project create --help
create: # Шаблон для `ya project create`
path: my_project_up # Относительный путь до директории с шаблоном создания
update: # <-- Шаблон для `ya project update`
path: my_project_up # <-- Относительный путь до директории с шаблоном обновленияСекция create в конфигурации не является обязательной. Можно создать проекты, которые предназначены только для обновления, без поддержки создания.
Добавить отсутствующие и удалить лишние записи PEERDIR в проекте. Необходимость записей определяется анализом зависимостей исходных файлов проекта.
Синтаксис команды: ya project fix-peerdirs [OPTION]... [TARGET]...
-h, --help Справка
-a Только добавить недостающие PEERDIR
-d Только удалить лишние PEERDIR
-v Подробная диагностика
-l Только диагностика
--sort Отсортировать PEERDIR
-c, --cycle Обнаруживать циклические зависимостиКоманда ya project macro используется для добавления или удаления макросов в файле ya.make.
ya project macro add <macro_string> [OPTIONS]
<macro_string>— строка макроса, которую необходимо добавить.[OPTIONS]— дополнительные параметры.
Опции для команды add
--after=SET_AFTER— добавить макрос после указанного макроса.--append— добавить аргументы к существующему макросу.
Примеры
ya project macro add "MACRO_NAME(VALUE1 VALUE2 ...)" Вставить макрос MACRO_NAME в начало списка макросов
ya project macro add --set_after=AFTER_MACRO_NAME "MACRO_NAME(VALUE1 VALUE2 ...)" Вставить макрос MACRO_NAME после AFTER_MACRO_NAME в начало списка макросовya project macro remove <macro_name>, где <macro_name> — имя макроса, который необходимо удалить.