- PVSM.RU - https://www.pvsm.ru -
Добрый день.
Хочу поделиться способом подстановки в код 1С 7.7 номера ревизии и других значений из рабочей копии SVN.
Реализовать нижеописанное навеяло статьей [1], автору выражаю благодарность за вдохновение.
Торговая сеть средних размеров (примерно 150 магазинов), небольшой коллектив разработчиков, пишем на 1С 7.7, конфигурации в магазинах самописные.
Используется SVN сервер Collabnet Subversion [2], клиент TurtoiseSVN [3], компилятор/декомпилятор метаданных 1С gComp [4]. Есть 1Сная база(мы зовем ее «копирка») из которой мы «раскидываем» обновления и обработки по магазинами. Магазины обновляются автоматом с помощью ConfStarter [5]'а.
Есть несколько самописных Java парсеров для подстановки функций (автологирования) и форматирования кода и пара bat'ников для упрощения работы с ними и с GComp:
"%GCOMP_PATH%gcomp" -c -D .REPO -F 1cv7.compile.md>.compile.log
где REPO — каталог с исходниками в каталоге БД
Каталог, где они живут, включен в PATH, поэтому запускается все это добро прямо из каталога БД 1С, что вполне удобно.
Редко, но все же случались казусы — то не ту сборку (ревизию) закинут, то не с той ветки, то магазин не обновился, и т.п.
Необходимо было реализовать контроль за состоянием магазинов, а именно хотелось иметь достоверную информацию о том, какая именно сборка в каком магазине установлена.
По заданному шаблону получаем данные о рабочей копии с помощью TurtoiseSVN, на выходе получаем другой файл-шаблон со структурой «МаскаДляПоиска» = «ЗначениеДляЗамены» для программки-парсера.
Парсер перебирает файл-шаблон и ищет совпадения в файле с кодом. Маской для поиска является название функции. Если таковая находится — заменяется следующая после нее строчка (которая возвращает значение функции) на «ЗначениеДляЗамены» из шаблона. После этого файл передается дальше на компиляцию. Далее из магазина выгружается файл с данными и передается в офис, где полученная информация обрабатывается и консолидируется.
Для получения данных о рабочей копии используется программа "SubWCRev.exe" из TurtoiseSVN. Она принимает три параметра:
Файл shablon.txt имеет вышеупомянутую структуру «МаскаДляПоиска» = «ЗначениеДляЗамены» и следующие записи:
###
getSVNRevision= Return "$WCREV$";
getSVNURL= Return "$WCURL$";
getSVNBuildTime= Return "$WCNOW$";
На выходе получаем такой же файл, только вместо ключевых слов, указанных между знаками $ подставляются соответствующие значения:
Подробнее о подстановке ключевых слов тут [6]
Программка-парсер была написана на AutoIt [7]. Я назвал ее Replacer. Она принимает два параметра:
Первая строчка в файле с настройками должна иметь значение ### для «защиты от дурака» — чтобы не перепутать порядок файлов. Именно поэтому так сделано в файле shablon.txt
#include "file.au3"
;$CmdLine[0] - это количество переданных параметров.
if $CmdLine[0] <2 Then
MsgBox(0,"error!","Replacer have not all params!")
Exit
EndIf
;Добавляем глобальные переменные
Global $SettingsFilePath = $CmdLine[1]
Global $WorkFilePath = $CmdLine[2]
;Проверяем на существование файл настроек
if FileExists ( $SettingsFilePath) = 0 Then
MsgBox(0, "Error", "Settings File is not exist!.")
exit
EndIf
;Проверяем на существование файл с кодом
if FileExists ( $WorkFilePath ) = 0 Then
MsgBox(0, "Error", "Global Module File is not exist!.")
exit
EndIf
;Открываем файл настроек
Local $Settingsfile = openFile($SettingsfilePath, 0)
Local $T = FileRead($SettingsFilePath,3)
if $T <> "###" Then
MsgBox(0,"Error in the settings file!","Settings file not have in first line a secure code ###")
Exit
EndIf
;Запускаем бесконечный цикл
While 1
;Считываем строку файла настроек
Local $line = FileReadLine($Settingsfile)
;Если неудачно, то выходим
If @error = -1 Then ExitLoop
;Ищем разделитель
Local $SeparatorPos = StringInStr($line, "=")
if $SeparatorPos = 0 Then
;Если не нашли - продолжаем цикл
ContinueLoop
EndIf
;с помощью функции получаем из строки значение для поиска
Local $find = getFindString($line)
;И для замены
Local $replace = getReplaceString($line)
;С помощью функции подменяем значение
___ReplaceStringInFile($WorkFilePath,$find,$replace)
WEnd
FileClose($Settingsfile)
;выходим из программы. Далее указанные функции выполняются только при вызове
exit
;В файле "file.au3" я нашел подходящую функцию, мне осталось только немного модифицировать ее.
;Она читает файл, создает массив строк, в массиве происходит поиск и замена, потом обратно запись из массива в файл.
Func ___ReplaceStringInFile($szFileName, $szSearchString, $szReplaceString, $fCaseness = 0, $fOccurance = 1)
Local $iRetVal = 0
Local $nCount, $sEndsWith
; Check if file is readonly ..
If StringInStr(FileGetAttrib($szFileName), "R") Then Return SetError(6, 0, -1)
;===============================================================================
;== Read the file into an array
;===============================================================================
Local $hFile = FileOpen($szFileName, $FO_READ)
If $hFile = -1 Then Return SetError(1, 0, -1)
Local $s_TotFile = FileRead($hFile, FileGetSize($szFileName))
If StringRight($s_TotFile, 2) = @CRLF Then
$sEndsWith = @CRLF
ElseIf StringRight($s_TotFile, 1) = @CR Then
$sEndsWith = @CR
ElseIf StringRight($s_TotFile, 1) = @LF Then
$sEndsWith = @LF
Else
$sEndsWith = ""
EndIf
Local $aFileLines = StringSplit(StringStripCR($s_TotFile), @LF)
FileClose($hFile)
;===============================================================================
;== Open the output file in write mode
;===============================================================================
Local $iEncoding = FileGetEncoding($szFileName)
Local $hWriteHandle = FileOpen($szFileName, $iEncoding + $FO_OVERWRITE)
If $hWriteHandle = -1 Then Return SetError(2, 0, -1)
;===============================================================================
;== Loop through the array and search for $szSearchString
;===============================================================================
local $needReplace = 0
For $nCount = 1 To $aFileLines[0]
;тут я добавил проверку на необходимость замены строки
if $needReplace = 1 Then
;подменяем содержимое строки и выходим из цикла
$aFileLines[$nCount] = $szReplaceString
ExitLoop
EndIf
;Если нашли значение в строке
If StringInStr($aFileLines[$nCount], $szSearchString, $fCaseness) Then
;Тут я закомментировал оригинальную строку
;$aFileLines[$nCount] = StringReplace($aFileLines[$nCount], $szSearchString, $szReplaceString, 1 - $fOccurance, $fCaseness)
;"Включаю" переменную needReplace и при следующей итерации цикла произойдет замена. Как раз то что нужно.
$needReplace = 1
$iRetVal = $iRetVal + 1
;======================================================================
;== If we want just the first string replaced, copy the rest of the lines
;== and stop
;======================================================================
If $fOccurance = 0 Then
$iRetVal = 1
ExitLoop
EndIf
EndIf
Next
;===============================================================================
;== Write the lines back to original file.
;===============================================================================
For $nCount = 1 To $aFileLines[0] - 1
If FileWriteLine($hWriteHandle, $aFileLines[$nCount]) = 0 Then
FileClose($hWriteHandle)
Return SetError(3, 0, -1)
EndIf
Next
; Write the last record and ensure it ends with the same as the input file
If $aFileLines[$nCount] <> "" Then FileWrite($hWriteHandle, $aFileLines[$nCount] & $sEndsWith)
FileClose($hWriteHandle)
Return $iRetVal
EndFunc
;открываем файл
Func openFile($FilePath,$mode)
Local $file = FileOpen($FilePath, $mode)
If $file = -1 Then
MsgBox(0, "Error", "Unable to open file." $FilePath)
exit
Else
Return $file
EndIf
EndFunc
;ищем разделитель, возвращаем все, что до него
Func getFindString($inString)
Return StringLeft($inString, StringInStr($inString, "=")-1)
EndFunc
;А тут все, что после него
Func getReplaceString($inString)
Return StringRight($inString, StringLen($inString)- StringInStr($inString, "="))
EndFunc
Для автоматизации всех этих действий я создал bat'ник "getRevision.bat", параметром в него передается папка, где находится глобальный модуль (это BUILD или REPO).
REM На всякий пожарный проверяется существование папки с исходниками
if not exist .REPO (
echo FAIL: REPO folder isn't exist!
pause
exit /b 1
)
REM и файла-шаблона.
if not exist "%~dp0shablon.txt" (
echo FAIL: Shablon isn't exist!
pause
exit /b 2
)
REM Запускаем SubWCRev.exe, получаем шаблон для парсера
"c:Program FilesTortoiseSVNbinSubWCRev.exe" .REPO "%~dp0shablon.txt" .ReplacerSettings.txt -f
REM Запускаем парсер, подменяем значение функций в глобальном модуле
"%~dp0Replacer.exe" ".ReplacerSettings.txt" "%1ГлобальныйМодуль.1s"
REM выпиливаем шаблон для парсера
del ".ReplacerSettings.txt"
Вызов getRevision.bat был добавлен в Build.bat, а так как Build.bat предварительно копирует исходники в отдельную папку BUILD и она же указывается параметром для getRevision.bat подмена значений никак не отражается в папке REPO с исходниками и соответственно изменения не попадают в SVN, что для меня очень удобно.
По просьбе коллег был создан отдельный bat'ник — СompileSVN.bat
Как можно понять по называнию, он делает подмену значений в оригинальной папке с исходниками и запускает компиляцию. Его содержимое:
@echo Установка значений SVN в глобальный модуль...
@echo off
call getrevision.bat .REPO
@echo Компиляция файлов из папки REPO в 1cv7.compile.md...
"%GCOMP_PATH%gcomp" -c -D .REPO -F 1cv7.compile.md>.compile.log
Compile.bat остался без изменений
Чтобы парсеру было что искать, вставляем в глобальный модуль функции «пустышки»
//-------------------------------------------------
Функция getSVNRevision() Экспорт
Возврат 0;
КонецФункции
//-------------------------------------------------
Функция getSVNURL() Экспорт
Возврат 0;
КонецФункции
//-------------------------------------------------
Функция getSVNBuildTime() Экспорт
Возврат 0;
КонецФункции
//-------------------------------------------------
Если запустить CompileSVN.bat и посмотреть изменения в коммите, можно увидеть следующее:
(некоторые данные изменены):
//-------------------------------------------------
Функция getSVNRevision() Экспорт
Return "5135";
КонецФункции
//-------------------------------------------------
Функция getSVNURL() Экспорт
Return "https://сервер:порт/svn/trunk";
КонецФункции
//-------------------------------------------------
Функция getSVNBuildTime() Экспорт
Return "2013/01/22 10:35:15";
КонецФункции
//-------------------------------------------------
Так же в глобальный модуль была добавлена процедура для выгрузки данных из магазина
Процедура глВыгрузитьMD_INFO() Экспорт
ВремяПоследнейЗаписи = "";
Попытка
ФС.АтрибутыФайла( КаталогИБ() + "1CV7.MD", , , , , ВремяПоследнейЗаписи, );
Исключение
КонецПопытки;
Текст = СоздатьОбъект( "Текст" );
Текст.ДобавитьСтроку( "###MD Info" );
Текст.ДобавитьСтроку( "SVN_Revision: " + getSVNRevision() );
Текст.ДобавитьСтроку( "SVN_URL: " + getSVNURL() );
Текст.ДобавитьСтроку(
"SVN_BuildTime: " +
СтрЗаменить( getSVNBuildTime(), "/", "." )
);
Текст.ДобавитьСтроку( "MD_UpdateTime: " + ВремяПоследнейЗаписи );
Текст.ДобавитьСтроку( "### Константы: " );
Текст.ДобавитьСтроку( "Магазин: " + СокрЛП( Константа.Магазин ) );
Текст.ДобавитьСтроку( "КодМагазина: " + СокрЛП( Константа.КодМагазина ) );
Попытка
Текст.Записать(
глПолучитьПапкуОбмена_Исходящие() +
"" +
глПравильноеИмяФайлаДляОбмена( "MDInfo", "" )
);
Исключение
КонецПопытки;
КонецПроцедуры
Выгружается такой вот файлик (некоторые данные изменены):
### MD Info
SVN_Revision: 5137
SVN_URL: https://сервер:порт/svn/branches/имя_ветки
SVN_BuildTime: 2013.01.21 13:45:44
MD_UpdateTime: 2013.01.22 05:02:52
### Константы:
Магазин: Имя_магазина
КодМагазина: 24
Файл записывается в папку для обмена, потом передается на FTP сервер. Оттуда наша база «Копирка» будет собирать эти файлы и полученные данные записывать в базу.
Для удобства коллективного обновления скриптов был использован инсталятор inno setup [8], подробно описывать его нет смысла — там все просто и есть хороший help.
При небольших манипуляциях вышеописанное вполне легко можно приспособить под любой другой язык программирования.
Благодарю за внимание.
Автор: RootOfLife
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/svn/25511
Ссылки в тексте:
[1] статьей: http://habrahabr.ru/post/157197/
[2] Collabnet Subversion: http://www.collab.net/downloads/subversion
[3] TurtoiseSVN: http://tortoisesvn.net/downloads.html
[4] gComp: http://1c.alterplast.ru/gcomp/
[5] ConfStarter: http://infostart.ru/public/14304/
[6] тут: http://tortoisesvn.net/docs/nightly/TortoiseSVN_ru/tsvn-subwcrev-keywords.html
[7] AutoIt: http://www.autoitscript.com/site/autoit/downloads/
[8] inno setup: http://www.jrsoftware.org/isdl.php
[9] Источник: http://habrahabr.ru/post/166769/
Нажмите здесь для печати.