1 { Finds missing svn revisions in wiki list format, 2 used for updating the wiki pages fixes branch. 3 4 Usage: 5 ./findmissingsvnrevisionwiki -h 6 ./findmissingsvnrevisionwiki -s <svnlogfile> -w <wiki-list-file> 7 8 Copyright (C) 2017 Mattias Gaertner mattias@freepascal.org 9 10 This library is free software; you can redistribute it and/or modify it 11 under the terms of the GNU Library General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or (at your 13 option) any later version with the following modification: 14 15 As a special exception, the copyright holders of this library give you 16 permission to link this library with independent modules to produce an 17 executable, regardless of the license terms of these independent modules,and 18 to copy and distribute the resulting executable under terms of your choice, 19 provided that you also meet, for each linked independent module, the terms 20 and conditions of the license of that module. An independent module is a 21 module which is not derived from or based on this library. If you modify 22 this library, you may extend this exception to your version of the library, 23 but you are not obligated to do so. If you do not wish to do so, delete this 24 exception statement from your version. 25 26 This program is distributed in the hope that it will be useful, but WITHOUT 27 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 28 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License 29 for more details. 30 31 You should have received a copy of the GNU Library General Public License 32 along with this library; if not, write to the Free Software Foundation, 33 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 34 } 35 program find_missing_wiki_svnrevisions; 36 37 {$mode objfpc}{$H+} 38 39 uses 40 Classes, SysUtils, CustApp, LazFileUtils; 41 42 type 43 44 { TMissingWikiSVNRevisions } 45 46 TMissingWikiSVNRevisions = class(TCustomApplication) 47 protected 48 procedure DoRun; override; 49 procedure ParamError(Msg: string); 50 procedure ExtractSVN(Lines: TStrings; UserFilter: String); 51 procedure ExtractWikiRevs(Lines: TStrings); 52 public 53 constructor Create(TheOwner: TComponent); override; 54 destructor Destroy; override; 55 procedure WriteHelp; virtual; 56 end; 57 58 { TMissingWikiSVNRevisions } 59 60 procedure TMissingWikiSVNRevisions.DoRun; 61 var 62 ErrorMsg, SVNFile, WikiFile, Line, Rev, UserFilter: String; 63 SVNLines, WIKILines: TStringList; 64 i: Integer; 65 p: SizeInt; 66 begin 67 // quick check parameters 68 ErrorMsg:=CheckOptions('hs:w:u:', 'help svnlog wikilist user'); 69 if ErrorMsg<>'' then 70 ParamError(ErrorMsg); 71 72 // parse parameters 73 if HasOption('h', 'help') then begin 74 WriteHelp; 75 Halt; 76 end; 77 78 if not HasOption('s','svnlog') then begin 79 WriteHelp; 80 Halt; 81 end; 82 if not HasOption('w','wikilist') then begin 83 WriteHelp; 84 Halt; 85 end; 86 87 SVNFile:=ExpandFileNameUTF8(GetOptionValue('s','svnlog')); 88 if not FileExists(SVNFile) then 89 ParamError('svn file not found "'+SVNFile+'"'); 90 91 WikiFile:=ExpandFileNameUTF8(GetOptionValue('w','wikilist')); 92 if not FileExists(WikiFile) then 93 ParamError('wiki list file not found "'+WikiFile+'"'); 94 95 UserFilter:=GetOptionValue('u','user'); 96 97 SVNLines:=TStringList.Create; 98 SVNLines.LoadFromFile(SVNFile); 99 WIKILines:=TStringList.Create; 100 WIKILines.LoadFromFile(WikiFile); 101 102 ExtractSVN(SVNLines,UserFilter); 103 ExtractWikiRevs(WIKILines); 104 //writeln('SVN: ',SVNLines.Text); 105 //writeln('WIKI: ',WIKILines.Text); 106 107 // write missing svn revisions 108 writeln('Missing svn revisions:'); 109 for i:=0 to SVNLines.Count-1 do begin 110 Line:=SVNLines[i]; 111 p:=Pos(' ',Line); 112 Rev:=LeftStr(Line,p-1); 113 if WIKILines.IndexOf(Rev)>=0 then continue; 114 writeln('*',Line); 115 end; 116 117 // stop program loop 118 Terminate; 119 end; 120 121 procedure TMissingWikiSVNRevisions.ParamError(Msg: string); 122 begin 123 writeln('Invalid param: ',Msg); 124 writeln; 125 writeln('Usage: ',ExeName,' -h'); 126 Halt; 127 end; 128 129 procedure TMissingWikiSVNRevisions.ExtractSVN(Lines: TStrings; 130 UserFilter: String); 131 { Remove empty and separator lines. 132 Combine each log entry into a single line "*r12345 message" 133 134 ------------------------------------------------------------------------ 135 r54919 | martin | 2017-05-14 12:59:15 +0200 (So, 14 Mai 2017) | 1 line 136 137 Fixed compile ifdef 138 139 -> 140 141 *r54919 Fixed compile ifdef 142 } 143 const MaxCol=80; 144 var 145 i: Integer; 146 Line, Revision, UserName: String; 147 p, StartP: PChar; 148 begin 149 i:=0; 150 UserName:=''; 151 while i<Lines.Count do begin 152 Line:=Lines[i]; 153 p:=PChar(Line); 154 if (LeftStr(Line,10)='----------') or (Trim(Line)='') then begin 155 Lines.Delete(i); 156 end else if (p^='r') and (p[1] in ['0'..'9']) then begin 157 // revision 158 inc(p,1); 159 while p^ in ['0'..'9'] do inc(p); 160 Revision:=LeftStr(Line,p-PChar(Line)); // 'r12345' 161 while p^ in [' ','|'] do inc(p); 162 StartP:=p; 163 while not (p^ in [' ','|',#0]) do inc(p); 164 UserName:=copy(Line,StartP-PChar(Line)+1,p-StartP); 165 if (UserFilter<>'') and (UserName<>UserFilter) then 166 Lines.Delete(i) 167 else begin 168 Lines[i]:=Revision; 169 inc(i); 170 end; 171 end else begin 172 // comment 173 Line:=Trim(Line); 174 if (UserFilter='') or (UserName=UserFilter) then begin 175 if (i>0) and (length(Lines[i-1])<MaxCol) then begin 176 Line:=Lines[i-1]+' '+Line; 177 if length(Line)>MaxCol then 178 Line:=LeftStr(Line,MaxCol)+'...'; 179 Lines[i-1]:=Line; 180 end; 181 end; 182 Lines.Delete(i); 183 end; 184 end; 185 end; 186 187 procedure TMissingWikiSVNRevisions.ExtractWikiRevs(Lines: TStrings); 188 var 189 i: Integer; 190 Line: String; 191 p: PChar; 192 begin 193 i:=0; 194 while i<Lines.Count do begin 195 Line:=Lines[i]; 196 if Trim(Line)='' then begin 197 Lines.Delete(i); 198 end else begin 199 p:=PChar(Line); 200 if (p[0]='*') and (p[1]='r') and (p[2] in ['0'..'9']) then begin 201 inc(p,2); 202 while p^ in ['0'..'9'] do inc(p); 203 Lines[i]:=copy(Line,2,p-PChar(Line)-1); // 'r12345' 204 inc(i); 205 end else begin 206 writeln('WARNING: invalid wiki line: "',Line,'"'); 207 Lines.Delete(i); 208 end; 209 end; 210 end; 211 end; 212 213 constructor TMissingWikiSVNRevisions.Create(TheOwner: TComponent); 214 begin 215 inherited Create(TheOwner); 216 StopOnException:=True; 217 end; 218 219 destructor TMissingWikiSVNRevisions.Destroy; 220 begin 221 inherited Destroy; 222 end; 223 224 procedure TMissingWikiSVNRevisions.WriteHelp; 225 begin 226 writeln('Usage: ', ExeName, ' -s svn.log -w wikilist.txt [-u username]'); 227 writeln; 228 writeln('Shows svn log entries not listed in the wikilist.'); 229 writeln; 230 writeln('-h, --help'); 231 writeln(' show this help'); 232 writeln('-s <file>, --svnlog=<file>'); 233 writeln(' SVN log, e.g. "svn log --limit=1000 > log.txt"'); 234 writeln('-w <file>, --wikilist=<file>'); 235 writeln(' List in wiki format: Every line "*r12345 text"'); 236 writeln('-u <user>, --user=<user>'); 237 writeln(' only user '); 238 end; 239 240 var 241 Application: TMissingWikiSVNRevisions; 242 begin 243 Application:=TMissingWikiSVNRevisions.Create(nil); 244 Application.Title:='Find missing svn revisions in wiki'; 245 Application.Run; 246 Application.Free; 247 end. 248 249