Подтвердить что ты не робот

Какой хороший способ организовать проекты с общими зависимостями в Mercurial?

В настоящее время я перехожу от устаревшей системы контроля версий и перемещаю свой групповой проект в меркурийный. В качестве одного из примеров типов кода, который я перемещаю, у меня есть решение с 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)?

4b9b3361

Ответ 1

Управление зависимостями - это важный аспект организации проекта, на мой взгляд. Вы подробно описали различные решения, основанные на функции Subrepos Mercurial, и я согласен со всеми плюсами/минусами, которые вы дали.

Я думаю, что SCM не подходят для управления зависимостями. Я предпочитаю иметь выделенный инструмент для этого (это было бы вашим решением № 3).

Мой текущий проект находится на Java. Он был создан с Apache Ant, и я сначала настроил Apache Ivy в качестве инструмента управления зависимостями. В конце концов, настройка состояла из некоторых файлов конфигурации Ivy в общем каталоге и одного файла XML, в котором перечислены зависимости для каждого модуля проекта. Ivy может быть вызвана целями Ant, поэтому я добавил два новых действия в каждом модуле: "разрешить зависимости" и "развернуть встроенный артефакт". Развертывание добавляет результат buid (называемый артефактом) в общий каталог. Разрешение зависимостей означает транзитивное разрешение зависимостей модуля и копирование разрешенных артефактов в папке "lib" источников модуля.

Это решение применимо к проекту С++, поскольку Ivy не является специфичным для управления зависимостями Java: артефактами может быть что угодно. В С++ артефакты, создаваемые модулем, будут:

  • a so/dll во время выполнения
  • файлы заголовков во время компиляции.

Это не идеальное решение: Ivy нелегко настроить, вам все равно нужно сообщить своей сборке script, какие зависимости использовать, и у вас нет прямого доступа к источникам зависимостей для целей отладки. Но у вас есть независимые репозитории SCM.

В нашем проекте мы затем переключили форму Ant + Ivy на Apache Maven, которая заботится как о строении, так и об управлении зависимостями, Артефакты развертываются в Apache Archiva вместо общей папки. Это огромное улучшение, но оно будет хорошо работать только для проектов Java.

Ответ 2

Что вы хотите сделать, так это каждый проект в своем собственном каталоге, как в (1). Затем вы помечаете рабочие версии ваших зависимостей и сохраняете тег в некотором файле для сборки, например:

App1/.dependencies:
CommonLib1 tag-20100515
CommonLib2 tag-20100510

App2/.dependencies:
CommonLib1 tag-20100510
CommonLib2 tag-20100510

Затем вы используете скрипты сборки для создания библиотек на основе определенного тега и включаете эти встроенные библиотеки в качестве производных объектов для своих приложений. Если время сборки является проблемой, вы можете иметь тегированную версию, которая используется для тех библиотек, которые были предварительно созданы и сохранены где-то.

Примечание (принципы проектирования одинаковы при разработке схемы базы данных, объектной модели или сборки продукта):

  • Не ссылайтесь на код в других проектах (разрывы инкапсуляции)
  • У вас нет нескольких копий библиотек в вашем репозитории (модульность)

Ответ 3

Мы решили аналогичную проблему, используя подрывную деятельность.

Каждое приложение и каждый Common Lib имеют свои собственные репозитории.

Каждое приложение имеет каталог Libs, который содержит зависимые dll.

поэтому приложение получает обновление Common Lib, если предоставляется новый набор dll.

однако обновление папки lib не является тривиальным, потому что зависящие под-dll должны соответствовать правильной версии.