Мой подчиненный, молодой 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 комментариев:
тут главное разобраться какая версия старше. а то бывают разработчики, которые вначале выпускают 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 коммитов больше не делают.
Я правильно понимаю, что вы создаете локальные репозитории для сторонних либ? Т.е. вышла новая версия ace, вы ее скачали и закомитили в свой реп ace?
Если так - то вопрос, а что именно из сторонней либы вы храните в репе? Вот например boost - хранить все включая скомпиленные версии либ, только исходники, исходники без доки\тулзов, только нужные мне исходники?
Второй вопрос - компиляция сторонней либы - встраивать ее в свой билд-скрипт?
>Я правильно понимаю, что вы создаете локальные репозитории для сторонних либ?
Да. За исключением Qt. Уж больно она большая, чтобы с ней бороться :)
>Т.е. вышла новая версия ace, вы ее скачали и закомитили в свой реп ace?
Да.
>Если так - то вопрос, а что именно из сторонней либы вы храните в репе?
По разному. Для ACE мы храним весь их ace-*.tar.bz2. Для POCO, PCRE и OTL, libcurl и пр. -- исходники. Для PCRE и OTL в отдельные подкаталоги укладываются так же и описания/doc-и (так исторически повелось).
>Вот например boost - хранить все включая скомпиленные версии либ, только исходники, исходники без доки\тулзов, только нужные мне исходники?
Boost мы пока не используем, нам легче :) Однажды что-то из него понадобилось, я вырезал это bcp и хотел закомитить только вырезанные исходники в репозиторий.
Вообще буст такой огромный, что с ним проще поступать как с Qt -- каждый разработчик сам ставит его себе на машину.
>Второй вопрос - компиляция сторонней либы - встраивать ее в свой билд-скрипт?
Да, мы стараемся делать так.
я на старой работе экстерналов наелся навсегда :)
То есть умом я понимаю что с автопростановкой в тег фиксированных ревизий оно может и будет управляемым, но в памяти картина маслом: для дерева из >50 проектов с 5 уровнями в глубину external это просто ппц. Там это отягощалось хранением бинарей Lib'ов. В общем желаю удачи - но я не с вами :)
Обычно я себе запрещаю писать неконструктивные посты но тут ... это реально убивало в течении всего времени что я там работал - такое врагу не пожелаешь. Ну и к тому же номера ревизий штука хрупкая - при первой же нетривиальной административной операции с историей всего репозитория могут съехать.
Возможно, вашему чудо инструменту полезно будет иметь возможность не только обновлять версии зависимостей, но и делать downgrade (т.е. откатываться на предыдущие версии).
2Rubanets Myroslav: у нас все строго -- svn:externals может задаваться только для одного каталога dev и все. Поэтому есть только один уровен экстерналсов. Иначе можно придти к тому, о чем ты говоришь.
2san: нужно будет подумать... Хотя у меня есть и другие идеи по поводу отслеживания зависимостей между проектами.
чувствую себя не понятым - папка разумеется одна и в каждом проекте только 1 уровень экстерналов. Просто представьте себе дерево библиотек напоминающее взрыв на макаронной фабрике ... И задержку на секунду/зависимость на каждой операции для крупного старого проекта ...
2Rubanets Myroslav: у меня сейчас в проекте 37 зависимостей. Вручную разруливать их, конечно, неприятно. Спасает то, что проекты по объему средние, команда маленькая, часть наших внутренних проектов давно находится в стадии bug-fix-only.
2Rubanets Myroslav
>я на старой работе экстерналов наелся навсегда
А что сейчас используется для отслеживания зависимостей между проектами?
2Евгений:
М>>я на старой работе экстерналов наелся навсегда
Е>А что сейчас используется для отслеживания зависимостей между проектами?
Фирма новая и людей мало. Для отслеживания зависимостей используется русский мат в переводе на бизнис-инглиш. Народ стонет что отправить надо дескать этого деспота на курсы вежливости и все такое но слушаются пока :) Щас сделал авторазворачивание зависимостей под линупс (вдруг пригодится), а для венды по жизни достаточно было распаковать пару архивов. Над бюстом висит полиси - "бинарники через мой труп" :). Один человек в эту схему уже не вписывается - у него UI/qt и тп но он сам себе доктор.
Не исключено что мечта одного нашего архитекта о том что будет шареная папка для каждой платформы станет более актуальна с приходом rhel6 когда количество билдов прыгнет вверх. Ну и на мою радость мы пока забиваем на 2.4кернелы и win64. Там наверное придется брать чтото в стиле cmake|buildbot но я не тороплю события - были у них на шелле кучки скриптов - пусть пока так и будет :)
2Rubanets Myroslav: спасибо за ответ.
Отправить комментарий