В настоящее время я перехожу от устаревшей системы контроля версий и перемещаю свой групповой проект в меркурийный. В качестве одного из примеров типов кода, который я перемещаю, у меня есть решение с 25+ проектами Visual Studio, содержащее несколько отдельных областей приложения, которые зависят от общего кода. Оглядываясь на переполнение стека, ближайший вопрос, который я нашел, был этот, но он просто упомянул контроль версий. Я ищу несколько дополнительных советов по конкретным методам реализации использования Mercurial для управления этими зависимостями.
Упрощенный вид зависимостей выглядит примерно так: (Это только для иллюстрации и примера, фактические зависимости значительно сложнее, но похожи по своему характеру.)
Common Lib 1
/ | \
---- | -----
/ | \ \
App 1 Common Lib 2 \ App 2
/ | \ \
------- | ------ |
/ | \|
App 3 App 4 App 5
Модули Common Lib будут общим кодом - это будет DLL или SO или какая-то другая библиотека, которая будет использоваться между всеми приложениями одновременно - как во время компиляции, так и во время выполнения. Приложения в противном случае могли бы работать независимо друг от друга.
У меня есть пара целей с настройкой моих ртутных репозиториев:
- Дайте каждому существенному приложению или группе компонентов собственный репозиторий.
- Сделать каждый репозиторий автономным.
- Сделать общую сумму проекта автономной.
- Простое создание всей базы кода сразу. (в конечном итоге все эти программы и библиотеки попадают в один установщик.)
- Держите его простым.
Еще один момент заключается в том, что у меня установлен сервер, где у меня есть отдельные репозитории для каждого из этих проектов.
Я вижу пару способов выложить эти проекты.
1. Создайте репозиторий "Shell", содержащий все.
Это будет использовать subrepos на основе url (например, в .hgsub, я бы сделал что-то вроде App1 = https://my.server/repo/app1
.) Выложенный, он выглядел бы следующим образом:
+---------------------------+
| Main Repository |
| | +---------------------+ |
| +-| Build | |
| | +---------------------+ |
| | +---------------------+ |
| +-| Common Lib 1 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| Common Lib 2 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| App 1 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| App 2 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| App 3 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| App 4 | |
| | +---------------------+ |
| | +---------------------+ |
| +-| App 5 | |
| +---------------------+ |
+---------------------------+
Каждая основная папка в репозитории оболочки будет содержать subrepo, по одному для каждой области проекта. Зависимости будут относительными: например, поскольку App 4 нуждается в Common Lib 2, он просто будет использовать относительные пути для ссылки на общую библиотеку.
Плюсы такого подхода:
- Каждая библиотека сбрасывается один раз и только один раз.
- Подтверждения Mercurial гарантируют, что одна и та же версия библиотеки будет использоваться во всех проектах автоматически, так как в проекте существует только одна версия этого подрежима.
- Легко найти каждый ресурс.
Недостатки этого подхода:
- Я не могу работать в приложении самостоятельно. Например, если я работаю над App 2, и ему необходимо изменить общие библиотеки, все остальные приложения должны будут внести эти изменения прямо сейчас.
- Если я вывожу репозиторий App, я должен выяснить (или узнать), какие другие зависимые репозитории он потребует от руки, если я хочу его построить.
- Зависимости не сильно разделены - было бы заманчиво вставлять новую функцию где угодно, так как было легко получить все функции.
2. Зависимые подпосылки должны содержаться полностью.
В этом подходе каждое приложение будет иметь свой собственный репозиторий (как и раньше), но на этот раз также содержат субрепозитории: один для своего собственного источника и один для каждого зависимого подпозитория. Затем общий репозиторий будет содержать каждый из этих репозиториев проектов и знает, как построить все решение. Это будет выглядеть следующим образом:
+-----------------------------------------------------------------------+
| Main Repository |
| +--------------------+ +--------------------+ +--------------------+ |
| | Build | | Common Lib 1 | | Common Lib 2 | |
| +--------------------+ | | +--------------+ | | | +--------------+ | |
| | +-| Lib 1 Source | | | +-| Common Lib 1 | | |
| | +--------------+ | | | +--------------+ | |
| | | | | +--------------+ | |
| | | | +-| Lib 2 Source | | |
| | | | +--------------+ | |
| +--------------------+ +--------------------+ |
| +--------------------+ +--------------------+ +---------------------+ |
| | App 1 | | App 2 | | App 3 | |
| | | +--------------+ | | | +--------------+ | | | +--------------+ | |
| | +-| Common Lib 1 | | | +-| Common Lib 1 | | | +-| Common Lib 2 | | |
| | | +--------------+ | | | +--------------+ | | | +--------------+ | |
| | | +--------------+ | | | +--------------+ | | | +--------------+ | |
| | +-| App 1 Source | | | +-| App 2 Source | | | +-| App 3 Source | | |
| | +--------------+ | | +--------------+ | | +--------------+ | |
| +--------------------+ +--------------------+ +---------------------+ |
| +--------------------+ +--------------------+ |
| | App 4 | | App 5 | |
| | | +--------------+ | | | +--------------+ | |
| | +-| Common Lib 2 | | | +-| Common Lib 1 | | |
| | | +--------------+ | | | +--------------+ | |
| | | +--------------+ | | | +--------------+ | |
| | +-| App 4 Source | | | +-| Common Lib 2 | | |
| | +--------------+ | | | +--------------+ | |
| +--------------------+ + | +--------------+ | |
| | +-| App 5 Source | | |
| | +--------------+ | |
| +--------------------+ |
+-----------------------------------------------------------------------+
Плюсы:
- Каждое приложение может быть создано самостоятельно, независимо друг от друга.
- Зависимые версии библиотек можно отслеживать для каждого приложения, а не глобально. Для добавления новой зависимости требуется явный акт вставки subrepo в проект.
Минусы:
- При выполнении окончательной сборки каждое приложение может использовать другую версию разделяемой библиотеки. (возможно, потребуется написать инструменты для синхронизации общих подпотоков lib. Eww.)
- Если я хочу построить весь источник, я в конечном итоге несколько раз удаляю разделяемые библиотеки. В случае с Common Lib 1 мне пришлось бы вытащить его через восемь (!) Раз.
3. Не включайте зависимости вообще как subrepos - вносите их как часть сборки.
Этот подход будет похож на подход 1, за исключением того, что общие библиотеки будут вытаскиваться только как часть сборки. Каждое приложение должно знать, какие репозитории ему нужны, и разместить их в общем месте.
Плюсы:
- Каждое приложение может создавать самостоятельно.
- Обычные библиотеки нужно будет только один раз вытащить.
Минусы:
- Нам нужно отслеживать версии библиотек, которые в настоящее время используются каждым приложением. Это дублирует функции subrepo.
- Нам нужно создать инфраструктуру для поддержки этого, а это значит, что в сборку скриптов нужно больше вещей. Тьфу.
4. Что еще?
Есть ли другой способ обращения с ним? Лучше? Какие способы вы пробовали и преуспели, какие способы вы пробовали, но ненавидели? Я сейчас склоняюсь к 1, но отсутствие независимости приложения, когда оно должно быть в состоянии, действительно беспокоит меня. Есть ли способ получить хорошее разделение метода 2 без массивного дублирования коллажа для поддержания тяги и зависимостей кода, в то время как не нужно писать сценарии для его обработки (как в варианте 3)?