Команда 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.py
template.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
можно будет запускать без явного указания типа проекта.
После генерации проекта будет вызвана функция 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>
— имя макроса, который необходимо удалить.