Когда постоянно выпускаешь новые релизы приходится заботится о нумерации версии выпущенного программного обеспечения. Конечно же версию можно просто выдумать, что большинство и делает (да и я в том числе так делал до тех пор, пока случайно не забыл обновить номер версии программы и в итоге получилось что 2 разные программы имели ту же самую версию, а это ОЧЕНЬ плохо). Обязательно наступит тот момент, когда к Вам обратятся пользователи Вашего творения с «претензиями» или же перечнем багов. Вот тут то и начнется самое интересное, ведь нужно провести расследование с использованием исходного кода программы. Где же брать этот код ведь мы имеем дело с множеством ревизий и оправданно возникает вопрос: «К какой ревизии относится конкретная версия программы?». Если в программе явно указывать ревизию — то проблема тривиальна. Просто смотрим версию проблемной программы, скачиваем полученную из версии программы ревизию с репозитория и разбираемся, что же не так. Осуществлять нумерацию возможно и вручную, но в этом случае будет присутствовать человеческий фактор в виде возможной ошибки. Да и вовсе неудобно каждый раз перед заливкой новых изменений на репозиторий вписывать версию репозитория в исходные коды программы. Есть способ получше! Он заключается в автоматическом вызове скрипта на этапе заливки исходников на репозиторий…

Механизм работы. Мы хотим иметь возможность в программе (из исходных кодов) получать доступ к переменной, которая бы содержала строку версии программы (данная строка, например, может быть выведена в окне «О программе»). Как вариант, данную переменную можно хранить в заголовочном файле. С другой стороны, каким то образом сей файл должен быть кем то или чем то создан в автоматическом режиме (ведь мы не хотим создавать его вручную). Это возможно осуществить с помощью программы TortoiseSVN. Данная программа обладает возможностью вызывать пользовательский скрипт в тот момент, когда пользователь решил залить изменения исходных кодов на репозиторий. Итого, последовательность действий:
— Пытаемся выполнить действие «SVN Commit»;
— В этот момент вызывается скрипт, который получает текущую версию исходников и генерирует заголовочный файл, который содержит строку версии программы;

В нашем случае, для генерации заголовочного файла ревизии, мы воспользуемся утилитой SubWCRev (из пакета TortoiseSVN). О данной утилите в документации написано следующее: «SubWCRev is Windows console program which can be used to read the status of a Subversion working copy and optionally perform keyword substitution in a template file. This is often used as part of the build process as a means of incorporating working copy information into the object you are building. Typically it might be used to include the revision number in an “About” box.». Это значит, что мы обратились по адресу. Это именно та утилита, которая умеет читать статус (в том числе версию) рабочей копии репозитория SVN и вместе с этим генерировать файл по шаблону, подставляя значения полученных переменных в результирующий файл.

Во избежание недоразумений, работу с автоматизированой системой генерации файла версии рассмотрим на примере.

Содержимое шаблона (файл Revision.templ):

#pragma once
// Базовая версия программы
#define BASE_PROGRAM_VERSION "1.0.9"
// Дополнительная версия программы (значение будет подставленно вместо $WCREV$ утилитой SubWCRev.exe)
#define ADDITIONAL_PROGRAM_VERSION "$WCREV$"
// Тип выпускаемого релиза (pre-alpha, alpha, beta, rc, rtm...)
#define RELEASE_TYPE "beta"
// Желаемый формат строки версии
#define PROGRAM_VERSION BASE_PROGRAM_VERSION##"."##ADDITIONAL_PROGRAM_VERSION##" "##RELEASE_TYPE

Содержимое скрипта, который должен быть вызван TortoiseSVN на какой-либо этапе заливки исходников на репозиторий (файл RevisionUpdate.bat):

:: Символ "лапка"
set LAPKA="
:: Получаем абсолютный путь, где находится данный скрипт
set UPATH=%~dp0
:: Заменяем символы backslash-ов на forwardslash-и (это нужно для корректной работы программы SubWCRev.exe)
set UPATH=%UPATH:\=/%
:: Указываем имя шаблонного файла
set TEMPLATE=Revision.templ
:: Указываем имя результирующего файла
set FILE=Revision.h

:: Обновляем ревизию в заголовочный файл
SubWCRev.exe %LAPKA%%UPATH%%LAPKA% %LAPKA%%UPATH%%TEMPLATE%%LAPKA% %LAPKA%%UPATH%%FILE%%LAPKA%

Добавляем на репозиторий файлы скрипта и шаблона. Открываем настройки TortoiseSVN. SettingsTortoiseSVN

Переходим в меню «Hook Scripts». Нажимаем кнопку «Add».
SettingsHookScriptsAdd

«Hook Type». Выбираем тип хука по которому должен быть выполнен вызов скрипта.
«Working Copy Path». Выбираем директорию, за которой должен следить TortoiseSVN.
«Command Line To Execute». Выбираем файл скрипта, который должен быть выполнен по событию хука.
Устанавливаем опции доступные через CheckBox-ы и сохраняем изменения.
Pre-CommitHook

Вручную запускаем скрипт. В результате должен появится заголовочный файл. Добавляем все файлы на репозиторий.
ScriptTemplateAndGeneratedFile

Производим заливку изменений на репозиторий SVN.
FirstCommit

Теперь, для теста, добавляем новый файл и пытаемся уже его залить на репозиторий.
SecondCommit

После успешной заливки можно просмотреть лог.
LogAfterSecondCommit

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

Ко всему сказанному… Для того, чтобы изложенный пример автоматизированной описанной в статье системы успешно заработал, необходимо установить TortoiseSVN (мне это подсказал капитан Очевидность:).
TortoiseSVN должен быть добавлен в PATH (можете не переживать, это делается автоматически при его установке, но если что-то пойдет не так — советую проверить PATH вручную и при необходимости прописать программу).

P.S. В данном посте описан пример использования скриптов на клиентской стороне, но делать это можно и на стороне сервера (но это уже совсем другая история:).

Файлы к статье

Скачать файлы