/////////////////////////////////////////////////////////// // GGBuildTools // // Набор утилит для сборки проектов Gipat Group // // Copyright (C) 2007 Gipat Group // // Распространяется на условиях // // Gipat Group's opened EI-editor-utility license // // версии 1.0 // // // // www.gipatgroup.org // /////////////////////////////////////////////////////////// //К работе над данным файлом приложили руки, ноги.... короче аффтары: // 1) Sagrer (sagrer@yandex.ru) //////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// // Класс для логики (т.е. того что не зависит // // от интерфейса) софтины вроде VerRevUpdater // /////////////////////////////////////////////////////////////// unit VerRevUpdLogic; {$mode objfpc}{$H+} interface uses Classes, SysUtils, SconfFormat, VerInfoTxtFormat, LCLTextFileInString, ExtraFileUtilsLCL, Dialogs, ExtraFunctionsLCL, SvnInfoReader, LCLAnIniFile; type FPostExternalMessage = procedure(const TextMessage : AnsiString) of object; //Тип функции для вызова внешней функции вывода мессаги. TVerRevUpdaterLogic = class //Класс, реально выполняющий работу софтины, по идее независим от интерфейса private protected //Переменные. SconfFilePath : AnsiString; //Полный путь к загруженному sconf-файлу. ProjectName : AnsiString; //Имя проекта. ProjectLocalRoot : AnsiString; //Локальный путь к проекту. ProjectGlobalRoot : AnsiString; //Глобальный путь к проекту. ProjectSconf : TSconfFormat; //Для инфы из sconf проекта. ProjectVit : TVerInfoTxtFormat; //Для инфы из\для *.vit CodeFile : TTextFileInString; //Для инфы, "руками" записываемой в *.pas или *.h или что-то аналогичное. //Защищенные методы. function UpdateVerInfoTxtOnlyProj() : Boolean; //Обновить версию проекта VerInfoTxtOnly. function UpdatePascalCodeProj() : Boolean; //Обновить версию проекта PascalCode. function UpdateCppCodeProj() : Boolean; //Обновить версию проекта CppCode. public //Переменные. ErrorMessage : AnsiString; //Мессага про ошибку. PostExternalMessage : FPostExternalMessage; //Функция, воспринимающая сообщения от выполняющегося процесса. //Конструкторы-деструкторы... constructor Create; virtual; destructor Destroy; override; //Открытые методы... function UpdateProjVer(const FullSconfFilePath : AnsiString) : Boolean; //Собсно обновить версию для проекта с указанным *.sconf-файлом. end; implementation ///////////////////////////////////////////// // TVerRevUpdaterLogic // ///////////////////////////////////////////// //-----------------------------------------// // Конструкторы-деструкторы... // //-----------------------------------------// constructor TVerRevUpdaterLogic.Create; begin //Проставить дефолтные значения... //Просто забить инфу в переменные... SconfFilePath := ''; ErrorMessage := ''; //Создать вложенные объекты классов... ProjectSconf := TSconfFormat.Create; ProjectVit := TVerInfoTxtFormat.Create; CodeFile := TTextFileInString.Create; end; destructor TVerRevUpdaterLogic.Destroy; begin //Выкидываем мусор ProjectSconf.Free; ProjectVit.Free; CodeFile.Free; //Выполнить унаследованный деструктор inherited; end; //------------------------------------------// // Защищенные методы... // //------------------------------------------// function TVerRevUpdaterLogic.UpdateVerInfoTxtOnlyProj() : Boolean; //Обновить версию проекта VerInfoTxtOnly. begin //Фсе элементарно - банально сохранить *.vit-файлег в директорию с прогой. Result := Self.ProjectVit.Save(Self.ProjectLocalRoot+Self.ProjectName+'.vit'); if Result = true then begin Self.PostExternalMessage('Saved file '+Self.ProjectLocalRoot+Self.ProjectName+'.vit'); end else begin //По неизвестной причине засавить не удалось. Self.PostExternalMessage('Cant save file '+Self.ProjectLocalRoot+Self.ProjectName+'.vit'); Self.ErrorMessage := 'Cant save file '+Self.ProjectLocalRoot+Self.ProjectName+'.vit'; end; end; function TVerRevUpdaterLogic.UpdatePascalCodeProj() : Boolean; //Обновить версию проекта PascalCode. var CodeTextFile : TTextFileInString; begin //Сначала обновить vit. Result := Self.UpdateVerInfoTxtOnlyProj(); //Если все ок - продолжаем. if Result = true then begin //Создадим новый текстовик и забросим в него мегапаскалевский мегамодуль с мегаинфой % ))). CodeTextFile := TTextFileInString.Create; CodeTextFile.MakNewFile; //Кидаем инфу % )). CodeTextFile.AddStr('/////////////////////////////////////////////////////////////////////////////'); CodeTextFile.AddStr('// This file was generated automatically by VerRevUpdater. //'); CodeTextFile.AddStr('// It includes a version number for this application. //'); CodeTextFile.AddStr('// Please, don''t modify it manually - it''ll be recreated next build. //'); CodeTextFile.AddStr('/////////////////////////////////////////////////////////////////////////////'); CodeTextFile.AddStr('unit '+Self.ProjectName+'_ver;'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('interface'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('const'); CodeTextFile.AddStr(' '+Self.ProjectName+'_Ver1 = '+IntToStr(Self.ProjectVit.Ver1)+';'); CodeTextFile.AddStr(' '+Self.ProjectName+'_Ver2 = '+IntToStr(Self.ProjectVit.Ver2)+';'); CodeTextFile.AddStr(' '+Self.ProjectName+'_Ver3 = '+IntToStr(Self.ProjectVit.Ver3)+';'); CodeTextFile.AddStr(' '+Self.ProjectName+'_Ver4 = '+IntToStr(Self.ProjectVit.Ver4)+';'); CodeTextFile.AddStr(' '+Self.ProjectName+'_Status = '+IntToStr(Self.ProjectVit.Status)+';'); CodeTextFile.AddStr(' '+Self.ProjectName+'_RCNum = '+IntToStr(Self.ProjectVit.RCNum)+';'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('implementation'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('end.'); //Сохраняем. CodeTextFile.Save(Self.ProjectLocalRoot+Self.ProjectName+'_ver.pas'); Self.PostExternalMessage('Saved file '+Self.ProjectLocalRoot+Self.ProjectName+'_ver.pas'); //Не забыть выкинуть мусор. CodeTextFile.Free; end; end; function TVerRevUpdaterLogic.UpdateCppCodeProj() : Boolean; //Обновить версию проекта CppCode. var CodeTextFile : TTextFileInString; begin //Сначала обновить vit. Result := Self.UpdateVerInfoTxtOnlyProj(); //Если все ок - продолжаем. if Result = true then begin //Создадим новый текстовик и забросим в него мегапаскалевский мегамодуль с мегаинфой % ))). CodeTextFile := TTextFileInString.Create; CodeTextFile.MakNewFile; //Кидаем инфу % )). CodeTextFile.AddStr('/////////////////////////////////////////////////////////////////////////////'); CodeTextFile.AddStr('// This file was generated automatically by VerRevUpdater. //'); CodeTextFile.AddStr('// It includes a version number for this application. //'); CodeTextFile.AddStr('// Please, don''t modify it manually - it''ll be recreated next build. //'); CodeTextFile.AddStr('/////////////////////////////////////////////////////////////////////////////'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('#ifndef '+UpperCase(Self.ProjectName)+'_VER_H_INCLUDED'); CodeTextFile.AddStr('#define '+UpperCase(Self.ProjectName)+'_VER_H_INCLUDED'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('const int '+Self.ProjectName+'_Ver1 = '+IntToStr(Self.ProjectVit.Ver1)+';'); CodeTextFile.AddStr('const int '+Self.ProjectName+'_Ver2 = '+IntToStr(Self.ProjectVit.Ver2)+';'); CodeTextFile.AddStr('const int '+Self.ProjectName+'_Ver3 = '+IntToStr(Self.ProjectVit.Ver3)+';'); CodeTextFile.AddStr('const int '+Self.ProjectName+'_Ver4 = '+IntToStr(Self.ProjectVit.Ver4)+';'); CodeTextFile.AddStr('const int '+Self.ProjectName+'_Status = '+IntToStr(Self.ProjectVit.Status)+';'); CodeTextFile.AddStr('const int '+Self.ProjectName+'_RCNum = '+IntToStr(Self.ProjectVit.RCNum)+';'); CodeTextFile.AddStr(''); CodeTextFile.AddStr('#endif // '+UpperCase(Self.ProjectName)+'_VER_H_INCLUDED'); //Сохраняем. CodeTextFile.Save(Self.ProjectLocalRoot+Self.ProjectName+'_ver.h'); Self.PostExternalMessage('Saved file '+Self.ProjectLocalRoot+Self.ProjectName+'_ver.h'); //Не забыть выкинуть мусор. CodeTextFile.Free; end; end; //------------------------------------------// // Открытые методы... // //------------------------------------------// function TVerRevUpdaterLogic.UpdateProjVer(const FullSconfFilePath : AnsiString) : Boolean; //Собсно обновить версию для проекта с указанным *.sconf-файлом. var SvnReader : TSvnInfoReader; TempVit : TVerInfoTxtFormat; begin //Инициализация. Result := true; //Читаем Sconf. Self.PostExternalMessage('Reading sconf from '+FullSconfFilePath); Result := Self.ProjectSconf.Load(FullSconfFilePath); if Result = true then begin //Ок. Смотрим - подлежит ли версия обновлению - это возможно только если в версии проекта //стоит слово "Project" Self.PostExternalMessage('Readed.'); if LowerCase(Self.ProjectSconf.MainSection.ProjectVer) = 'project' then begin //Ога. Оно. Получаем имя проекта, глобальный и локальный пути. Self.ProjectName := GetFileNameWithoutExtension(FullSconfFilePath); Self.ProjectLocalRoot := AddLastSlash(Self.ProjectSconf.MainSection.ProjectRootDir); Self.ProjectGlobalRoot := ResolveLocalPath(Self.ProjectLocalRoot,ExtractFilePath(FullSconfFilePath)); //Продолжаем - читаем *.vit-файл. Self.PostExternalMessage('Reading version from'+Self.ProjectLocalRoot+Self.ProjectName+'_dev.vit'); Result := Self.ProjectVit.Load(Self.ProjectLocalRoot+Self.ProjectName+'_dev.vit'); //to be continued - следующая серия - на корневом уровне функции ниже, под if-ом проверяющим Result %). end else begin Self.PostExternalMessage('Project don''t using VerRevUpdating. Nothing to do.'); Exit; end; end else begin //Не удалось прочитать файл. Self.ErrorMessage := 'Cant load '+FullSconfFilePath; end; //Прочитался ли vit-файл? if Result = true then begin //Прочитался. Self.PostExternalMessage('Readed. Version is '+Self.ProjectVit.GenerateVersionString()); //Теперь если нужно - обновим инфу из SVN. if Self.ProjectSconf.MainSection.UseSvn = true then begin //Читаем инфу. Self.PostExternalMessage('Reading SVN revision.'); SvnReader := TSvnInfoReader.Create; Self.ProjectVit.Ver4 := SvnReader.GetSvnDirRevision(Self.ProjectLocalRoot); //Если ревизия 0 - значит была ошибка - её стоит запостить. if Self.ProjectVit.Ver4 = 0 then begin Self.PostExternalMessage(SvnReader.ErrorMessage); //А йесчО попытаемся прочитать номер ревизии из [имя проекта].vit если таковой в наличии. if FileExists(Self.ProjectLocalRoot+Self.ProjectName+'.vit') = true then begin //Ага, есть файлег. Читаем. TempVit := TVerInfoTxtFormat.Create; if TempVit.Load(Self.ProjectLocalRoot+Self.ProjectName+'.vit') = true then begin Self.ProjectVit.Ver4 := TempVit.Ver4; Self.PostExternalMessage('Revision restored from old '+Self.ProjectLocalRoot+Self.ProjectName+'.vit file.'); end; TempVit.Free; end; end; Self.PostExternalMessage('Revision is '+IntToStr(Self.ProjectVit.Ver4)+'. Version will be '+Self.ProjectVit.GenerateVersionString()); //Не забыть убрать мусор. SvnReader.Free; end; //Так. Дальше - собсно уже действуем в зависимости от того, какой тип проекта у нас тут. if Self.ProjectSconf.MainSection.ProjectType = ScF_ProjectType_VerInfoTxtOnly then begin //Только vit. Self.PostExternalMessage('Updating VerInfoTxtOnly project.'); Result := Self.UpdateVerInfoTxtOnlyProj(); end else if Self.ProjectSconf.MainSection.ProjectType = ScF_ProjectType_PascalCode then begin //Паскаль. Self.PostExternalMessage('Updating PascalCode project.'); Result := Self.UpdatePascalCodeProj(); end else if Self.ProjectSconf.MainSection.ProjectType = ScF_ProjectType_CppCode then begin //ЦыПыПы %). Self.PostExternalMessage('Updating CppCode project.'); Result := Self.UpdateCppCodeProj(); end; end; end; end.