В нашем блоге мы уже говорили о о принципах организации репозитория для большого проекта в виде набора независимых модулей, что позволяет организовать извлечение исходных кодов в произвольную файловую структуру рабочей копии.
Разумеется, такой подход не мог не отразиться на системе сборки проекта, поскольку требовал создания механизма отслеживания зависимостей между модулями с учетом их фактического размещения.
Данная статья посвящена тому, как можно использовать возможности git для решения не только этой задачи, но и извлечения фрагмента проекта с автоматическим учетом внутренних межмодульных зависимостей.
Несколько слов о примерах
Изначально предполагалось предоставить данной публикации фрагменты системы сборки в том виде, в котором она реализована в ЛИНТЕР , однако в этом проекте мы не используем нативные модули git и используем собственную утилиту make. Поэтому, чтобы не пострадала практическая ценность материала для читателей, все примеры адаптирован для использования совместно с подмодулями git и gnu make, что привело к определённым трудностям, которые будут указаны ниже.
Описание демо-версии Для простоты рассмотрим интеграцию системы сборки с git на примере условного продукта под названием project, который состоит из следующих функциональных модулей: приложения – само приложение; демо – демонстрационные примеры; libfoo и libbar — это библиотеки, от которых зависят приложения.
Граф зависимостей проекта будет следующим:
Рисунок 1. График зависимости проекта.
Организация хранения С точки зрения системы управления версиями проект разделен на пять отдельных репозиториев — четыре для модулей и пятый — project.git, который выполняет роль контейнера и содержит систему сборки.
Этот метод организации имеет ряд преимуществ по сравнению с монорепозиторием:
- каждый субмодуль имеет отдельную историю редактирования;
- возможность клонировать только часть проекта;
- каждый репозиторий может иметь индивидуальные правила и политики доступа;
- возможность извлечения проекта в произвольную структуру рабочей копии.
При этом корневой make-файл проекта должен не только «знать» положение модулей внутри проекта, но и обеспечивать вызов дочерних процессов make на целевых объектах в необходимой последовательности: от ветвей дерева зависимостей к корни.
Для этого нужно явно описать эти межмодульные зависимости; в нашем примере это сделано следующим образом :
Корректного обхода этого дерева можно добиться с помощью инструментов make, создав динамические цели с явным указанием зависимостей, для чего объявим функцию gen-dep следующего вида:MODS = project application libfoo libbar demo submodule.project.deps = application demo submodule.demo.deps = application submodule.application.deps = libfoo libbar submodule.libfoo.deps = submodule.libbar.deps =
define gen-dep
$(1):$(foreach dep,$(submodule.$(1).
deps),$(dep)) ;
endef
Теперь если в теле корневого Makefile вызвать gen-dep для всех модулей
$(foreach mod,$(MODS),$(eval $(call gen-dep,$(mod))))
тогда это создаст следующие динамические цели во время выполнения (вы можете проверить это, запустив make с ключом -p)
project: application demo
demo: application
application: libfoo libbar
libbar:
libfoo:
что позволяет гарантировать, что зависимости вызываются в необходимом порядке при доступе к ним.
В то же время, если имя цели совпадает с существующим файлом или каталогом, то это может привести к сбою выполнения, так как make «не знает», что эти наши цели — действия, а не файлы, во избежание этого укажем явно: $(eval .
PHONY: $(foreach mod,$(MODS), $(mod)))
Допустим, перед разработчиком стоит задача внесения изменений в приложение, для чего ему необходимо получить только подмодули application, libbar, libfoo. Для этого система сборки должна на основе заявленных выше зависимостей сформировать описание модулей и их размещение для последующего использования git, что, как известно , описывает зарегистрированные подмодули в файле с именем .
gitmodules, расположенном в корне клонированного репозитория.
Мы принесем это следующие изменения в нашем примере, чтобы обеспечить генерацию .
gitmodules минимально необходимого состава: …
MODURLPREFIX ?= [email protected]/
MODFILE ?= .
gitmodules … define tmpl.module "[submodule \"$(1)\"]" endef define tmpl.path "\tpath = $(1)" endef define tmpl.url "\turl = $(1)" endef … define submodule-set submodule.$(1).
name := $(2) submodule.$(1).
path := $(3) submodule.$(1).
url := $(4) endef define set-default $(call submodule-set,$(1),$(1),$(1),$(MODURLPREFIX)$(1).
git) endef define gen-dep $(1):$(foreach dep,$(submodule.$(1).
deps),$(dep))
Теги: #git #make #Системы контроля версий #linter #разработка #инструменты разработчика #Разработка веб-сайтов #git #Системы контроля версий
-
Перейти К Новым Комментариям
19 Oct, 24 -
Субстики №48
19 Oct, 24 -
Интересные Международные События В Декабре
19 Oct, 24 -
Как Мы Перешли Со Scala На Go
19 Oct, 24