Delphi工程版本号修改工具
自动修改某目录下符合条件的Delphi工程(dproj)版本号, 支持命令行调用
支持通配符忽略文件
-p [Path] 在[Path]路径下查询所有dproj文件(可以为空, 默认路径为程序当前路径)
-v [Version] 将查询到的dproj文件中Base节点版本改为[Version]并删除其他节点版本信息(可以为空, 进入程序后输入)
-i [File1,File2...]要忽略的文件, 支持? *的通配符, 忽略大小写, 包含路径, 不要包含扩展名, 如: work\project?
-b 修改时备份原文件到文件所在路径的dproj_bak目录下(默认不备份)
-ac 工作结束自动关闭程序(默认不关闭)
已经编译完的程序放CSDN了, 不过有点坑, 提交的资源不能修改内容, 也不能修改下载积分(当初没看, 直接选了5分...呵呵)
http://download.csdn.net/download/hskill/10120236
下面直接给出源码, 是个控制台程序
PS: 里面用到了QXML, 但是QXML会吧单引号转义, 不过不影响IDE的读取保存
program dproj_Version; // *************************************************************************** // // 版本: 1.0 // 作者: 刘志林 // 修改日期: 2017-11-15 // QQ: 17948876 // E-mail: lzl_17948876@hotmail.com // 博客: http://www.cnblogs.com/lzl_17948876/ // // !!! 若有修改,请通知作者,谢谢合作 !!! // // *************************************************************************** {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes, System.IOUtils, System.Types, System.Masks, QXML, QString; function _GetXNode(AXNParent: TQXMLNode; AName: string; out AValue: string): TQXMLNode; begin Result := AXNParent.ItemByName(AName); if Result = nil then Result := AXNParent.Add(AName); AValue := Result.Text; end; type EInvalidVersion = Class(Exception); TVersion = record public procedure Init; function IsEmpty: Boolean; procedure FromString(AStr: string); function ToString(ADelimiter: Char = '.'): string; case Integer of 0: (Data: array[0..3] of UInt32); 1: (MajorVer, MinorVer, Release, Build: UInt32); end; { TVersion } procedure TVersion.FromString(AStr: string); var i: Integer; begin Init; with TStringList.Create do try Delimiter := '.'; StrictDelimiter := True; DelimitedText := AStr; try if Count <> 4 then Abort; for i := 0 to 3 do Data[i] := StrToInt(Strings[i]); if IsEmpty then Abort; except Init; raise EInvalidVersion.Create(AStr + '不是有效的版本号'); end; finally Free; end; end; procedure TVersion.Init; begin MajorVer := 0; MinorVer := 0; Release := 0; Build := 0; end; function TVersion.IsEmpty: Boolean; begin Result := Data[0] + Data[1] + Data[2] + Data[3] = 0; end; function TVersion.ToString(ADelimiter: Char = '.'): string; begin Result := Format('%1:d%0:s%2:d%0:s%3:d%0:s%4:d', [ADelimiter, Data[0], Data[1], Data[2], Data[3]]) end; function _Compare(const AStr: string; const AL: array of string): Boolean; var i: Integer; begin Result := False; for i := Low(AL) to High(AL) do begin if CompareText(AStr, AL[i]) <> 0 then Continue; Result := True; Break; end; end; function IsIgnored(AName: string; const AIGList: TArray<string>): Boolean; var i: Integer; begin Result := False; for i := Low(AIGList) to High(AIGList) do begin if not MatchesMask(AName, AIGList[i]) then Continue; Result := True; Break; end; end; const _EXT = '.dproj'; const Helps: array[0..4] of string = ( '-p [Path] 在[Path]路径下查询所有dproj文件(可以为空, 默认路径为程序当前路径)', '-v [Version] 将查询到的dproj文件中Base节点版本改为[Version]并删除其他节点版本信息(可以为空, 进入程序后输入)', '-i [File1,File2...]要忽略的文件, 支持? *的通配符, 忽略大小写, 包含路径, 不要包含扩展名, 如: work\project?', '-b 修改时备份原文件到文件所在路径的dproj_bak目录下(默认不备份)', '-ac 工作结束自动关闭程序(默认不关闭)' ); var nXDOC: TQXML; nXNRoot, nXN, nXNV: TQXMLNode; l, i, nParamIndex, nFileIndex, nXNIndex, nIKIndex: Integer; nStrs: TStringList; nName, nVersionStr, nPath, nFile, nStr, nPK: string; nIgnoredList: TArray<string>; nVersion, nOldVersion: TVersion; nFiles: TStringDynArray; nBackup, nAutoClose: Boolean; begin try { TODO -oUser -cConsole Main : Insert code here } ChDir(ExtractFilePath(ParamStr(0))); nPath := '.\'; nVersion.Init; SetLength(nIgnoredList, 0); nBackup := False; nAutoClose := False; nParamIndex := 1; while nParamIndex <= ParamCount do begin nStr := ParamStr(nParamIndex); l := nStr.Length; if not (nStr[1] in ['-', '/']) then Continue; nStr := Copy(nStr, 2, l - 1); if _Compare(nStr, ['p']) then {路径} begin nPath := ParamStr(nParamIndex + 1); Inc(nParamIndex, 2); end else if _Compare(nStr, ['v']) then {版本号} begin nVersionStr := ParamStr(nParamIndex + 1); Inc(nParamIndex, 2); end else if _Compare(nStr, ['i']) then {忽略的文件} begin with TStringList.Create do try StrictDelimiter := True; Delimiter := ','; DelimitedText := ParamStr(nParamIndex + 1); SetLength(nIgnoredList, Count); for i := 0 to Count - 1 do nIgnoredList[i] := '*' + ChangeFileExt(Strings[i], '') + _EXT; finally Free; end; Inc(nParamIndex, 2); end else if _Compare(nStr, ['b']) then {备份} begin nBackup := True; Inc(nParamIndex, 1); end else if _Compare(nStr, ['ac']) then {自动关闭} begin nAutoClose := True; Inc(nParamIndex, 1); end else if _Compare(nStr, ['h', '?', 'help']) then {帮助} begin for i := Low(Helps) to High(Helps) do Writeln(Helps[i]); Abort; end else Inc(nParamIndex, 1); end; if nPath = '' then raise Exception.Create('无效的路径'); nPath := TPath.GetFullPath(nPath); if not DirectoryExists(nPath) then raise Exception.CreateFmt('"%s" 路径不存在', [nPath]); if nVersionStr = '' then Writeln('清输入版本号:') else try nVersion.FromString(nVersionStr); except on E: Exception do Writeln('错误: ' + E.Message); end; while nVersion.IsEmpty do begin Write('> '); Readln(nVersionStr); try nVersion.FromString(nVersionStr); except on E: Exception do Writeln('错误: ' + E.Message); end; end; Writeln(''); Writeln('******** 开始处理 ********'); Writeln(Format('目标目录: %s', [nPath])); Write('忽略的对象:'); for i := Low(nIgnoredList) to High(nIgnoredList) do Write(Format(' "%s"', [nIgnoredList[i]])); Write(#10); nFiles := TDirectory.GetFiles(nPath, '*' + _EXT, TSearchOption.soAllDirectories); if Length(nFiles) = 0 then raise Exception.Create('待处理的文件数量为0'); Writeln(Format('待处理文件数量: %d', [Length(nFiles)])); Writeln(''); nXDOC := TQXML.Create; nStrs := TStringList.Create; try nStrs.Delimiter := ';'; nStrs.StrictDelimiter := True; for nFileIndex := Low(nFiles) to High(nFiles) do begin if IsIgnored(nFiles[nFileIndex], nIgnoredList) then begin Writeln('* 忽略 ' + nFiles[nFileIndex]); Continue; end; Writeln(nFiles[nFileIndex]); try nOldVersion.Init; nXDOC.LoadFromFile(nFiles[nFileIndex]); nXNRoot := nXDOC.Items[0]; for nXNIndex := 0 to nXNRoot.Count - 1 do begin nXN := nXNRoot.Items[nXNIndex]; if nXN.Name <> 'PropertyGroup' then Continue; if nXN.Attrs.AsString['Condition'] = '''$(Base)''!=''''' then begin _GetXNode(nXN, 'VerInfo_MajorVer', nStr).Text := nVersion.MajorVer.ToString; nOldVersion.MajorVer := StrToIntDef(nStr, 0); _GetXNode(nXN, 'VerInfo_MinorVer', nStr).Text := nVersion.MinorVer.ToString; nOldVersion.MinorVer := StrToIntDef(nStr, 0); _GetXNode(nXN, 'VerInfo_Release', nStr).Text := nVersion.Release.ToString; nOldVersion.Release := StrToIntDef(nStr, 0); _GetXNode(nXN, 'VerInfo_Build', nStr).Text := nVersion.Build.ToString; nOldVersion.Build := StrToIntDef(nStr, 0); with _GetXNode(nXN, 'VerInfo_Keys', nStr) do begin nStrs.DelimitedText := Text; for nIKIndex := 0 to nStrs.Count - 1 do begin nName := nStrs.KeyNames[nIKIndex]; if CompareText('FileVersion', nName) = 0 then nStrs[nIKIndex] := 'FileVersion=' + nVersion.ToString; end; Text := nStrs.DelimitedText; end; _GetXNode(nXN, 'VerInfo_IncludeVerInfo', nStr).Text := True.ToString(TUseBoolStrs.True); end else begin {删除其他版本信息} nXN.Delete('VerInfo_MajorVer'); nXN.Delete('VerInfo_MinorVer'); nXN.Delete('VerInfo_Release'); nXN.Delete('VerInfo_Build'); nXN.Delete('VerInfo_Keys'); end; end; if nBackup then begin nPath := ExtractFilePath(nFiles[nFileIndex]) + '\dproj_bak\'; ForceDirectories(nPath); nStr := nPath + ExtractFileName(nFiles[nFileIndex]) + '.#' + nOldVersion.ToString + '#.bak'; if FileExists(nStr) then TFile.Delete(nStr); TFile.Copy(nFiles[nFileIndex], nStr); end; nXDOC.SaveToFile(nFiles[nFileIndex], TTextEncoding.teUTF8, True, False, True); except on E: Exception do Writeln('错误: ' + E.Message); end; end; finally nStrs.Free; nXDOC.Free; end; Writeln(''); Writeln('******** 处理完毕 ********') except on E: EAbort do; on E: Exception do begin Writeln('错误: ', E.Message); nAutoClose := False; end; end; if not nAutoClose then begin Writeln(''); Writeln('按任意键关闭'); Read(nStr); end; end.
--------------------------------------------------------------------------------------------------
作者:黑暗煎饼果子
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
--------------------------------------------------------------------------------------------------