|
@@ -23,783 +23,618 @@
|
|
|
program dbdigest;
|
|
|
|
|
|
uses
|
|
|
- sysutils,teststr,testu,tresults,dbtests;
|
|
|
+ {$ifdef unix}
|
|
|
+ cthreads,
|
|
|
+ {$endif}
|
|
|
+ types, classes, custapp, sysutils, inifiles, teststr, testu, tresults, dbtests, digestanalyst;
|
|
|
|
|
|
+Type
|
|
|
|
|
|
-Var
|
|
|
- StatusCount : Array[TTestStatus] of Integer;
|
|
|
- UnknownLines : integer;
|
|
|
-
|
|
|
+ { TThreadTask }
|
|
|
|
|
|
-Procedure ExtractTestFileName(Var Line : string);
|
|
|
+ TThreadTask = Class(TObject)
|
|
|
+ CfgFileName : string;
|
|
|
+ Config: TDigestConfig;
|
|
|
+ Data: TTestRunData;
|
|
|
+ Constructor Create(const aFileName : String; const aConfig : TDigestConfig; aData : TTestRunData);
|
|
|
+ end;
|
|
|
|
|
|
-Var I : integer;
|
|
|
+ { TDBDigestApplication }
|
|
|
+
|
|
|
+ TDBDigestApplication = class(TCustomApplication)
|
|
|
+ Const
|
|
|
+ ShortOpts =
|
|
|
+ 'd'+ { DatabaseName }
|
|
|
+ 'h'+ { Host }
|
|
|
+ 'u'+ { UserName }
|
|
|
+ 'p'+ { Password }
|
|
|
+ 'P'+ { Port }
|
|
|
+ 'l'+ { LogFile }
|
|
|
+ 'L'+ { LongLogFile }
|
|
|
+ 'o'+ { OS }
|
|
|
+ 'c'+ { CPU }
|
|
|
+ 'a'+ { Category }
|
|
|
+ 'v'+ { Version }
|
|
|
+ 't'+ { Date }
|
|
|
+ 's'+ { Submitter }
|
|
|
+ 'm'+ { Machine }
|
|
|
+ 'C'+ { Comment }
|
|
|
+ 'S'+ { TestSrcDir }
|
|
|
+ 'r'+ { RelSrcDir }
|
|
|
+ 'T'+ { ThreadList }
|
|
|
+ 'j'+ { ThreadCount }
|
|
|
+ 'V'+ { Verbose }
|
|
|
+ 'Q' { SQL }
|
|
|
+ ;
|
|
|
+
|
|
|
+ LongOpts : Array of string = (
|
|
|
+ 'databasename',
|
|
|
+ 'host',
|
|
|
+ 'username',
|
|
|
+ 'password',
|
|
|
+ 'port',
|
|
|
+ 'logfile',
|
|
|
+ 'longlogfile',
|
|
|
+ 'os',
|
|
|
+ 'cpu',
|
|
|
+ 'category',
|
|
|
+ 'version',
|
|
|
+ 'date',
|
|
|
+ 'submitter',
|
|
|
+ 'machine',
|
|
|
+ 'comment',
|
|
|
+ 'testsrcdir',
|
|
|
+ 'relsrcdir',
|
|
|
+ 'threadlist',
|
|
|
+ 'threadcount',
|
|
|
+ 'verbose',
|
|
|
+ 'sql',
|
|
|
+ 'compilerdate',
|
|
|
+ 'compilerfullversion',
|
|
|
+ 'svncompilerrevision',
|
|
|
+ 'svntestsrevision',
|
|
|
+ 'svnrtlrevision',
|
|
|
+ 'svnpackagesrevision'
|
|
|
+ );
|
|
|
+
|
|
|
+ private
|
|
|
+ FTasks : TThreadList;
|
|
|
+ FMaxThreads : Integer;
|
|
|
+ FThreadCount : Integer;
|
|
|
+ // Process the command line. Return true if we can continue
|
|
|
+ function ProcessCommandLine(var aConfig: TDigestConfig; var aData: TTestRunData): Boolean;
|
|
|
+ // Check the names of the log files, expanding them if needed.
|
|
|
+ function CheckConfigFiles(lCfg: String; var lData: TTestRunData): Boolean;
|
|
|
+ // Extract a date.
|
|
|
+ class function ExtractDate(aValue: string): TDateTime;
|
|
|
+ // Analyse a log file (i.e. one dbdigest.cfg file)
|
|
|
+ procedure Analyze(const aConfig: TDigestConfig; const aData: TTestRunData);
|
|
|
+ // process a config file (dbdigest.cfg file);
|
|
|
+ procedure ProcessConfigfile(const aFileName: String; var aConfig: TDigestConfig; var aData: TTestRunData);
|
|
|
+ // process a single option. Adapt aConf,aData as needed. Return false if the option was not recognized.
|
|
|
+ function ProcessOption(const aOption: String; aValue: String; var aConfig: TDigestConfig; var aData: TTestRunData): Boolean;
|
|
|
+ // Read /etc/dbdigest.ini for database configuration.
|
|
|
+ procedure ReadSystemDBConfig(var aConfig: TDigestConfig);
|
|
|
+ // In thread mode, create a list of tasks.
|
|
|
+ function CreateTaskList(const aBaseConfig: TDigestConfig; const aBaseData: TTestRunData): boolean;
|
|
|
+ // Callback when a task is done. Checks to see if additional threads must be started.
|
|
|
+ procedure TaskDone(Sender: TObject);
|
|
|
+ // Wait for all tasks & threads to terminate.
|
|
|
+ procedure WaitForThreads;
|
|
|
+ // Start as many threads as allowed, up to task count.
|
|
|
+ procedure StartThreads;
|
|
|
+ protected
|
|
|
+ // Run
|
|
|
+ procedure DoRun; override;
|
|
|
+ // Print usage message.
|
|
|
+ procedure Usage(const aMsg: String);
|
|
|
+ Public
|
|
|
+ Constructor Create(aOwner : TComponent); override;
|
|
|
+ end;
|
|
|
|
|
|
-begin
|
|
|
- I:=Pos(' ',Line);
|
|
|
- If (I<>0) then
|
|
|
- Line:=Copy(Line,1,I-1);
|
|
|
-end;
|
|
|
+ { TProcessFileThread }
|
|
|
|
|
|
-Function Analyse(Var Line : string; Var Status : TTestStatus) : Boolean;
|
|
|
+ TProcessFileThread = class(TThread)
|
|
|
+ Private
|
|
|
+ FTask : TThreadTask;
|
|
|
+ FApp : TDBDigestApplication;
|
|
|
+ Public
|
|
|
+ Constructor Create(aApp : TDBDigestApplication; const aTask : TThreadTask; aOnTerminate : TNotifyEvent);
|
|
|
+ Destructor Destroy; override;
|
|
|
+ Procedure Execute; override;
|
|
|
+ end;
|
|
|
|
|
|
-Var
|
|
|
- TS : TTestStatus;
|
|
|
+{ TThreadTask }
|
|
|
|
|
|
+constructor TThreadTask.Create(const aFileName: String; const aConfig: TDigestConfig; aData: TTestRunData);
|
|
|
begin
|
|
|
- Result:=False;
|
|
|
- For TS:=FirstStatus to LastStatus do
|
|
|
- begin
|
|
|
- Result:=Pos(StatusText[TS],Line)=1;
|
|
|
- If Result then
|
|
|
- begin
|
|
|
- Status:=TS;
|
|
|
- Delete(Line,1,Length(StatusText[TS]));
|
|
|
- ExtractTestFileName(Line);
|
|
|
- Break;
|
|
|
- end;
|
|
|
- end;
|
|
|
+ CfgFileName:=aFileName;
|
|
|
+ Config:=aConfig;
|
|
|
+ Data:=aData;
|
|
|
end;
|
|
|
|
|
|
-Type
|
|
|
-
|
|
|
-TConfigOpt = (
|
|
|
- coDatabaseName,
|
|
|
- coHost,
|
|
|
- coUserName,
|
|
|
- coPassword,
|
|
|
- coPort,
|
|
|
- coLogFile,
|
|
|
- coLongLogFile,
|
|
|
- coOS,
|
|
|
- coCPU,
|
|
|
- coCategory,
|
|
|
- coVersion,
|
|
|
- coDate,
|
|
|
- coSubmitter,
|
|
|
- coMachine,
|
|
|
- coComment,
|
|
|
- coTestSrcDir,
|
|
|
- coRelSrcDir,
|
|
|
- coVerbose,
|
|
|
- coSQL
|
|
|
- );
|
|
|
-
|
|
|
-{ Additional options only for dbdigest.cfg file }
|
|
|
-
|
|
|
-TConfigAddOpt = (
|
|
|
- coCompilerDate,
|
|
|
- coCompilerFullVersion,
|
|
|
- coSvnCompilerRevision,
|
|
|
- coSvnTestsRevision,
|
|
|
- coSvnRTLRevision,
|
|
|
- coSvnPackagesRevision
|
|
|
- );
|
|
|
-
|
|
|
-Const
|
|
|
-
|
|
|
-ConfigStrings : Array [TConfigOpt] of string = (
|
|
|
- 'databasename',
|
|
|
- 'host',
|
|
|
- 'username',
|
|
|
- 'password',
|
|
|
- 'port',
|
|
|
- 'logfile',
|
|
|
- 'longlogfile',
|
|
|
- 'os',
|
|
|
- 'cpu',
|
|
|
- 'category',
|
|
|
- 'version',
|
|
|
- 'date',
|
|
|
- 'submitter',
|
|
|
- 'machine',
|
|
|
- 'comment',
|
|
|
- 'testsrcdir',
|
|
|
- 'relsrcdir',
|
|
|
- 'verbose',
|
|
|
- 'sql'
|
|
|
-);
|
|
|
-
|
|
|
-ConfigOpts : Array[TConfigOpt] of char =(
|
|
|
- 'd', { coDatabaseName }
|
|
|
- 'h', { coHost }
|
|
|
- 'u', { coUserName }
|
|
|
- 'p', { coPassword }
|
|
|
- 'P', { coPort }
|
|
|
- 'l', { coLogFile }
|
|
|
- 'L', { coLongLogFile }
|
|
|
- 'o', { coOS }
|
|
|
- 'c', { coCPU }
|
|
|
- 'a', { coCategory }
|
|
|
- 'v', { coVersion }
|
|
|
- 't', { coDate }
|
|
|
- 's', { coSubmitter }
|
|
|
- 'm', { coMachine }
|
|
|
- 'C', { coComment }
|
|
|
- 'S', { coTestSrcDir }
|
|
|
- 'r', { coRelSrcDir }
|
|
|
- 'V', { coVerbose }
|
|
|
- 'Q' { coSQL }
|
|
|
-);
|
|
|
-
|
|
|
-ConfigAddStrings : Array [TConfigAddOpt] of string = (
|
|
|
- 'compilerdate',
|
|
|
- 'compilerfullversion',
|
|
|
- 'svncompilerrevision',
|
|
|
- 'svntestsrevision',
|
|
|
- 'svnrtlrevision',
|
|
|
- 'svnpackagesrevision'
|
|
|
- );
|
|
|
-
|
|
|
-ConfigAddCols : Array [TConfigAddOpt] of string = (
|
|
|
- 'TU_COMPILERDATE',
|
|
|
- 'TU_COMPILERFULLVERSION',
|
|
|
- 'TU_SVNCOMPILERREVISION',
|
|
|
- 'TU_SVNTESTSREVISION',
|
|
|
- 'TU_SVNRTLREVISION',
|
|
|
- 'TU_SVNPACKAGESREVISION'
|
|
|
- );
|
|
|
+{ TProcessFileThread }
|
|
|
|
|
|
+constructor TProcessFileThread.Create(aApp: TDBDigestApplication; const aTask: TThreadTask; aOnTerminate: TNotifyEvent);
|
|
|
+begin
|
|
|
+ FTask:=aTask;
|
|
|
+ FApp:=aApp;
|
|
|
+ Self.OnTerminate:=aOnTerminate;
|
|
|
+ Inherited create(False);
|
|
|
+end;
|
|
|
|
|
|
-Var
|
|
|
- TestOS,
|
|
|
- TestCPU,
|
|
|
- TestVersion,
|
|
|
- TestCategory,
|
|
|
- DatabaseName,
|
|
|
- HostName,
|
|
|
- UserName,
|
|
|
- Password,
|
|
|
- Port,
|
|
|
- LongLogFileName,
|
|
|
- LogFileName,
|
|
|
- Submitter,
|
|
|
- Machine,
|
|
|
- Comment : String;
|
|
|
- TestDate : TDateTime;
|
|
|
- TestCompilerDate,
|
|
|
- TestCompilerFullVersion,
|
|
|
- TestSvnCompilerRevision,
|
|
|
- TestSvnTestsRevision,
|
|
|
- TestSvnRTLRevision,
|
|
|
- TestSvnPackagesRevision : String;
|
|
|
-
|
|
|
-Procedure SetAddOpt (O : TConfigAddOpt; Value : string);
|
|
|
+destructor TProcessFileThread.Destroy;
|
|
|
+var
|
|
|
+ lPrefix : String;
|
|
|
+ lCfg : String;
|
|
|
begin
|
|
|
- Case O of
|
|
|
- coCompilerDate:
|
|
|
- TestCompilerDate:=Value;
|
|
|
- coCompilerFullVersion:
|
|
|
- TestCompilerFullVersion:=Value;
|
|
|
- coSvnCompilerRevision:
|
|
|
- TestSvnCompilerRevision:=Value;
|
|
|
- coSvnTestsRevision:
|
|
|
- TestSvnTestsRevision:=Value;
|
|
|
- coSvnRTLRevision:
|
|
|
- TestSvnRTLRevision:=Value;
|
|
|
- coSvnPackagesRevision:
|
|
|
- TestSvnPackagesRevision:=Value;
|
|
|
+ try
|
|
|
+ lCfg:=FTask.CfgFileName;
|
|
|
+ lPrefix:='['+IntToStr(PtrInt(GetCurrentThreadId))+' - '+lCfg+'] ';
|
|
|
+ FreeAndNil(FTask);
|
|
|
+ Verbose(V_DEBUG,lPrefix+' task destroyed ');
|
|
|
+ except
|
|
|
+ On e : Exception do
|
|
|
+ Verbose(V_WARNING,lPrefix+Format('Error %s during processing of "%s": %s',[E.ClassName,lCfg,E.Message]));
|
|
|
end;
|
|
|
+ inherited Destroy;
|
|
|
end;
|
|
|
|
|
|
-Procedure SetOpt (O : TConfigOpt; Value : string);
|
|
|
+procedure TProcessFileThread.Execute;
|
|
|
var
|
|
|
- year,month,day,min,hour : word;
|
|
|
+ lPrefix:String;
|
|
|
+
|
|
|
begin
|
|
|
- Case O of
|
|
|
- coDatabaseName : DatabaseName:=Value;
|
|
|
- coHost : HostName:=Value;
|
|
|
- coUserName : UserName:=Value;
|
|
|
- coPassword : Password:=Value;
|
|
|
- coPort : Port:=Value;
|
|
|
- coLogFile : LogFileName:=Value;
|
|
|
- coLongLogFile : LongLogFileName:=Value;
|
|
|
- coOS : TestOS:=Value;
|
|
|
- coCPU : TestCPU:=Value;
|
|
|
- coCategory : TestCategory:=Value;
|
|
|
- coVersion : TestVersion:=Value;
|
|
|
- coSQL : DoSQL:=True;
|
|
|
- coDate :
|
|
|
- begin
|
|
|
- { Formated like YYYYMMDDhhmm }
|
|
|
- if Length(value)=12 then
|
|
|
- begin
|
|
|
- year:=StrToInt(Copy(value,1,4));
|
|
|
- month:=StrToInt(Copy(value,5,2));
|
|
|
- day:=StrToInt(Copy(Value,7,2));
|
|
|
- hour:=StrToInt(Copy(Value,9,2));
|
|
|
- min:=StrToInt(Copy(Value,11,2));
|
|
|
- TestDate:=EncodeDate(year,month,day)+EncodeTime(hour,min,0,0);
|
|
|
- end
|
|
|
- else
|
|
|
- Verbose(V_Error,'Error in date format, use YYYYMMDDhhmm');
|
|
|
- end;
|
|
|
- coSubmitter : Submitter:=Value;
|
|
|
- coMachine : Machine:=Value;
|
|
|
- coComment : Comment:=Value;
|
|
|
- coVerbose : DoVerbose:=true;
|
|
|
- coTestSrcDir :
|
|
|
- begin
|
|
|
- TestSrcDir:=Value;
|
|
|
- if (TestSrcDir<>'') and (TestSrcDir[length(TestSrcDir)]<>'/') then
|
|
|
- TestSrcDir:=TestSrcDir+'/';
|
|
|
- end;
|
|
|
- coRelSrcDir :
|
|
|
- begin
|
|
|
- RelSrcDir:=Value;
|
|
|
- if (RelSrcDir<>'') and (RelSrcDir[length(RelSrcDir)]<>'/') then
|
|
|
- RelSrcDir:=RelSrcDir+'/';
|
|
|
- if (RelSrcDir<>'') and (RelSrcDir[1]='/') then
|
|
|
- RelSrcDir:=copy(RelSrcDir,2,length(RelSrcDir)-1);
|
|
|
- end;
|
|
|
+ try
|
|
|
+ lPrefix:='['+IntToStr(PtrInt(GetCurrentThreadId))+' - '+FTask.CfgFileName+'] ';
|
|
|
+ FApp.Analyze(FTask.Config,FTask.Data);
|
|
|
+ Writeln(IntToStr(PtrInt(GetCurrentThreadId))+'Thread done');
|
|
|
+ except
|
|
|
+ On e : Exception do
|
|
|
+ Verbose(V_WARNING,lPrefix+Format('Error %s during processing of "%s": %s',[E.ClassName,FTask.CfgFileName,E.Message]));
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-Function ProcessOption(S: String) : Boolean;
|
|
|
+class function TDBDigestApplication.ExtractDate(aValue: string): TDateTime;
|
|
|
|
|
|
-Var
|
|
|
- N : String;
|
|
|
- I : Integer;
|
|
|
- co : TConfigOpt;
|
|
|
- coa : TConfigAddOpt;
|
|
|
+var
|
|
|
+ year,month,day,min,hour : word;
|
|
|
|
|
|
begin
|
|
|
- Verbose(V_DEBUG,'Processing option: '+S);
|
|
|
- I:=Pos('=',S);
|
|
|
- Result:=(I<>0);
|
|
|
- If Result then
|
|
|
+ if (Length(avalue)=12) or (Length(avalue)=8) then
|
|
|
begin
|
|
|
- N:=Copy(S,1,I-1);
|
|
|
- Delete(S,1,I);
|
|
|
- For co:=low(TConfigOpt) to high(TConfigOpt) do
|
|
|
- begin
|
|
|
- Result:=CompareText(ConfigStrings[co],N)=0;
|
|
|
- If Result then
|
|
|
+ year:=StrToInt(Copy(avalue,1,4));
|
|
|
+ month:=StrToInt(Copy(avalue,5,2));
|
|
|
+ day:=StrToInt(Copy(aValue,7,2));
|
|
|
+ if Length(avalue)=12 then
|
|
|
begin
|
|
|
- SetOpt(co,S);
|
|
|
- Exit;
|
|
|
+ hour:=StrToInt(Copy(aValue,9,2));
|
|
|
+ min:=StrToInt(Copy(aValue,11,2));
|
|
|
end;
|
|
|
- end;
|
|
|
- For coa:=low(TConfigAddOpt) to high(TConfigAddOpt) do
|
|
|
- begin
|
|
|
- Result:=CompareText(ConfigAddStrings[coa],N)=0;
|
|
|
- If Result then
|
|
|
- begin
|
|
|
- SetAddOpt(coa,S);
|
|
|
- Exit;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- Verbose(V_ERROR,'Unknown option : '+n+S);
|
|
|
+ Result:=EncodeDate(year,month,day)+EncodeTime(hour,min,0,0);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ Verbose(V_Error,'Error in date format, use YYYYMMDDhhmm');
|
|
|
end;
|
|
|
|
|
|
-Procedure ProcessConfigfile(FN : String);
|
|
|
-
|
|
|
-Var
|
|
|
- F : Text;
|
|
|
- S : String;
|
|
|
- I : Integer;
|
|
|
+function TDBDigestApplication.ProcessOption(const aOption: String; aValue: String; var aConfig: TDigestConfig;
|
|
|
+ var aData: TTestRunData): Boolean;
|
|
|
|
|
|
begin
|
|
|
- // Set the default value for old digests without RelSrcDir to the rtl/compiler
|
|
|
- // testsuite
|
|
|
- RelSrcDir:='tests/';
|
|
|
- If Not FileExists(FN) Then
|
|
|
- Exit;
|
|
|
- Verbose(V_DEBUG,'Parsing config file: '+FN);
|
|
|
- Assign(F,FN);
|
|
|
- {$i-}
|
|
|
- Reset(F);
|
|
|
- If IOResult<>0 then
|
|
|
- Exit;
|
|
|
- {$I+}
|
|
|
- While not(EOF(F)) do
|
|
|
- begin
|
|
|
- ReadLn(F,S);
|
|
|
- S:=trim(S);
|
|
|
- I:=Pos('#',S);
|
|
|
- If I<>0 then
|
|
|
- S:=Copy(S,1,I-1);
|
|
|
- If (S<>'') then
|
|
|
- ProcessOption(S);
|
|
|
- end;
|
|
|
- Close(F);
|
|
|
+ Result:=True;
|
|
|
+ Verbose(V_DEBUG,'Processing option: '+aOption);
|
|
|
+ Case aOption of
|
|
|
+ 'd','databasename' : aConfig.databasename:=aValue;
|
|
|
+ 'h','host' : aConfig.host:=aValue;
|
|
|
+ 'u','username': aConfig.username:=aValue;
|
|
|
+ 'p','password': aConfig.password:=aValue;
|
|
|
+ 'P','port': aConfig.port:=StrToIntDef(aValue,0);
|
|
|
+ 'l','logfile': aData.logfile:=aValue;
|
|
|
+ 'L','longlogfile': aData.longlogfile:=aValue;
|
|
|
+ 'o','os': aData.os:=aValue;
|
|
|
+ 'c','cpu': aData.cpu:=aValue;
|
|
|
+ 'a','category': aData.category:=aValue;
|
|
|
+ 'v','version': aData.version:=aValue;
|
|
|
+ 't','date': aData.date:=ExtractDate(aValue);
|
|
|
+ 's','submitter': aData.submitter:=aValue;
|
|
|
+ 'm','machine': aData.machine:=aValue;
|
|
|
+ 'C','comment': aData.config:=aValue;
|
|
|
+ 'D','description': aData.description:=aValue;
|
|
|
+ 'S','testsrcdir': aConfig.testsrcdir:=aValue;
|
|
|
+ 'r','relsrcdir': aConfig.relsrcdir:=aValue;
|
|
|
+ 'V','verbose': DoVerbose:=True;
|
|
|
+ 'sql': dosql:=true;
|
|
|
+ 'T','threadlist' : ; // treated elsewhere
|
|
|
+ 'j','threadcount' : ; // treated elsewhere
|
|
|
+ 'compilerdate': aData.CompilerDate:=aValue;
|
|
|
+ 'compilerfullversion': aData.CompilerFullVersion:=aValue;
|
|
|
+ 'svncompilerrevision': aData.CompilerRevision:=aValue;
|
|
|
+ 'svntestsrevision': aData.TestsRevision:=aValue;
|
|
|
+ 'svnrtlrevision': aData.RTLRevision:=aValue;
|
|
|
+ 'svnpackagesrevision' : aData.PackagesRevision:=aValue;
|
|
|
+ else
|
|
|
+ Verbose(V_ERROR,'Unknown processing option: '+aOption);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
-Procedure ProcessCommandLine;
|
|
|
+procedure TDBDigestApplication.ProcessConfigfile(const aFileName: String; var aConfig: TDigestConfig; var aData: TTestRunData);
|
|
|
|
|
|
Var
|
|
|
+ Cfg : TStrings;
|
|
|
+ aLine,S,N,V : String;
|
|
|
I : Integer;
|
|
|
- O : String;
|
|
|
- c,co : TConfigOpt;
|
|
|
- ShortOptFound, Found : Boolean;
|
|
|
|
|
|
begin
|
|
|
- I:=1;
|
|
|
- While I<=ParamCount do
|
|
|
- begin
|
|
|
- O:=Paramstr(I);
|
|
|
- ShortOptFound:=(Length(O)=2) and (O[1]='-');
|
|
|
- If ShortOptFound then
|
|
|
- For co:=low(TConfigOpt) to high(TConfigOpt) do
|
|
|
+ // Set the default value for old digests without RelSrcDir to the rtl/compiler
|
|
|
+ // testsuite
|
|
|
+ If Not FileExists(aFileName) Then
|
|
|
+ Exit;
|
|
|
+ Verbose(V_DEBUG,'Parsing config file: '+aFileName);
|
|
|
+ Cfg:=TStringList.Create;
|
|
|
+ try
|
|
|
+ Cfg.LoadFromFile(aFileName);
|
|
|
+ For aLine in Cfg do
|
|
|
+ begin
|
|
|
+ S:=Trim(aLine);
|
|
|
+ I:=Pos('#',S);
|
|
|
+ If I<>0 then
|
|
|
+ S:=Copy(S,1,I-1);
|
|
|
+ If (S<>'') then
|
|
|
begin
|
|
|
- Found:=(O[2]=ConfigOpts[co]);
|
|
|
- If Found then
|
|
|
+ I:=Pos('=',S);
|
|
|
+ if (I=0) then
|
|
|
+ Verbose(V_ERROR,'Unknown processing option: '+S)
|
|
|
+ else
|
|
|
begin
|
|
|
- c:=co;
|
|
|
- Break;
|
|
|
+ N:=LowerCase(Copy(S,1,I-1));
|
|
|
+ V:=Copy(S,I+1,Length(S)-I);
|
|
|
+ ProcessOption(N,V,aConfig,aData);
|
|
|
end;
|
|
|
end;
|
|
|
- If not ShortOptFound then
|
|
|
- begin
|
|
|
- Found:=false;
|
|
|
- { accept long options }
|
|
|
- if (copy(O,1,2)='--') then
|
|
|
- begin
|
|
|
- { remove -- }
|
|
|
- O:=copy(O,3,length(O));
|
|
|
- For co:=low(TConfigOpt) to high(TConfigOpt) do
|
|
|
- begin
|
|
|
- Found:=(O=ConfigStrings[co]);
|
|
|
- If Found then
|
|
|
- begin
|
|
|
- c:=co;
|
|
|
- Break;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end
|
|
|
end;
|
|
|
- if not Found then
|
|
|
- Verbose(V_ERROR,'Illegal command-line option : '+O)
|
|
|
- else
|
|
|
- begin
|
|
|
- if c=coverbose then
|
|
|
- begin
|
|
|
- Found:=true;
|
|
|
- o:='';
|
|
|
- end
|
|
|
- else
|
|
|
- Found:=(I<ParamCount);
|
|
|
- If Not found then
|
|
|
- Verbose(V_ERROR,'Option requires argument : '+O)
|
|
|
- else
|
|
|
- begin
|
|
|
- inc(I);
|
|
|
- O:=Paramstr(I);
|
|
|
- SetOpt(c,o);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Inc(I);
|
|
|
- end;
|
|
|
-end;
|
|
|
|
|
|
-Var
|
|
|
- TestCPUID : Integer;
|
|
|
- TestOSID : Integer;
|
|
|
- TestVersionID : Integer;
|
|
|
- TestCategoryID : Integer;
|
|
|
- TestRunID : Integer;
|
|
|
- ConfigID : Integer;
|
|
|
-
|
|
|
-Procedure GetIDs;
|
|
|
-var
|
|
|
- qry : string;
|
|
|
-begin
|
|
|
- TestCPUID := GetCPUId(TestCPU);
|
|
|
- If TestCPUID=-1 then
|
|
|
- Verbose(V_Error,'NO ID for CPU "'+TestCPU+'" found.');
|
|
|
- TestOSID := GetOSID(TestOS);
|
|
|
- If TestOSID=-1 then
|
|
|
- Verbose(V_Error,'NO ID for OS "'+TestOS+'" found.');
|
|
|
- TestCategoryID := GetCategoryID(TestCategory);
|
|
|
- If TestCategoryID=-1 then
|
|
|
- begin
|
|
|
-// Verbose(V_Error,'NO ID for Category "'+TestCategory+'" found.');
|
|
|
- TestCategoryID:=1;
|
|
|
- end;
|
|
|
- TestVersionID := GetVersionID(TestVersion);
|
|
|
- If TestVersionID=-1 then
|
|
|
- Verbose(V_Error,'NO ID for version "'+TestVersion+'" found.');
|
|
|
- If (Round(TestDate)=0) then
|
|
|
- Testdate:=Now;
|
|
|
- TestRunID:=GetRunID(TestOSID,TestCPUID,TestVersionID,TestDate);
|
|
|
- If (TestRunID=-1) then
|
|
|
- begin
|
|
|
- TestRunID:=AddRun(TestOSID,TestCPUID,TestVersionID,TestCategoryID,TestDate);
|
|
|
- If TestRunID=-1 then
|
|
|
- Verbose(V_Error,'Could not insert new testrun record!');
|
|
|
- end
|
|
|
- else
|
|
|
- CleanTestRun(TestRunID);
|
|
|
- { Add known infomration at start }
|
|
|
- qry:=format('UPDATE TESTRUN SET TU_SUBMITTER=''%s'', TU_MACHINE=''%s'', TU_COMMENT=''%s'', TU_DATE=''%s''',[Submitter,Machine,Comment,SqlDate(TestDate)]);
|
|
|
- qry:=qry+' WHERE TU_ID='+format('%d',[TestRunID]);
|
|
|
- ExecuteQuery(Qry,False);
|
|
|
+ finally
|
|
|
+ Cfg.Free;
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
+{ TDBDigestApplication }
|
|
|
+
|
|
|
+procedure TDBDigestApplication.Usage(const aMsg: String);
|
|
|
|
|
|
-var
|
|
|
- LongLogFile : Text;
|
|
|
-const
|
|
|
- UseLongLog : boolean = false;
|
|
|
- LongLogOpenCount : longint = 0;
|
|
|
- FirstLongLogLine : boolean = true;
|
|
|
-const
|
|
|
- SeparationLine = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>';
|
|
|
-
|
|
|
-Function GetContentsFromLongLog(Line : String) : String;
|
|
|
-var
|
|
|
- S : String;
|
|
|
- IsFirst, IsFound : boolean;
|
|
|
begin
|
|
|
- Result:='';
|
|
|
- IsFirst:=true;
|
|
|
- IsFound:=false;
|
|
|
- While Not(EOF(LongLogFile)) do
|
|
|
- begin
|
|
|
- ReadLn(LongLogFile,S);
|
|
|
- if FirstLongLogLine then
|
|
|
- begin
|
|
|
- { At start of file there is a separation line }
|
|
|
- if (pos(Line,S)=0) and (pos(SeparationLine,S)>=1) then
|
|
|
- Readln(LongLogFile,S);
|
|
|
- FirstLongLogLine:=false;
|
|
|
- end;
|
|
|
- if pos(Line,S)=1 then
|
|
|
- begin
|
|
|
- IsFound:=true;
|
|
|
- while not eof(LongLogFile) do
|
|
|
- begin
|
|
|
- ReadLn(LongLogFile,S);
|
|
|
- { End of file marker }
|
|
|
- if eof(LongLogFile) or (pos(SeparationLine,S)=1) then
|
|
|
- exit;
|
|
|
- if length(Result)<MaxLogSize then
|
|
|
- Result:=Result+S+LineEnding;
|
|
|
- if pos(SeparationLine,S)>1 then
|
|
|
- exit;
|
|
|
- end;
|
|
|
- end
|
|
|
- else if IsFirst then
|
|
|
- begin
|
|
|
- Verbose(V_Warning,'Line "'+Line+'" not found as next "'+S+'"');
|
|
|
- IsFirst:=false;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if not IsFound then
|
|
|
- begin
|
|
|
- Verbose(V_Warning,'Line "'+Line+'" not found');
|
|
|
- { Restart to get a chance to find others }
|
|
|
- if eof(LongLogFile) then
|
|
|
- begin
|
|
|
- Close(LongLogFile);
|
|
|
- Reset(LongLogFile);
|
|
|
- inc(LongLogOpenCount);
|
|
|
- end;
|
|
|
- end;
|
|
|
+ if (aMsg<>'') then
|
|
|
+ Writeln('Error : ',aMsg);
|
|
|
+ Writeln('Usage: ',ExeName,' [options] [test run data options]');
|
|
|
+ Writeln('Configuration options:');
|
|
|
+ Writeln('-H --help show this help');
|
|
|
+ Writeln('-d --databasename=NAME database name');
|
|
|
+ Writeln('-f --config=FILENAME config file. If not set, dbdigest.cfg is used.');
|
|
|
+ Writeln('-h --host=HOST database hostname');
|
|
|
+ Writeln('-p --password=PWD database user password');
|
|
|
+ Writeln('-P --port=NNN database connection port');
|
|
|
+ Writeln('-r --relsrcdir relative source dir');
|
|
|
+ Writeln('-S --testsrcdir test source dir');
|
|
|
+ Writeln('-u --username=USER database user name');
|
|
|
+ Writeln('-T --threadlist=FILE file with configuration file names to imports.');
|
|
|
+ Writeln('-j --threadcount=N Number of threads to use');
|
|
|
+ Writeln('-V --verbose be more verbose');
|
|
|
+ Writeln('Test run data:');
|
|
|
+ Writeln('-l --logfile=FILE set log file to analyse');
|
|
|
+ Writeln('-L --longlogfile=FILE set long log filename (logs of run tests)');
|
|
|
+ Writeln('-o --os=OS set OS for testrun');
|
|
|
+ Writeln('-c --cpu=CPU set CPU');
|
|
|
+ Writeln('-a --category=CAT set category');
|
|
|
+ Writeln('-v --version=VER set compiler version');
|
|
|
+ Writeln('-t --date=DATE date in YYYMMDD(hhmmnn) format');
|
|
|
+ Writeln('-s --submitter=NAME submitter name');
|
|
|
+ Writeln('-m --machine=NAME set machine name on which testsuite was run');
|
|
|
+ Writeln('-C --compile-flags=FLAGS set used compilation flags');
|
|
|
+ Writeln(' --comment=FLAGS backwards compatible way to set compilation flags (deprecated)');
|
|
|
+ Writeln('-D --description=DESC set config description (helpful comment)');
|
|
|
+ Writeln(' --compilerdate=DATE set compiler date');
|
|
|
+ Writeln(' --compilerfullversion=VERSION set full compiler version');
|
|
|
+ Writeln(' --svncompilerrevision=REV set revision of used compiler');
|
|
|
+ Writeln(' --svntestsrevision=REV set revision of testsuite files');
|
|
|
+ Writeln(' --svnrtlrevision=REV set revision of RTL');
|
|
|
+ Writeln(' --svnpackagesrevision=REV set revison of packages');
|
|
|
+ Writeln('');
|
|
|
+ Writeln('If -T is specified, no test run options may be specified');
|
|
|
+ Writeln('');
|
|
|
+ Writeln('The config file can contain the same options as the command-line in the form.');
|
|
|
+ Writeln('option=value');
|
|
|
+ Writeln('where option is the long or short version of the option');
|
|
|
+ Writeln('comments may be included using the # character.');
|
|
|
+ ExitCode:=Ord(aMsg<>'');
|
|
|
end;
|
|
|
|
|
|
-Function GetLog(Line, FN : String) : String;
|
|
|
-
|
|
|
+constructor TDBDigestApplication.Create(aOwner: TComponent);
|
|
|
begin
|
|
|
- if UseLongLog then
|
|
|
- begin
|
|
|
- Result:=GetContentsFromLongLog(Line);
|
|
|
- exit;
|
|
|
- end;
|
|
|
- FN:=ChangeFileExt(FN,'.log');
|
|
|
- { packages tests have ../ replaced by root/ }
|
|
|
- if not FileExists(FN) and (Copy(FN,1,3)='../') then
|
|
|
- FN:='root/'+Copy(FN,4,length(FN));
|
|
|
- If FileExists(FN) then
|
|
|
- Result:=GetFileContents(FN)
|
|
|
- else
|
|
|
- begin
|
|
|
- Verbose(V_Warning,'File "'+FN+'" not found');
|
|
|
- Result:='';
|
|
|
- end;
|
|
|
+ inherited Create(aOwner);
|
|
|
+ FTasks:=TThreadList.Create;
|
|
|
end;
|
|
|
|
|
|
-Function GetExecuteLog(Line, FN : String) : String;
|
|
|
+function TDBDigestApplication.ProcessCommandLine(var aConfig: TDigestConfig; var aData : TTestRunData): Boolean;
|
|
|
+
|
|
|
+ Function MakeOpts(s : string) : string;
|
|
|
+ var
|
|
|
+ C : char;
|
|
|
+ begin
|
|
|
+ Result:='';
|
|
|
+ For C in s do
|
|
|
+ begin
|
|
|
+ Result:=Result+C;
|
|
|
+ if not (C in ['V','Q']) then
|
|
|
+ Result:=Result+':';
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ Function MakeLongOpts(s : array of string) : TStringDynArray;
|
|
|
+ var
|
|
|
+ I : Integer;
|
|
|
+ begin
|
|
|
+ Result:=['help'];
|
|
|
+ SetLength(Result,1+Length(S));
|
|
|
+ For I:=0 to Length(S)-1 do
|
|
|
+ begin
|
|
|
+ Result[1+I]:=S[I];
|
|
|
+ if (S[I]<>'verbose') and (S[I]<>'sql') then
|
|
|
+ Result[1+I]:=Result[1+I]+':';
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+var
|
|
|
+ Long,ErrMsg,lValue : String;
|
|
|
+ Short : Char;
|
|
|
+ I : integer;
|
|
|
+ lHas : boolean;
|
|
|
|
|
|
begin
|
|
|
- if UseLongLog then
|
|
|
+ ErrMsg:=CheckOptions(MakeOpts(ShortOpts)+'H',MakeLongOpts(LongOpts));
|
|
|
+ Result:=(ErrMsg='');
|
|
|
+ if (not Result) or HasOption('H','help') then
|
|
|
begin
|
|
|
- Result:=GetContentsFromLongLog(Line);
|
|
|
- exit;
|
|
|
+ Usage(ErrMsg);
|
|
|
+ Exit(false);
|
|
|
end;
|
|
|
- FN:=ChangeFileExt(FN,'.elg');
|
|
|
- { packages tests have ../ replaced by root/ }
|
|
|
- if not FileExists(FN) and (Copy(FN,1,3)='../') then
|
|
|
- FN:='root/'+Copy(FN,4,length(FN));
|
|
|
- If FileExists(FN) then
|
|
|
- Result:=GetFileContents(FN)
|
|
|
- else
|
|
|
+ I:=0;
|
|
|
+ For Long in LongOpts do
|
|
|
begin
|
|
|
- Verbose(V_Warning,'File "'+FN+'" not found');
|
|
|
- Result:='';
|
|
|
+ Inc(I);
|
|
|
+ if I<=Length(ShortOpts) then
|
|
|
+ begin
|
|
|
+ Short:=ShortOpts[I];
|
|
|
+ if Short='r' then
|
|
|
+ Writeln('ag');
|
|
|
+ lHas:=HasOption(Short,Long);
|
|
|
+ lValue:=GetOptionValue(Short,Long);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ Short:=#0;
|
|
|
+ lHas:=HasOption(Long);
|
|
|
+ lValue:=GetOptionValue(Long);
|
|
|
+ end;
|
|
|
+ if lHas then
|
|
|
+ ProcessOption(long,lValue,aConfig,aData);
|
|
|
end;
|
|
|
+ Result:=True;
|
|
|
end;
|
|
|
|
|
|
-Procedure Processfile (FN: String);
|
|
|
+procedure TDBDigestApplication.Analyze(const aConfig : TDigestConfig; const aData : TTestRunData);
|
|
|
|
|
|
var
|
|
|
- logfile : text;
|
|
|
- fullline,line,prevLine : string;
|
|
|
- TS,PrevTS : TTestStatus;
|
|
|
- ID,PrevID : integer;
|
|
|
- Testlog : string;
|
|
|
- count_test : boolean;
|
|
|
+ lSQL : TTestSQL;
|
|
|
+ lDigest : TDBDigestAnalyzer;
|
|
|
+ lPrefix : string;
|
|
|
+
|
|
|
begin
|
|
|
- Assign(logfile,FN);
|
|
|
- PrevId:=-1;
|
|
|
- PrevLine:='';
|
|
|
- count_test:=false;
|
|
|
- PrevTS:=low(TTestStatus);
|
|
|
-{$i-}
|
|
|
- reset(logfile);
|
|
|
- if ioresult<>0 then
|
|
|
- Verbose(V_Error,'Unable to open log file'+FN);
|
|
|
-{$i+}
|
|
|
- while not eof(logfile) do
|
|
|
- begin
|
|
|
- readln(logfile,line);
|
|
|
- fullline:=line;
|
|
|
- ts:=stFailedToCompile;
|
|
|
- If analyse(line,TS) then
|
|
|
- begin
|
|
|
- Verbose(V_NORMAL,'Analysing result for test '+Line);
|
|
|
- If Not ExpectRun[TS] then
|
|
|
- begin
|
|
|
- ID:=RequireTestID(Line);
|
|
|
- if (PrevID<>-1) and (PrevID<>ID) then
|
|
|
- begin
|
|
|
- { This can only happen if a Successfully compiled message
|
|
|
- is not followed by any other line about the same test }
|
|
|
- TestLog:='';
|
|
|
- AddTestResult(PrevID,TestRunId,ord(PrevTS),
|
|
|
- TestOK[PrevTS],TestSkipped[PrevTS],TestLog,count_test);
|
|
|
- Verbose(V_Warning,'Orphaned test: "'+prevline+'"');
|
|
|
- end;
|
|
|
- PrevID:=-1;
|
|
|
- If (ID<>-1) then
|
|
|
- begin
|
|
|
- If Not (TestOK[TS] or TestSkipped[TS]) then
|
|
|
- begin
|
|
|
- TestLog:=GetExecuteLog(Fullline,Line);
|
|
|
- if pos(failed_to_compile,TestLog)=1 then
|
|
|
- TestLog:=GetLog(Fullline,Line);
|
|
|
- end
|
|
|
- else
|
|
|
- TestLog:='';
|
|
|
- { AddTestResult can fail for test that contain %recompile
|
|
|
- as the same }
|
|
|
- if AddTestResult(ID,TestRunID,Ord(TS),TestOK[TS],
|
|
|
- TestSkipped[TS],TestLog,count_test) <> -1 then
|
|
|
- begin
|
|
|
- if count_test then
|
|
|
- Inc(StatusCount[TS])
|
|
|
- else
|
|
|
- Verbose(V_Debug,'Test: "'+line+'" was updated');
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Verbose(V_Warning,'Test: "'+line+'" already registered');
|
|
|
- end;
|
|
|
+ lDigest:=Nil;
|
|
|
+ With aConfig do
|
|
|
+ lSQL:=TTestSQL.create(databasename,host,username,password,port);
|
|
|
+ try
|
|
|
+ lSQL.ConnectToDatabase;
|
|
|
+ if GetCurrentThreadId<>MainThreadID then
|
|
|
+ lPrefix:='['+IntToStr(PtrInt(GetCurrentThreadId))+' - '+aData.logfile+']: '
|
|
|
+ else
|
|
|
+ lPrefix:='';
|
|
|
+ lSQL.LogPrefix:=lPrefix;
|
|
|
+ lDigest:=TDBDigestAnalyzer.Create(lSQL,lPrefix);
|
|
|
+ lDigest.Analyse(aConfig,aData);
|
|
|
+ finally
|
|
|
+ lDigest.Free;
|
|
|
+ lSQL.Free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
- end;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Inc(StatusCount[TS]);
|
|
|
- PrevTS:=TS;
|
|
|
- PrevID:=RequireTestID(line);
|
|
|
- PrevLine:=line;
|
|
|
- end;
|
|
|
+procedure TDBDigestApplication.ReadSystemDBConfig(var aConfig : TDigestConfig);
|
|
|
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Inc(UnknownLines);
|
|
|
- Verbose(V_Warning,'Unknown line: "'+line+'"');
|
|
|
- end;
|
|
|
+// Keep filename in sync with algorithm in dbadd
|
|
|
+
|
|
|
+var
|
|
|
+ lFileName : String;
|
|
|
+ Ini : TCustomIniFile;
|
|
|
+
|
|
|
+begin
|
|
|
+ lFileName:='/etc/dbdigest.ini';
|
|
|
+ if not FileExists(lFileName) then exit;
|
|
|
+ Ini:=TMemIniFile.Create(lFileName);
|
|
|
+ With Ini do
|
|
|
+ try
|
|
|
+ aConfig.DatabaseName:=ReadString(SSection,KeyName,'testsuite');
|
|
|
+ aConfig.Host:=ReadString(SSection,KeyHost,'localhost');
|
|
|
+ aConfig.UserName:=ReadString(SSection,KeyUser,'');
|
|
|
+ aConfig.Password:=ReadString(SSection,KeyPassword,'');
|
|
|
+ aConfig.Port:=ReadInteger(SSection,KeyPort,0);
|
|
|
+ finally
|
|
|
+ Ini.Free;
|
|
|
end;
|
|
|
- close(logfile);
|
|
|
end;
|
|
|
|
|
|
-procedure UpdateTestRun;
|
|
|
+function TDBDigestApplication.CheckConfigFiles(lCfg : String; var lData : TTestRunData) : Boolean;
|
|
|
+
|
|
|
+ function CheckFile(const aDir : String; var aFile : String) : boolean;
|
|
|
|
|
|
var
|
|
|
- i : TTestStatus;
|
|
|
- qry : string;
|
|
|
+ lExpanded : string;
|
|
|
|
|
|
begin
|
|
|
- qry:='UPDATE TESTRUN SET ';
|
|
|
- for i:=low(TTestStatus) to high(TTestStatus) do
|
|
|
- qry:=qry+format('%s=%d, ',[SQLField[i],StatusCount[i]]);
|
|
|
- if TestCompilerDate<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coCompilerDate],EscapeSQL(TestCompilerDate)]);
|
|
|
- if TestCompilerFullVersion<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coCompilerFullVersion],EscapeSQL(TestCompilerFullVersion)]);
|
|
|
- if TestSvnCompilerRevision<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coSvnCompilerRevision],EscapeSQL(TestSvnCompilerRevision)]);
|
|
|
- if TestSvnTestsRevision<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coSvnTestsRevision],EscapeSQL(TestSvnTestsRevision)]);
|
|
|
- if TestSvnRTLRevision<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coSvnRTLRevision],EscapeSQL(TestSvnRTLRevision)]);
|
|
|
- if TestSvnPackagesRevision<>'' then
|
|
|
- qry:=qry+format('%s=''%s'', ',[ConfigAddCols[coSvnPackagesRevision],EscapeSQL(TestSvnPackagesRevision)]);
|
|
|
-
|
|
|
- qry:=qry+format('TU_SUBMITTER=''%s'', TU_MACHINE=''%s'', TU_COMMENT=''%s'', TU_DATE=''%s''',[Submitter,Machine,Comment,SqlDate(TestDate)]);
|
|
|
- qry:=qry+' WHERE TU_ID='+format('%d',[TestRunID]);
|
|
|
- ExecuteQuery(Qry,False);
|
|
|
+ if (aFile<>'') and (aFile[1]<>'/') then
|
|
|
+ begin
|
|
|
+ lExpanded:=aDir+aFile;
|
|
|
+ Verbose(V_Debug,Format('Expanding file from %s to %s',[aFile,lExpanded]));
|
|
|
+ aFile:=lExpanded;
|
|
|
+ end;
|
|
|
+ Result:=FileExists(aFile);
|
|
|
+ if not Result then
|
|
|
+ Verbose(V_Warning,Format('file does not exist: %s',[lExpanded]));
|
|
|
end;
|
|
|
|
|
|
-function GetTestConfigId : Integer;
|
|
|
var
|
|
|
- qry : string;
|
|
|
+ lDir : String;
|
|
|
+
|
|
|
begin
|
|
|
- qry:='SELECT TCONF_ID FROM TESTCONFIG WHERE ' +
|
|
|
- 'TCONF_CPU_FK=%d AND ' +
|
|
|
- 'TCONF_OS_FK=%d AND ' +
|
|
|
- 'TCONF_VERSION_FK=%d AND ' +
|
|
|
- 'TCONF_CATEGORY_FK=%d AND ' +
|
|
|
- 'TCONF_SUBMITTER=''%s'' AND ' +
|
|
|
- 'TCONF_MACHINE=''%s'' AND ' +
|
|
|
- 'TCONF_COMMENT=''%s'' ';
|
|
|
- ConfigID:=IDQuery(format(qry,[TestCPUID, TestOSID, TestVersionID, TestCategoryID,
|
|
|
- Submitter, Machine, Comment]));
|
|
|
- GetTestConfigID:=ConfigID;
|
|
|
+ lDir:=ExtractFilePath(ExpandFileName(lCfg));
|
|
|
+ Result:=CheckFile(lDir,lData.logfile);
|
|
|
+ if Result then
|
|
|
+ Result:=CheckFile(lDir,lData.longlogfile);
|
|
|
end;
|
|
|
|
|
|
-function UpdateTestConfigID : boolean;
|
|
|
+
|
|
|
+function TDBDigestApplication.CreateTaskList(const aBaseConfig: TDigestConfig; const aBaseData: TTestRunData) : boolean;
|
|
|
+
|
|
|
var
|
|
|
- qry : string;
|
|
|
- firstRunID, lastRunID,PrevRunID : Integer;
|
|
|
- RunCount : Integer;
|
|
|
- AddCount : boolean;
|
|
|
+ lCfg,lFileName : String;
|
|
|
+ L : TStrings;
|
|
|
+ lConfig : TDigestConfig;
|
|
|
+ lData : TTestRunData;
|
|
|
+ lList : TList;
|
|
|
+
|
|
|
|
|
|
begin
|
|
|
- AddCount:=false;
|
|
|
- UpdateTestConfigID:=false;
|
|
|
- qry:=format('SELECT TCONF_FIRST_RUN_FK FROM TESTCONFIG WHERE TCONF_ID=%d',[ConfigID]);
|
|
|
- FirstRunID:=IDQuery(qry);
|
|
|
- if TestRunID<FirstRunID then
|
|
|
- begin
|
|
|
- Verbose(V_Warning,format('FirstRunID changed from %d to %d',[FirstRunID,TestRunID]));
|
|
|
- qry:=format('UPDATE TESTCONFIG SET TCONF_FIRST_RUN_FK=%d WHERE TCONF_ID=%d',
|
|
|
- [TestRunID,ConfigID]);
|
|
|
- if Not ExecuteQuery(qry,False) then
|
|
|
- Verbose(V_Warning,'Update of LastRunID failed');
|
|
|
- end;
|
|
|
- qry:=format('SELECT TCONF_LAST_RUN_FK FROM TESTCONFIG WHERE TCONF_ID=%d',[ConfigID]);
|
|
|
- LastRunID:=IDQuery(qry);
|
|
|
- if TestRunID>LastRunID then
|
|
|
- begin
|
|
|
- qry:=format('UPDATE TESTCONFIG SET TCONF_LAST_RUN_FK=%d WHERE TCONF_ID=%d',
|
|
|
- [TestRunID,ConfigID]);
|
|
|
- if not ExecuteQuery(qry,False) then
|
|
|
- Verbose(V_Warning,'Update of LastRunID failed');
|
|
|
- end
|
|
|
- else
|
|
|
- Verbose(V_Warning,format('LastRunID %di,new %d',[LastRunID,TestRunID]));
|
|
|
- qry:=format('SELECT TCONF_NEW_RUN_FK FROM TESTCONFIG WHERE TCONF_ID=%d',[ConfigID]);
|
|
|
- PrevRunID:=IDQuery(qry);
|
|
|
- if TestRunID<>PrevRunID then
|
|
|
- begin
|
|
|
- qry:=format('UPDATE TESTCONFIG SET TCONF_NEW_RUN_FK=%d WHERE TCONF_ID=%d',
|
|
|
- [TestRunID,ConfigID]);
|
|
|
- if not ExecuteQuery(qry,False) then
|
|
|
- Verbose(V_Warning,'Update of LastRunID failed');
|
|
|
- AddTestHistoryEntry(TestRunID,PrevRunID);
|
|
|
- AddCount:=true;
|
|
|
- end
|
|
|
- else
|
|
|
- Verbose(V_Warning,'TestRunID is equal to last!');
|
|
|
- qry:=format('SELECT TCONF_COUNT_RUNS FROM TESTCONFIG WHERE TCONF_ID=%d',[ConfigID]);
|
|
|
- RunCount:=IDQuery(qry);
|
|
|
- { Add one to run count }
|
|
|
- if AddCount then
|
|
|
+ Result:=False;
|
|
|
+ lFileName:=GetOptionValue('T','threadlist');
|
|
|
+ if not FileExists(lFileName) then
|
|
|
begin
|
|
|
- Inc(RunCount);
|
|
|
- qry:=format('UPDATE TESTCONFIG SET TCONF_COUNT_RUNS=%d WHERE TCONF_ID=%d',
|
|
|
- [RunCount,ConfigID]);
|
|
|
- if not ExecuteQuery(qry,False) then
|
|
|
- Verbose(V_Warning,'Update of TU_COUNT_RUNS failed');
|
|
|
+ Verbose(V_Normal,'No such file :'+lFileName);
|
|
|
+ Exit;
|
|
|
end;
|
|
|
- UpdateTestConfigID:=true;
|
|
|
+ L:=TStringList.Create;
|
|
|
+ try
|
|
|
+ l.LoadFromFile(lFileName);
|
|
|
+ Result:=True;
|
|
|
+ For lcfg in L do
|
|
|
+ begin
|
|
|
+ if not FileExists(lCfg) then
|
|
|
+ begin
|
|
|
+ Verbose(V_Warning,'No such file: '+lcfg);
|
|
|
+ Result:=False;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ lConfig:=aBaseConfig;
|
|
|
+ lData:=aBaseData;
|
|
|
+ lList:=FTasks.LockList;
|
|
|
+ ProcessConfigfile(lCfg,lConfig,lData);
|
|
|
+ if CheckConfigFiles(lCfg,lData) then
|
|
|
+ lList.Add(TThreadTask.Create(lCfg,lConfig,lData))
|
|
|
+ else
|
|
|
+ Result:=False;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ finally
|
|
|
+ l.Free;
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
-function InsertNewTestConfigId : longint;
|
|
|
-var
|
|
|
- qry : string;
|
|
|
+procedure TDBDigestApplication.TaskDone(Sender: TObject);
|
|
|
begin
|
|
|
- qry:='INSERT INTO TESTCONFIG '+
|
|
|
- '(TCONF_NEW_RUN_FK,TCONF_FIRST_RUN_FK,TCONF_LAST_RUN_FK,' +
|
|
|
- 'TCONF_CPU_FK,TCONF_OS_FK,TCONF_VERSION_FK,TCONF_CATEGORY_FK,'+
|
|
|
- 'TCONF_SUBMITTER,TCONF_MACHINE,TCONF_COMMENT,'+
|
|
|
- 'TCONF_NEW_DATE,TCONF_FIRST_DATE,TCONF_LAST_DATE) ';
|
|
|
- qry:=qry+format(' VALUES(%d,%d,%d,%d,%d,%d,%d,''%s'',''%s'',''%s'',''%s'',''%s'',''%s'') ',
|
|
|
- [TestRunID, TestRunID, TestRunID, TestCPUID,
|
|
|
- TestOSID, TestVersionID, TestCategoryID,
|
|
|
- Submitter, Machine, Comment,
|
|
|
- SqlDate(TestDate), SqlDate(TestDate), SqlDate(TestDate)]);
|
|
|
- qry:=qry+' RETURNING TCONF_ID';
|
|
|
- Result:=InsertQuery(qry);
|
|
|
- AddTestHistoryEntry(TestRunID,0);
|
|
|
+ InterlockedDecrement(FThreadCount);
|
|
|
+ StartThreads;
|
|
|
end;
|
|
|
|
|
|
-procedure UpdateTestConfig;
|
|
|
+Procedure TDBDigestApplication.StartThreads;
|
|
|
|
|
|
- begin
|
|
|
- if GetTestPreviousRunHistoryID(TestRunID) <> -1 then
|
|
|
- begin
|
|
|
- Verbose(V_DEBUG,format('TestRun %d already in TestHistory table',[TestRunID]));
|
|
|
- exit;
|
|
|
- end;
|
|
|
+var
|
|
|
+ L : TList;
|
|
|
+ lTask : TThreadTask;
|
|
|
|
|
|
- if GetTestConfigID >= 0 then
|
|
|
- begin
|
|
|
- if not UpdateTestConfigID then
|
|
|
- Verbose(V_Warning, ' Update of TESTCONFIG table failed');
|
|
|
- end
|
|
|
- else
|
|
|
+begin
|
|
|
+ L:=FTasks.LockList;
|
|
|
+ try
|
|
|
+ Verbose(V_DEBUG,Format('Starting tasks. Current thread count: %d remaining tasks: %d.',[FThreadCount,l.Count]));
|
|
|
+ While (L.Count>0) and (FThreadCount<FMaxThreads) do
|
|
|
begin
|
|
|
- if InsertNewTestConfigID = -1 then
|
|
|
- Verbose(V_Warning, ' Insert of new entry into TESTCONFIG table failed');
|
|
|
+ lTask:=TThreadTask(L[0]);
|
|
|
+ L.Delete(0);
|
|
|
+ Verbose(V_DEBUG,'Starting task for '+lTask.CfgFileName);
|
|
|
+ TProcessFileThread.Create(Self,lTask,@TaskDone);
|
|
|
+ InterlockedIncrement(FThreadCount);
|
|
|
end;
|
|
|
+ finally
|
|
|
+ FTasks.UnlockList;
|
|
|
end;
|
|
|
+end;
|
|
|
|
|
|
+procedure TDBDigestApplication.WaitForThreads;
|
|
|
+
|
|
|
+var
|
|
|
+ lDone : Boolean;
|
|
|
+ lList : TList;
|
|
|
|
|
|
begin
|
|
|
- ProcessConfigFile('dbdigest.cfg');
|
|
|
- ProcessCommandLine;
|
|
|
- If LogFileName<>'' then
|
|
|
+ Repeat
|
|
|
+ CheckSynchronize;
|
|
|
+ Sleep(100);
|
|
|
+ lList:=FTasks.LockList;
|
|
|
+ try
|
|
|
+ Verbose(V_DEBUG,Format('Waiting...(Todo: %d threads: %d)',[lList.Count,FThreadCount]));
|
|
|
+ lDone:=(lList.Count=0) and (FThreadCount=0);
|
|
|
+ finally
|
|
|
+ FTasks.UnlockList;
|
|
|
+ end
|
|
|
+ until ldone;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TDBDigestApplication.DoRun;
|
|
|
+
|
|
|
+var
|
|
|
+ lConfigFile : String;
|
|
|
+ lConfig : TDigestConfig;
|
|
|
+ lData : TTestRunData;
|
|
|
+begin
|
|
|
+ Terminate;
|
|
|
+ lConfigFile:=GetOptionValue('f','config');
|
|
|
+ if lConfigFile='' then
|
|
|
+ lConfigFile:='dbdigest.cfg';
|
|
|
+ lConfig:=Default(TDigestConfig);
|
|
|
+ lConfig.RelSrcDir:='tests/';
|
|
|
+ ReadSystemDBConfig(lConfig);
|
|
|
+ if not HasOption('T','threadlist') then
|
|
|
begin
|
|
|
- ConnectToDatabase(DatabaseName,HostName,UserName,Password,Port);
|
|
|
- if LongLogFileName<>'' then
|
|
|
- begin
|
|
|
-{$I-}
|
|
|
- Assign(LongLogFile,LongLogFileName);
|
|
|
- Reset(LongLogFile);
|
|
|
- If IOResult=0 then
|
|
|
- begin
|
|
|
- UseLongLog:=true;
|
|
|
- inc(LongLogOpenCount);
|
|
|
- end;
|
|
|
-{$I+}
|
|
|
- end;
|
|
|
- GetIDs;
|
|
|
- ProcessFile(LogFileName);
|
|
|
- UpdateTestRun;
|
|
|
- UpdateTestConfig;
|
|
|
- if UseLongLog then
|
|
|
- begin
|
|
|
- Close(LongLogFile);
|
|
|
- if LongLogOpenCount>1 then
|
|
|
- Verbose(V_Warning,format('LongLog file was read %d times.',[LongLogOpenCount]));
|
|
|
- end
|
|
|
+ lData:=Default(TTestRunData);
|
|
|
+ ProcessConfigFile(lConfigFile,lConfig,lData);
|
|
|
+ if ProcessCommandLine(lConfig,lData) then
|
|
|
+ Analyze(lConfig,lData);
|
|
|
end
|
|
|
else
|
|
|
- Verbose(V_ERROR,'Missing log file name');
|
|
|
+ begin
|
|
|
+ FMaxThreads:=StrToIntDef(GetOptionValue('j','threadcount'),4);
|
|
|
+ if ProcessCommandLine(lConfig,lData) then
|
|
|
+ if CreateTaskList(lConfig,lData) then
|
|
|
+ begin
|
|
|
+ StartThreads;
|
|
|
+ WaitForThreads;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+var
|
|
|
+ Application : TDBDigestApplication;
|
|
|
+
|
|
|
+begin
|
|
|
+ Application:=TDBDigestApplication.Create(Nil);
|
|
|
+ Application.Initialize;
|
|
|
+ Application.Run;
|
|
|
+ Application.Free;
|
|
|
end.
|