среда, 28 апреля 2010 г.

[prog] Пишется инструмент под условным названием svn_tag_maker

Мой подчиненный, молодой C++ программист, в порядке обучения пишет программу под названием svn_tag_maker. Ее основное предназначение – наведение порядка в svn-репозиториях.

Суть вот в чем. У нас зависимости между проектами выставляются посредством svn-свойства svn:externals (более подробно идею можно прочитать в моей статье). Например, если проекту ig_inout_door-2.0 нужны подпроекты ace, so_4 и pcre, то ссылки на соответствующие ветки этих проектов помещаются в svn:externals для каталога dev в проекте ig_inout_door. Выглядит такое свойство, приблизительно следующим образом:

ace   http://***/ace/tags/universal_wrapper.1.2/dev/ace
ace_lib_distrib   http://***/ace/tags/distribs/5.6.5/ace_lib_distrib
pcre  http://***/regex/pcre/tags/mxx_ru/7.7/dev/pcre
so_4  http://***/so_4/tags/4.4.b6/dev/so_4

Благодаря этому, если я делаю себе checkout проекта ig_inout_door-2.0, то он автоматом получает и все необходимые зависимости.

В чем здесь есть сложность – в том, что со временем появляются новые версии подпроектов, которые фиксируются в новых тегах своих репозиториев. Причем я могу даже не подозревать об этом. В какой-то прекрасный момент я озадачиваюсь вопросом – а нет ли новых версий для ace или so_4? И что мне делать в этой ситуации?

Можно самому заглянуть в репозитории соответствующих подпроектов и найти там вручную новые теги. Но ведь лучше, чтобы это сделала программа. Как раз такой программой и должна стать svn_tag_maker.

У svn_tag_maker планируется три режима. Первый режим – find, поиск новых версий подпроектов. Натравливаю svn_tag_maker на каталог dev проекта ig_inout_door-2.0 и получаю на выходе текстовый файл вида:

ace # http://***/ace/tags/universal_wrapper.1.2/dev/ace
   http://***/ace/tags/universal_wrapper.1.3/

ace_lib_distrib # http://***/ace/tags/distribs/5.6.5/ace_lib_distrib
   http://***/ace/tags/distribs/5.6.6/
   http://***/ace/tags/distribs/5.6.7/
   http://***/ace/tags/distribs/5.6.8/
   http://***/ace/tags/distribs/5.7.8/

pcre # http://***/regex/pcre/tags/mxx_ru/7.7/dev/pcre
   http://***/regex/pcre/tags/mxx_ru/7.8/

so_4 # http://***/so_4/tags/4.4.b6/dev/so_4
   # New version not found! Last version is used.

Здесь каждый блок относится к одному подпроекту. Первая строка блока содержит имя каталога, завязанного на подпроект (например, ace и ace_lib_distrib), и текущую версию этого подпроекта. В последующих строках блока перечисляются более свежие версии подпроекта. Если для подпроекта новых версий нет (как в данном примере для so_4), то ничего не перечисляется.

Мне остается только выкинуть из этого файла строки с версиями, которые ему не интересны. Например, мне не интересны версии ace, отличные от 5.6.8, и не интересен so_4, т.к. для него нет новых версий. Я их удаляю и получаю файл вида:

ace # http://***/ace/tags/universal_wrapper.1.2/dev/ace
   http://***/ace/tags/universal_wrapper.1.3/

ace_lib_distrib # http://***/ace/tags/distribs/5.6.5/ace_lib_distrib
   http://***/ace/tags/distribs/5.6.8/

pcre # http://***/regex/pcre/tags/mxx_ru/7.7/dev/pcre
   http://***/regex/pcre/tags/mxx_ru/7.8/

(в принципе, строки для so_4 я мог бы и оставить, они были бы проигнорированы).

Результирующий файл скармливается svn_tag_maker в режиме update – это второй режим ее работы. Получив этот файл svn_tag_maker заменяет в svn:externals для ig_inout_door пути к подпроектам. И новый svn:externals приобретает вид:

ace   http://***/ace/tags/universal_wrapper.1.3/dev/ace
ace_lib_distrib   http://***/ace/tags/distribs/5.6.8/ace_lib_distrib
pcre  http://***/regex/pcre/tags/mxx_ru/7.8/dev/pcre
so_4  http://***/so_4/tags/4.4.b6/dev/so_4

Все, теперь я могу сделать svn up, получить новые версии подпроектов и проверить работоспособность проекта с ними.

Третий режим работы svn_tag_maker – это режим make. В этом режиме программе скармливается рабочая копия проекта и указывается, какую версию нужно создать в репозитории.

Например, пусть я разработал ig_inout_door версии 2.0.3 и мне нужно зафиксировать ее в виде тега. Я запускаю svn_tag_maker и говорю: вот рабочая копия ig_inout_door, версия у нее 2.0.3. После этого svn_tag_maker проверяет, все ли у меня закомичено (чтобы не потерять изменения). И если все нормально, то выполняет svn cp из рабочей копии в раздел tags репозитория – создается ветка tags/2.0.3. При этом для всех svn:externals в tags/2.0.3 будут прописаны точные ревизии подпроектов. Т.е. свойство svn:externals для tags/2.0.3 будет иметь вид:

ace -r346  http://***/ace/tags/universal_wrapper.1.3/dev/ace
ace_lib_distrib -r98  http://***/ace/tags/distribs/5.6.8/ace_lib_distrib
pcre -r13  http://***/regex/pcre/tags/mxx_ru/7.8/dev/pcre
so_4 -r729  http://***/so_4/tags/4.4.b6/dev/so_4

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

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

13 комментариев:

Ctapmex комментирует...

тут главное разобраться какая версия старше. а то бывают разработчики, которые вначале выпускают 1.0.7 (имея ввиду 1.0.07), а потом 1.0.71. либо наоборот.

а при создании метки разве автоматом не проставляется номер ревизии зависимости? если нет, то это для меня прям как удар обухом )

Евгений Охотников комментирует...

> бывают разработчики, которые вначале выпускают 1.0.7 (имея ввиду 1.0.07), а потом 1.0.71. либо наоборот.

Ну у нас 1.0.07 преобразуется в 1.0.7. И 1.0.7 старше (т.е. раньше выпущена), чем 1.0.71. Если нужно сделать обновление ветки 1.0.7, то оно делается под номером 1.0.7.1.

>а при создании метки разве автоматом не проставляется номер ревизии зависимости?

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

Eugeniy комментирует...

Я правильно понимаю, что вы создаете локальные репозитории для сторонних либ? Т.е. вышла новая версия ace, вы ее скачали и закомитили в свой реп ace?
Если так - то вопрос, а что именно из сторонней либы вы храните в репе? Вот например boost - хранить все включая скомпиленные версии либ, только исходники, исходники без доки\тулзов, только нужные мне исходники?
Второй вопрос - компиляция сторонней либы - встраивать ее в свой билд-скрипт?

Евгений Охотников комментирует...

>Я правильно понимаю, что вы создаете локальные репозитории для сторонних либ?

Да. За исключением Qt. Уж больно она большая, чтобы с ней бороться :)

>Т.е. вышла новая версия ace, вы ее скачали и закомитили в свой реп ace?

Да.

>Если так - то вопрос, а что именно из сторонней либы вы храните в репе?

По разному. Для ACE мы храним весь их ace-*.tar.bz2. Для POCO, PCRE и OTL, libcurl и пр. -- исходники. Для PCRE и OTL в отдельные подкаталоги укладываются так же и описания/doc-и (так исторически повелось).

>Вот например boost - хранить все включая скомпиленные версии либ, только исходники, исходники без доки\тулзов, только нужные мне исходники?

Boost мы пока не используем, нам легче :) Однажды что-то из него понадобилось, я вырезал это bcp и хотел закомитить только вырезанные исходники в репозиторий.

Вообще буст такой огромный, что с ним проще поступать как с Qt -- каждый разработчик сам ставит его себе на машину.

>Второй вопрос - компиляция сторонней либы - встраивать ее в свой билд-скрипт?

Да, мы стараемся делать так.

Rubanets Myroslav комментирует...

я на старой работе экстерналов наелся навсегда :)
То есть умом я понимаю что с автопростановкой в тег фиксированных ревизий оно может и будет управляемым, но в памяти картина маслом: для дерева из >50 проектов с 5 уровнями в глубину external это просто ппц. Там это отягощалось хранением бинарей Lib'ов. В общем желаю удачи - но я не с вами :)

Обычно я себе запрещаю писать неконструктивные посты но тут ... это реально убивало в течении всего времени что я там работал - такое врагу не пожелаешь. Ну и к тому же номера ревизий штука хрупкая - при первой же нетривиальной административной операции с историей всего репозитория могут съехать.

Анонимный комментирует...

Возможно, вашему чудо инструменту полезно будет иметь возможность не только обновлять версии зависимостей, но и делать downgrade (т.е. откатываться на предыдущие версии).

Евгений Охотников комментирует...

2Rubanets Myroslav: у нас все строго -- svn:externals может задаваться только для одного каталога dev и все. Поэтому есть только один уровен экстерналсов. Иначе можно придти к тому, о чем ты говоришь.

Евгений Охотников комментирует...

2san: нужно будет подумать... Хотя у меня есть и другие идеи по поводу отслеживания зависимостей между проектами.

Rubanets Myroslav комментирует...

чувствую себя не понятым - папка разумеется одна и в каждом проекте только 1 уровень экстерналов. Просто представьте себе дерево библиотек напоминающее взрыв на макаронной фабрике ... И задержку на секунду/зависимость на каждой операции для крупного старого проекта ...

Евгений Охотников комментирует...

2Rubanets Myroslav: у меня сейчас в проекте 37 зависимостей. Вручную разруливать их, конечно, неприятно. Спасает то, что проекты по объему средние, команда маленькая, часть наших внутренних проектов давно находится в стадии bug-fix-only.

Евгений Охотников комментирует...

2Rubanets Myroslav

>я на старой работе экстерналов наелся навсегда

А что сейчас используется для отслеживания зависимостей между проектами?

Rubanets Myroslav комментирует...

2Евгений:
М>>я на старой работе экстерналов наелся навсегда

Е>А что сейчас используется для отслеживания зависимостей между проектами?
Фирма новая и людей мало. Для отслеживания зависимостей используется русский мат в переводе на бизнис-инглиш. Народ стонет что отправить надо дескать этого деспота на курсы вежливости и все такое но слушаются пока :) Щас сделал авторазворачивание зависимостей под линупс (вдруг пригодится), а для венды по жизни достаточно было распаковать пару архивов. Над бюстом висит полиси - "бинарники через мой труп" :). Один человек в эту схему уже не вписывается - у него UI/qt и тп но он сам себе доктор.
Не исключено что мечта одного нашего архитекта о том что будет шареная папка для каждой платформы станет более актуальна с приходом rhel6 когда количество билдов прыгнет вверх. Ну и на мою радость мы пока забиваем на 2.4кернелы и win64. Там наверное придется брать чтото в стиле cmake|buildbot но я не тороплю события - были у них на шелле кучки скриптов - пусть пока так и будет :)

Евгений Охотников комментирует...

2Rubanets Myroslav: спасибо за ответ.