unit dateiBeziehungen; {$mode objfpc}{$H+} interface uses classes, sysUtils, tools, regExpr; type tZeilenTyp = (ztSuche,ztZiel,ztQuelle,ztBefehl); tGenerischeAbhaengigkeit = class; tExpliziteAbhaengigkeit = class; tGenerischeAbhaengigkeiten = class(tFPList) private function rItem(idx: longint): tGenerischeAbhaengigkeit; inline; procedure wItem(idx: longint; neu: tGenerischeAbhaengigkeit); inline; public property items[idx: longint]: tGenerischeAbhaengigkeit read rItem write wItem; default; procedure kopiereVon(original: tGenerischeAbhaengigkeiten); procedure mrProper; function add(neu: tGenerischeAbhaengigkeit): longint; function last: tGenerischeAbhaengigkeit; end; tExpliziteAbhaengigkeiten = class(tFPList) private function rItem(idx: longint): tExpliziteAbhaengigkeit; inline; procedure wItem(idx: longint; neu: tExpliziteAbhaengigkeit); inline; public property items[idx: longint]: tExpliziteAbhaengigkeit read rItem write wItem; default; procedure kopiereVon(original: tExpliziteAbhaengigkeiten); procedure mrProper; function add(neu: tExpliziteAbhaengigkeit): longint; function last: tExpliziteAbhaengigkeit; procedure sort; end; // Die goldene Regel bzgl. Abhängigkeiten ist, // dass jedes Ziel nur ein Mal erzeugt werden kann und muss (logisch) // und somit für zwei Regeln mit Zielmengen A und B // A \cut B \neq \emptyset => A \cut B \in {A,B} // gilt. Von diesen beiden Regeln ist dann höchstens eine anzuwenden. // Mit den Informationen jeder einzelnen Quelle muss die gesamte Regel // konstruiert werden können. Das beinhaltet: // - weitere Quellen (per regex matchbar) // - auszuführende Befehle (darf von "weiteren Quellen" abhängen) // - erzeugte Ziele (darf von "weiteren Quellen" abhängen) tGenerischeAbhaengigkeit = class(tObject) private _machDatei,_pruefSummenDatei: string; _quellens,_zieles: array of tDateienMitDaten; _dats: tDateienMitDaten; function rQuellen(idx: longint): tDateienMitDaten; function rZiele(idx: longint): tDateienMitDaten; function quellersetzung(var worin: string; quellen: tDateienMitDaten; momentanePosition: longint): boolean; function zieleHinzufuegen(ziele, quellen: tDateienMitDaten; zielFkt: string): boolean; function findeMehrZiele(ziele, quellen: tDateienMitDaten): boolean; function matchCount: longint; public quellenREs: array of string; // regexe der Quellen - nur deshalb kein tRegExpr, weil es ohnehin zuerst substituiert werden muss zieleFkt,befehleFkt: tStringlist; property quellen[idx: longint]: tDateienMitDaten read rQuellen; property ziele[idx: longint]: tDateienMitDaten read rZiele; constructor create(dats: tDateienMitDaten; machDatei,pruefSummenDatei: string); destructor destroy; override; function findeQuellen(dats: tDateienMitDaten): boolean; procedure generiereErben(var es: tExpliziteAbhaengigkeiten); end; tExpliziteAbhaengigkeit = class(tObject) ziele,quellen: tDateienMitDaten; befehle: tStringlist; constructor create; destructor destroy; override; function hatQuelleVonAlsZiel(abh: tExpliziteAbhaengigkeit): boolean; function ersetzbarDurch(abh: tExpliziteAbhaengigkeit): boolean; function pruefeObZuTun: boolean; function dump: string; end; tMach = class private _machDatei,_pruefsummenDatei: string; _oriAbh: tGenerischeAbhaengigkeiten; _mglAbh: tExpliziteAbhaengigkeiten; _dats: tDateienMitDaten; _ign: array of tRegExpr; function liesMachDatei: boolean; function liesPruefsummenfile: boolean; function sammleDateien(wo: string; rekursiv: boolean): longint; public constructor create(machDatei, pruefSummenDatei: string); destructor destroy; override; procedure erzeugeRegeln; procedure findeWasZuTunIst; procedure tueWasZuTunIst(unsicher: boolean; ausgabeDatei: string); function anzOriAbh: longint; inline; function anzMglAbh: longint; inline; function anzDats: longint; inline; end; procedure allgemeineErsetzungen(var worin: string; machDatei: string); implementation uses lowlevelunit, mystringlistunit, systemunit; // tGenerischeAbhaengigkeiten ************************************************************ function tGenerischeAbhaengigkeiten.rItem(idx: longint): tGenerischeAbhaengigkeit; begin result:=tGenerischeAbhaengigkeit(get(idx)); end; procedure tGenerischeAbhaengigkeiten.wItem(idx: longint; neu: tGenerischeAbhaengigkeit); begin put(idx,neu); end; procedure tGenerischeAbhaengigkeiten.kopiereVon(original: tGenerischeAbhaengigkeiten); var i: longint; begin clear; for i:=0 to original.count-1 do add(original[i]); end; procedure tGenerischeAbhaengigkeiten.mrProper; var i: longint; begin for i:=0 to count-1 do items[i].free; clear; end; function tGenerischeAbhaengigkeiten.add(neu: tGenerischeAbhaengigkeit): longint; var i: longint; begin for i:=0 to count-1 do if items[i]=neu then fehler('Fehler: Ich soll etwas zur Liste hinzufügen, was schon drin ist!'); result:=inherited add(neu); end; function tGenerischeAbhaengigkeiten.last: tGenerischeAbhaengigkeit; begin result:=tGenerischeAbhaengigkeit(inherited last); end; // tExpliziteAbhaengigkeiten ************************************************************ function tExpliziteAbhaengigkeiten.rItem(idx: longint): tExpliziteAbhaengigkeit; begin result:=tExpliziteAbhaengigkeit(get(idx)); end; procedure tExpliziteAbhaengigkeiten.wItem(idx: longint; neu: tExpliziteAbhaengigkeit); begin put(idx,neu); end; procedure tExpliziteAbhaengigkeiten.kopiereVon(original: tExpliziteAbhaengigkeiten); var i: longint; begin clear; for i:=0 to original.count-1 do add(original[i]); end; procedure tExpliziteAbhaengigkeiten.mrProper; var i: longint; begin for i:=0 to count-1 do items[i].free; clear; end; function tExpliziteAbhaengigkeiten.add(neu: tExpliziteAbhaengigkeit): longint; var i: longint; begin for i:=0 to count-1 do if items[i]=neu then fehler('Fehler: Ich soll etwas zur Liste hinzufügen, was schon drin ist!'); result:=inherited add(neu); end; function tExpliziteAbhaengigkeiten.last: tExpliziteAbhaengigkeit; begin result:=tExpliziteAbhaengigkeit(inherited last); end; procedure tExpliziteAbhaengigkeiten.sort; var i,j,k,pLen: longint; perm: array of longint; tmp: tExpliziteAbhaengigkeit; bedingungen: array of tPoint; nehmbare: array of byte; // 0 = ja, 1 = nein, 2 = nie wieder (schon genommen) fortschritt: boolean; begin // Permutation initialisieren setlength(perm,count); for i:=0 to length(perm)-1 do perm[i]:=count; // sollte ohnehin überschrieben werden, aber "count" sorgt unten für einen Fehler! setlength(bedingungen,0); // aka "y hängt (direkt) von x ab" for i:=0 to count-1 do for j:=0 to count-1 do if (i<>j) and (items[i].hatQuelleVonAlsZiel(items[j])) then begin setlength(bedingungen,length(bedingungen)+1); bedingungen[length(bedingungen)-1].x:=i; bedingungen[length(bedingungen)-1].y:=j; end; setlength(nehmbare,count); for i:=0 to length(nehmbare)-1 do nehmbare[i]:=0; pLen:=0; while pLen=0 then begin tmp:=items[i]; j:=i; while perm[j]<>i do begin k:=perm[j]; perm[j]:=-1; items[j]:=items[k]; j:=k; end; items[j]:=tmp; perm[j]:=-1; end; end; // tGenerischeAbhaengigkeit ************************************************************** constructor tGenerischeAbhaengigkeit.create(dats: tDateienMitDaten; machDatei,pruefSummenDatei: string); begin inherited create; _dats:=dats; setlength(quellenREs,0); zieleFkt:=tStringlist.create; befehleFkt:=tStringlist.create; setlength(_quellens,0); setlength(_zieles,0); _machDatei:=machDatei; _pruefSummenDatei:=pruefSummenDatei; end; destructor tGenerischeAbhaengigkeit.destroy; var i: longint; begin for i:=0 to length(_quellens)-1 do _quellens[i].free; setLength(_quellens,0); for i:=0 to length(quellenREs)-1 do setlength(quellenREs[i],0); setlength(quellenREs,0); for i:=0 to length(_zieles)-1 do _zieles[i].free; setLength(_zieles,0); zieleFkt.free; befehleFkt.free; for i:=0 to length(_quellens)-1 do _quellens[i].free; setlength(_quellens,0); inherited destroy; end; function tGenerischeAbhaengigkeit.rQuellen(idx: longint): tDateienMitDaten; begin result:=_quellens[idx]; end; function tGenerischeAbhaengigkeit.rZiele(idx: longint): tDateienMitDaten; begin result:=_zieles[idx]; end; function tGenerischeAbhaengigkeit.quellersetzung(var worin: string; quellen: tDateienMitDaten; momentanePosition: longint): boolean; var s,anfang,mitte,numStr: string; i,li,re,qNum: longint; tmpRE: tRegExpr; begin result:=true; for qNum:=-byte(momentanePosition>0) to momentanePosition-1 do begin if qNum<0 then numStr:='' else numStr:=inttostr(qnum); s:=quellen[qnum+byte(qnum<0)].name; ersetzeAlleVorkommen(worin,'%in'+numStr+'%',s); // %in% s:=extractfilename(s); ersetzeAlleVorkommen(worin,'%ifile'+numStr+'%',s); // %ifile% if pos('.',s)>0 then delete(s,pos('.',s),length(s)); ersetzeAlleVorkommen(worin,'%basename'+numStr+'%',s); // %basename% end; while pos('%dirname',worin)>0 do begin // %dirname% anfang:=erstesArgument(worin,'%dirname',false); mitte:=erstesArgument(worin,'%',false); if mitte='' then qNum:=0 else qNum:=strtoint(erstesArgument(mitte,',',true)); if mitte='' then li:=0 else li:=strtoint(erstesArgument(mitte,',',true)); if mitte='' then re:=-1 else re:=strtoint(erstesArgument(mitte,',',true)); if qNum>=momentanePosition then fehler('Quellersetzung sieht ''%dirname%'' für Quelle Nummer '+inttostr(qNum)+' an Position '+inttostr(momentanePosition)+'.'); s:=extractfilepath(quellen[qnum].name); if rightStr(s,1)='/' then delete(s,length(s),1); i:=anzCs('/',s)+1; if li<0 then li:=li+i; if re<0 then re:=re+i; while li>0 do begin dec(li); dec(re); erstesArgument(s,'/',false); end; mitte:=''; while re>=0 do begin dec(re); mitte:=mitte+'/'+erstesArgument(s,'/',false); end; delete(mitte,1,1); worin:=anfang+mitte+worin; end; allgemeineErsetzungen(worin,_machDatei); // %DIRNAME% %num'...'% result:=false; tmpRE:=tRegExpr.create; for qNum:=-byte(momentanePosition>0) to momentanePosition-1 do begin if qNum<0 then numStr:='' else numStr:=inttostr(qnum); s:=quellen[qnum+byte(qnum<0)].name; while pos('%nurmit'+numStr+'''',worin)>0 do begin // %nurmit'...'% anfang:=erstesArgument(worin,'%nurmit'+numStr+'''',false); tmpRE.expression:=erstesArgument(worin,'''%',false); if not tmpRE.exec(s) then begin tmpRE.free; exit; end; worin:=anfang+worin; end; while pos('%nurohne'+numStr+'''',worin)>0 do begin // %nurohne'...'% anfang:=erstesArgument(worin,'%nurohne'+numStr+'''',false); tmpRE.expression:=erstesArgument(worin,'''%',false); if tmpRE.exec(s) then begin tmpRE.free; exit; end; worin:=anfang+worin; end; end; result:=true; tmpRE.free; end; function tGenerischeAbhaengigkeit.zieleHinzufuegen(ziele, quellen: tDateienMitDaten; zielFkt: string): boolean; var i,ebene,ende: longint; s,t,u: string; wasda: boolean; sR: tSearchRec; begin result:=false; if pos('{',zielFkt)=0 then begin if not quellersetzung(zielFkt,quellen,quellen.count) then exit; if pos('*',zielFkt)=0 then begin zielFkt:=unescape(zielFkt); wasda:=false; for i:=0 to _dats.count-1 do if zielFkt=_dats[i].name then begin wasda:=true; ziele.add(_dats[i]); end; if not wasda then begin result:=true; _dats.add(tDateiMitDatum.create); _dats.last.name:=zielFkt; _dats.last.aktuell:=aNichtVorhanden; ziele.add(_dats[i]); end; end else begin i:=findFirst(zielFkt,$3f,sR); while i=0 do begin zieleHinzufuegen(ziele,quellen,extractFileDir(zielFkt)+'/'+sR.name); i:=findNext(sR); end; findClose(sR); end; end else begin ende:=pos('{',zielFkt); ebene:=1; while (ebene>0) or (zielFkt[ende]<>'}') do begin inc(ende); case zielFkt[ende] of '{': inc(ebene); '}': dec(ebene); end{of case}; end; s:=copy(zielFkt,1,pos('{',zielFkt)-1); t:=copy(zielFkt,pos('{',zielFkt)+1,ende-pos('{',zielFkt)-1); u:=copy(zielFkt,ende+1,length(zielFkt)); if unescapedpos('..',t)>0 then begin for i:=strtoint(copy(t,1,unescapedpos('..',t)-1)) to strtoint(copy(t,unescapedpos('..',t)+2,length(t))) do zieleHinzufuegen(ziele,quellen,s+inttostr(i)+u); end else begin t:=t+','; while unescapedpos(',',t)>0 do begin zieleHinzufuegen(ziele,quellen,s+copy(t,1,unescapedpos(',',t)-1)+u); delete(t,1,unescapedpos(',',t)); end; end; end; end; function tGenerischeAbhaengigkeit.findeMehrZiele(ziele, quellen: tDateienMitDaten): boolean; var i: longint; begin result:=false; for i:=0 to zieleFkt.count-1 do if zieleHinzufuegen(ziele,quellen,zieleFkt[i]) then result:=true; end; function tGenerischeAbhaengigkeit.matchCount: longint; begin if length(_quellens)<>length(_zieles) then fehler('unterschiedlich viele Sätze an Quellen ('+inttostr(length(_quellens))+') und Zielen ('+inttostr(length(_zieles))+').'); result:=length(_quellens); end; function tGenerischeAbhaengigkeit.findeQuellen(dats: tDateienMitDaten): boolean; var i,lastI: longint; idx: array of longint; tmpQs: tDateienMitDaten; // hierin wird die momentan betrachte Kombination von Quellen gespeichert s: string; tmpRE: tRegExpr; begin result:=false; for i:=0 to length(_quellens)-1 do _quellens[i].free; setlength(_quellens,0); for i:=0 to length(_zieles)-1 do _zieles[i].free; setlength(_zieles,0); if length(quellenREs)=0 then exit; tmpRE:=tRegExpr.create; tmpQs:=tDateienMitDaten.create; tmpQs.count:=length(quellenREs); setlength(idx,tmpQs.count); for i:=0 to length(idx)-1 do begin idx[i]:=-1; tmpQs[i]:=nil; end; lastI:=-1; repeat if assigned(tmpQs[0]) then i:=length(idx)-1 else i:=0; while (i>=0) and (ilastI then begin // wir betrachten eine neue Stelle, s:=quellenREs[i]; // daher ist der RegEx nicht mehr aktuell if not quellErsetzung(s,tmpQs,i) then begin // regex-substitution nicht erfolgreich - idx[i]:=-1; // wird behandelt wie nie passender regex tmpQs[i]:=nil; dec(i); continue; end; tmpRE.expression:=s; lastI:=i; end; repeat inc(idx[i]); until (idx[i]>=dats.count) or (tmpRE.exec(dats[idx[i]].name)); if idx[i]>=dats.count then begin // Überlauf idx[i]:=-1; tmpQs[i]:=nil; dec(i); continue; end; tmpQs[i]:=dats[idx[i]]; inc(i); // nächste Stelle if i>=length(idx) then // zu weit? break; // dann fertig idx[i]:=-1; // sonst initialisieren end; if i<0 then break; // Überlauf auf -1 => fertig setlength(_quellens,length(_quellens)+1); _quellens[length(_quellens)-1]:=tDateienMitDaten.create; for i:=0 to tmpQs.count-1 do _quellens[length(_quellens)-1].add(tmpQs[i]); until false; tmpRE.free; tmpQs.free; setlength(idx,0); setlength(_zieles,length(_quellens)); for i:=0 to length(_zieles)-1 do begin _zieles[i]:=tDateienMitDaten.create; if findeMehrZiele(_zieles[i],_quellens[i]) then result:=true; end; end; procedure tGenerischeAbhaengigkeit.generiereErben(var es: tExpliziteAbhaengigkeiten); var i,j: longint; s: string; neuSums: tMyStringList; begin neuSums:=tMyStringList.create; for i:=0 to matchCount-1 do begin es.add(tExpliziteAbhaengigkeit.create); for j:=0 to quellen[i].count-1 do es.last.quellen.add(quellen[i][j]); for j:=0 to ziele[i].count-1 do es.last.ziele.add(ziele[i][j]); for j:=0 to befehleFkt.count-1 do begin s:=befehleFkt[j]; if quellersetzung(s,quellen[i],quellen[i].count) then es.last.befehle.add(s); end; if es.last.befehle.count=0 then fehler( 'Keine Befehle auszuführen für explizite Abhängigkeit!'#10+ 'Befehle:'#10+ befehleFkt.text+ 'Quellen:'#10+ quellen[i].toString ); if quellen[i].count + ziele[i].count > 0 then begin // sha512summen erneuern s:='sed "'; for j:=0 to quellen[i].count-1 do s:=s+'/\s'+escape(quellen[i][j].name,'./','\')+'\$/d; '; for j:=0 to ziele[i].count-1 do s:=s+'/\s'+escape(ziele[i][j].name,'./','\')+'\$/d; '; s:=s+'" -i "'+_pruefsummenDatei+'"'; es.last.befehle.add(s); s:='sha512sum'; for j:=0 to quellen[i].count-1 do neuSums.add(quellen[i][j].name); for j:=0 to ziele[i].count-1 do neuSums.add(ziele[i][j].name); neuSums.sort; neuSums.uniq('-'); for j:=0 to neuSums.count-1 do s:=s+' "'+escape(neuSums[j],'"\','\')+'"'; s:=s+' >> '+_pruefsummenDatei; es.last.befehle.add(s); end; end; neuSums.free; end; // tExpliziteAbhaengigkeit ************************************************************** constructor tExpliziteAbhaengigkeit.create; begin inherited create; quellen:=tDateienMitDaten.create; ziele:=tDateienMitDaten.create; befehle:=tStringlist.create; end; destructor tExpliziteAbhaengigkeit.destroy; begin quellen.free; ziele.free; befehle.free; inherited destroy; end; function tExpliziteAbhaengigkeit.hatQuelleVonAlsZiel(abh: tExpliziteAbhaengigkeit): boolean; var i,j: longint; begin result:=true; for i:=0 to ziele.count-1 do for j:=0 to abh.quellen.count-1 do if abh.quellen[j].name = ziele[i].name then exit; result:=false; end; function tExpliziteAbhaengigkeit.ersetzbarDurch(abh: tExpliziteAbhaengigkeit): boolean; var i,j: longint; begin result:=true; for i:=0 to ziele.count-1 do begin result:=false; for j:=0 to abh.ziele.count-1 do if abh.ziele[j].name = ziele[i].name then result:=true; if not result then exit; end; end; function tExpliziteAbhaengigkeit.pruefeObZuTun: boolean; var i: longint; quA,ziA: tAktualitaet; begin quA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Quellen aktuell sind for i:=0 to quellen.count-1 do if quellen[i].aktuell<>aAktuell then // nicht aktuelle Quellen quA:=aWirdErneuert; // werden sicherlich erneuert werden ziA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Ziele aktuell sind for i:=0 to ziele.count-1 do ziA:=min(ziA,ziele[i].aktuell); result:=ziA'/') and not fileexists(machDatei+'Machdatei') do begin delete(machDatei,length(machDatei),1); machDatei:=extractfilepath(machDatei); end; machDatei:=machDatei+'Machdatei'; end; _machDatei:=machDatei; if not fileexists(_machDatei) then fehler('Datei '''+_machDatei+''' existiert nicht!'); // pruefSummenDatei teilweise prüfen und setzen if pruefSummenDatei='' then pruefSummenDatei:=extractfilepath(_machDatei)+'.summen'; _pruefsummenDatei:=pruefSummenDatei; // finale Prüfung / finales Einlesen if not liesMachDatei then fehler('Datei '''+_machDatei+''' ist fehlerhaft!'); if not liesPruefsummenfile then fehler('Datei '''+_pruefsummenDatei+''' ist fehlerhaft!'); end; destructor tMach.destroy; var i: longint; begin _oriAbh.mrProper; _oriAbh.free; _mglAbh.mrProper; _mglAbh.free; _dats.mrProper; _dats.free; for i:=0 to length(_ign)-1 do _ign[i].free; setlength(_ign,0); inherited destroy; end; function tMach.liesMachDatei: boolean; var f: tMyStringList; s,t: string; na: tGenerischeAbhaengigkeit; rek: boolean; posi: longint; wasWar,wasIst: tZeilenTyp; procedure aufraeumen; begin f.free; na.free; end; begin result:=false; na:=tGenerischeAbhaengigkeit.create(_dats,_machDatei,_pruefSummenDatei); wasWar:=ztSuche; f:=tMyStringList.create; f.loadFromFile(_machDatei); f.add('%%DATEIENDE%%'); if not f.unfoldMacros then begin f.free; gibAus('tMach.liesMachDatei: unfoldMacros fehlgeschlagen!',3); exit; end; s:=''; while f.readln(s) do begin if rightStr(s,1)=';' then // ein Befehl(steil) wasIst:=ztBefehl else if rightStr(s,1)=':' then // ein Ziel wasIst:=ztZiel else if (leftStr(s,1)='^') and (rightStr(s,1)='$') then // eine Quelle wasIst:=ztQuelle else // eine zu überwachende Datei wasIst:=ztSuche; if wasIst in [ztBefehl] then delete(s,length(s),1); if (wasWar=ztBefehl) and (wasIst<>ztBefehl) then begin _oriAbh.add(na); na:=tGenerischeAbhaengigkeit.create(_dats,_machDatei,_pruefsummenDatei); end; if s='%%DATEIENDE%%' then break; case wasIst of ztSuche: begin allgemeineErsetzungen(s,_machDatei); if startetMit('!',s) then begin setlength(_ign,length(_ign)+1); _ign[length(_ign)-1]:=tRegExpr.create; _ign[length(_ign)-1].expression:=s; end else begin rek:=startetMit('-r',s); while s<>'' do if sammleDateien(erstesArgument(s),rek)=0 then begin f.stepBack; f.readln(s); gibAus('Fehler: Ich habe etwas zu überwachendes nicht gefudnen ('''+s+''').',3); aufraeumen; exit; end; end; end; ztBefehl: begin while unescapedpos(';',s)>0 do begin posi:=unescapedpos(';',s); s:=trim(leftStr(s,posi-1))+' && '+trim(rightStr(s,length(s)-posi)); end; while pos(';;',s)>0 do delete(s,pos(';;',s),1); na.befehleFkt.add(s); end; ztZiel: while s<>'' do begin t:=erstesArgument(s); if rightStr(t,1)=':' then delete(t,length(t),1); na.zieleFkt.add(t); end; ztQuelle: begin setlength(na.quellenREs,length(na.quellenREs)+1); na.quellenREs[length(na.quellenREs)-1]:=s; end; end{of case}; wasWar:=wasIst; end; if s<>'%%DATEIENDE%%' then gibAus('Interner Fehler! Die letzte Regel wird vsl. nicht beachtet!',3); aufraeumen; result:=true; end; function tMach.liesPruefsummenfile: boolean; var f: textfile; i,j: longint; gutschlecht: tMyStringlistBArray; gefunden,gut: boolean; begin result:=false; if _pruefsummenDatei='' then begin gibAus('Fehler: Leerer Name als Summendatei angegeben!',3); exit; end; if not fileexists(_pruefsummenDatei) then begin assignfile(f,_pruefsummenDatei); rewrite(f); closefile(f); end; if not fileexists(_pruefsummenDatei) then begin gibAus('Fehler: Ich bin nicht in der Lage, die bisher nicht existierende Datei '''+_pruefsummenDatei+''' anzulegen!',3); exit; end; gutschlecht:=testeSummen(_pruefsummenDatei); for gut:=false to true do for i:=0 to gutschlecht[gut].count-1 do begin gefunden:=false; for j:=0 to _dats.count-1 do if _dats[j].name=gutschlecht[gut][i] then begin if gut then _dats[j].aktuell:=aAktuell else _dats[j].aktuell:=aVeraltet; gefunden:=true; break; end; if not gefunden then begin if not gut then begin // dateien mit ungültiger Prüfsumme können auch nicht vorhanden sein, _dats.add(tDateiMitDatum.create); // dann werden sie einfach eingefügt _dats.last.name:=gutschlecht[gut][i]; _dats.last.aktuell:=aNichtVorhanden; continue; end; gibAus('Fehler: In der Summendatei gibt es eine Datei mit gültiger Prüfsumme, die ich nicht finden kann: '''+gutschlecht[gut][i]+'''!',3); for gefunden:=false to true do gutschlecht[gefunden].free; exit; end; end; for gefunden:=false to true do gutschlecht[gefunden].free; result:=true; end; function tMach.sammleDateien(wo: string; rekursiv: boolean): longint; var sr: tSearchRec; err,i: longint; weglassen: boolean; begin result:=0; err:=FindFirst(wo,fareadOnly or faHidden or faSysFile or (byte(rekursiv)*faDirectory),sr); while err=0 do begin weglassen:=false; for i:=0 to length(_ign)-1 do weglassen:=weglassen or _ign[i].exec(extractfilepath(wo)+sr.name); if not weglassen then begin if sr.attr and faDirectory <> 0 then begin if rekursiv and (sr.name<>'.') and (sr.name<>'..') then result:=result+sammleDateien(extractfilepath(wo)+sr.name+'/*',rekursiv); end else begin inc(result); _dats.add(tDateiMitDatum.create); _dats.last.name:=extractfilepath(wo)+sr.name; _dats.last.aktuell:=aVeraltet; end; end; err:=FindNext(sr); end; findClose(sr); end; procedure tMach.erzeugeRegeln; var i: longint; neues: boolean; begin repeat neues:=false; for i:=0 to _oriAbh.count-1 do if _oriAbh[i].findeQuellen(_dats) then neues:=true; // neue Dateien sind entstanden until not neues; for i:=0 to _oriAbh.count-1 do _oriAbh[i].generiereErben(_mglAbh); end; procedure tMach.findeWasZuTunIst; var i,j: longint; neues: boolean; zuTun: array of boolean; begin setlength(zuTun,_mglAbh.count); for i:=0 to length(zuTun)-1 do zuTun[i]:=false; // schauen, welche Regeln angewandt werden müssen repeat neues:=false; for i:=0 to length(zuTun)-1 do if not zuTun[i] then if _mglAbh[i].pruefeObZuTun then begin zuTun[i]:=true; neues:=true; end; until not neues; // schauen, welche Regeln redundant sind for i:=0 to length(zuTun)-1 do if zuTun[i] then for j:=0 to length(zuTun)-1 do if zuTun[j] and (i<>j) and _mglAbh[i].ersetzbarDurch(_mglAbh[j]) then begin _mglAbh[j].quellen.append(_mglAbh[i].quellen); zuTun[i]:=false; break; end; for i:=length(zuTun)-1 downto 0 do if not zuTun[i] then begin _mglAbh[i].free; _mglAbh.delete(i); end; setlength(zuTun,0); // anzuwendende Regeln sortieren _mglAbh.sort; end; procedure tMach.tueWasZuTunIst(unsicher: boolean; ausgabeDatei: string); var i,j: longint; ausg: textfile; befehle,alleDateien: tMyStringlist; lokTest: tRegExpr; begin befehle:=tMyStringlist.create; for i:=0 to _mglAbh.count-1 do for j:=0 to _mglAbh[i].befehle.count-1 do befehle.add(_mglAbh[i].befehle[j]); if not unsicher then begin lokTest:=tRegExpr.create; if (ausgabeDatei='') or (extractfilepath(ausgabeDatei)=extractfilepath(_pruefsummenDatei)) then lokTest.expression:=unterVerzeichnisRegex([_pruefsummenDatei]) else lokTest.expression:=unterVerzeichnisRegex([ausgabeDatei,_pruefsummenDatei]); alleDateien:=_dats.toMyStringList; alleDateien.grep('^\.uralt\.$',true); for i:=0 to befehle.count-1 do testeObBefehlLokal(befehle[i],extractfiledir(ausgabeDatei),alleDateien,lokTest); alleDateien.free; lokTest.free; end; if _mglAbh.count=0 then befehle.add('echo "Es gibt hier nichts zu tun!"'); if ausgabeDatei='' then begin gibAus('befehle:',3); for i:=0 to befehle.count-1 do writeln(befehle[i]); end else begin assignFile(ausg,ausgabeDatei); rewrite(ausg); writeln(ausg,'set -e'); for i:=0 to befehle.count-1 do writeln(ausg,'('+befehle[i]+') || (printf ''In\n"%s"\n'' "'+escape(befehle[i],'\"','\')+'"; read -p "ist ein Fehler aufgetreten! ... "; exit 1)'); closeFile(ausg); end; befehle.free; end; function tMach.anzOriAbh: longint; begin result:=_oriAbh.count; end; function tMach.anzMglAbh: longint; begin result:=_mglAbh.count; end; function tMach.anzDats: longint; begin result:=_dats.count; end; // allgemeine Funktionen procedure allgemeineErsetzungen(var worin: string; machDatei: string); var i: longint; s,anfang,mitte: string; begin s:=extractfilepath(machDatei); if rightStr(s,1)='/' then delete(s,length(s),1); ersetzeAlleVorkommen(worin,'%DIRNAME%',s); while pos('%num''',worin)>0 do begin anfang:=erstesArgument(worin,'%num'''); mitte:=erstesArgument(worin,'''%'); for i:=length(mitte) downto 1 do if mitte[i] in ['0'..'9'] then break else delete(mitte,i,1); for i:=length(mitte) downto 1 do if not (mitte[i] in ['0'..'9']) then begin delete(mitte,1,i); break; end; worin:=anfang+mitte+worin; end; end; end.