source: trunk/USvnZero.pas

Last change on this file was 11, checked in by chronos, 19 months ago
  • Modified: Remove pristine files instead of zero their content.
File size: 9.3 KB
Line 
1unit USvnZero;
2
3interface
4
5uses
6 Classes, SysUtils, FileUtil, USubversion, UCommon;
7
8type
9
10 { TSvnZero }
11
12 TSvnZero = class(TSubversion)
13 private
14 Subversion: TSubversion;
15 FWorkingCopyRootPath: string;
16 FWorkingCopyRootPathCurrentDir: string;
17 function GetWorkingCopyRootPath(FileName: string): string;
18 function CheckErrorOutput(Text: string): Boolean;
19 function GetFileInfoByMd5(Md5Hash: string): TSubversionInfo;
20 function GetFileInfoBySha1(Sha1Hash: string): TSubversionInfo;
21 procedure ZeroPristine;
22 procedure RestorePristine;
23 function GetWorkingCopyRootPathFromText(Text: string): string;
24 function GetSvnDir(FileName: string): string;
25 function GetPristineDir(FileName: string): string;
26 function GetCommand(Parameters: array of string): string;
27 function IsWorkingCopyCommand(Command: string): Boolean;
28 public
29 procedure Execute(Parameters: array of string); override;
30 constructor Create;
31 destructor Destroy; override;
32 end;
33
34
35implementation
36
37uses
38 SQLite3, SQLite3Wrap;
39
40const
41 SvnBaseExt = '.svn-base';
42
43resourcestring
44 SZeroedFilesCount = 'Zeroed files count: %d';
45 SPristineRecoveryFail = 'Pristine file recovery not successful';
46
47procedure TSvnZero.ZeroPristine;
48var
49 Files: TStrings;
50 I: Integer;
51 Dir: string;
52 FileName: string;
53 ZeroedFilesCount: Integer;
54begin
55 ZeroedFilesCount := 0;
56 Dir := GetPristineDir('.');
57 if DirectoryExists(Dir) then
58 try
59 Files := FindAllFiles(Dir, '*' + SvnBaseExt);
60 for I := 0 to Files.Count - 1 do begin
61 FileName := Files[I];
62 DeleteFile(FileName);
63 MakeFileWriteable(FileName);
64 Inc(ZeroedFilesCount);
65 end;
66 finally
67 Files.Free;
68 end;
69 //StandardOutput := StandardOutput + Format(SZeroedFilesCount, [ZeroedFilesCount]) + LineEnding;
70end;
71
72procedure TSvnZero.RestorePristine;
73begin
74end;
75
76function TSvnZero.GetWorkingCopyRootPathFromText(Text: string): string;
77var
78 Index: Integer;
79const
80 StartText = 'Working Copy Root Path: ';
81begin
82 Result := '';
83 Index := Pos(StartText, Text);
84 if Index > 0 then begin
85 Result := Copy(Text, Index + Length(StartText), MaxInt);
86 Index := Pos(LineEnding, Result);
87 if Index > 0 then begin
88 Delete(Result, Index, MaxInt);
89 end;
90 end;
91end;
92
93function TSvnZero.GetSvnDir(FileName: string): string;
94begin
95 Result := GetWorkingCopyRootPath(FileName) + DirectorySeparator + '.svn';
96end;
97
98function TSvnZero.GetPristineDir(FileName: string): string;
99begin
100 Result := GetSvnDir(FileName) + DirectorySeparator + 'pristine';
101end;
102
103function TSvnZero.GetCommand(Parameters: array of string): string;
104var
105 I: Integer;
106begin
107 Result := '';
108 I := 0;
109 while (I < Length(Parameters)) do begin
110 if Copy(Parameters[I], 1, 1) <> '-' then begin
111 Result := Parameters[I];
112 Break;
113 end;
114 Inc(I);
115 end;
116end;
117
118function TSvnZero.IsWorkingCopyCommand(Command: string): Boolean;
119begin
120 Result := (Command = 'update') or (Command = 'commit');
121end;
122
123procedure TSvnZero.Execute(Parameters: array of string);
124var
125 StandardOutputMerged: string;
126 LastErrorOutput: string;
127begin
128 Subversion.PrintOutput := PrintOutput;
129 Subversion.PrintCommand := PrintCommand;
130 LastErrorOutput := '';
131 StandardOutputMerged := '';
132 while True do begin
133 Subversion.Execute(Parameters);
134 ErrorOutput := Subversion.ErrorOutput;
135 StandardOutputMerged := StandardOutputMerged + Subversion.StandardOutput;
136 if CheckErrorOutput(ErrorOutput) then begin
137 if LastErrorOutput = ErrorOutput then begin
138 WriteLn(SPristineRecoveryFail);
139 Break;
140 end;
141 end else Break;
142 LastErrorOutput := ErrorOutput;
143 end;
144 if StandardOutputMerged <> '' then StandardOutput := StandardOutputMerged;
145 if IsWorkingCopyCommand(GetCommand(Parameters)) then ZeroPristine;
146end;
147
148constructor TSvnZero.Create;
149begin
150 Subversion := TSubversion.Create;
151end;
152
153destructor TSvnZero.Destroy;
154begin
155 FreeAndNil(Subversion);
156 inherited;
157end;
158
159function TSvnZero.GetWorkingCopyRootPath(FileName: string): string;
160begin
161 if (FWorkingCopyRootPathCurrentDir <> GetCurrentDir) or (FWorkingCopyRootPath = '') then begin
162 Subversion.Execute(['info', FileName]);
163 FWorkingCopyRootPath := GetWorkingCopyRootPathFromText(Subversion.StandardOutput);
164 FWorkingCopyRootPathCurrentDir := GetCurrentDir;
165 end;
166 Result := FWorkingCopyRootPath;
167end;
168
169function TSvnZero.CheckErrorOutput(Text: string): Boolean;
170var
171 FileName: string;
172 I: Integer;
173 ExportedFileName: string;
174 PristineFileName: string;
175 Info: TSubversionInfo;
176 Md5Hash: string;
177 Sha1Hash: string;
178const
179 StartText = 'expected:';
180 StartText2 = 'svn: E000002: Can''t open file ''';
181begin
182 Result := False;
183 I := Pos(StartText2, Text);
184 if I > 0 then begin
185 Sha1Hash := Copy(Text, I + Length(StartText2), MaxInt);
186 I := Pos('.svn-base', Sha1Hash);
187 if I > 0 then
188 Delete(Sha1Hash, I, MaxInt);
189 I := LastPos(DirectorySeparator, Sha1Hash);
190 if I > 0 then
191 Delete(Sha1Hash, 1, I);
192
193 Info := GetFileInfoBySha1(Sha1Hash);
194 ExportedFileName := GetSvnDir('.') + DirectorySeparator + 'tmp' +
195 DirectorySeparator + 'ExportedFile.bin';
196 PristineFileName := GetPristineDir('.') + DirectorySeparator + Copy(Info.Checksum, 1, 2) +
197 DirectorySeparator + Info.Checksum + '.svn-base';
198 Subversion.Execute(['export', '-r', Info.Revision, '--force', Info.URL, ExportedFileName]);
199 MakeFileWriteable(PristineFileName);
200 CopyFile(ExportedFileName, PristineFileName);
201 Subversion.Execute(['cleanup']);
202 Result := True;
203 end;
204
205(* if Pos(': Checksum mismatch', Text) > 0 then begin
206 I := Pos(StartText, Text);
207 if I > 0 then begin
208 Md5Hash := Copy(Text, I + Length(StartText), MaxInt);
209 I := Pos(#10, Md5Hash);
210 if I > 0 then
211 Delete(Md5Hash, I, MaxInt);
212 Md5Hash := Trim(Md5Hash);
213 Info := GetFileInfoByMd5(Md5Hash);
214 ExportedFileName := GetSvnDir('.') + DirectorySeparator + 'tmp' +
215 DirectorySeparator + 'ExportedFile.bin';
216 PristineFileName := GetPristineDir('.') + DirectorySeparator + Copy(Info.Checksum, 1, 2) +
217 DirectorySeparator + Info.Checksum + '.svn-base';
218 Subversion.Execute(['export', '-r', Info.Revision, '--force', Info.URL, ExportedFileName]);
219 MakeFileWriteable(PristineFileName);
220 CopyFile(ExportedFileName, PristineFileName);
221 Subversion.Execute(['cleanup']);
222 Result := True;
223 end;
224 { I := Pos('''', Text);
225 if I > 0 then begin
226 FileName := Copy(Text, I + 1, MaxInt);
227 I := Pos('''', FileName);
228 if I > 0 then
229 Delete(FileName, I, MaxInt);
230
231 Subversion.Execute(['info', FileName]);
232 Info := GetInfo(Subversion.StandardOutput);
233 ExportedFileName := GetSvnDir(FileName) + DirectorySeparator + 'tmp' +
234 DirectorySeparator + 'ExportedFile.bin';
235 PristineFileName := GetPristineDir(FileName) + DirectorySeparator + Copy(Info.Checksum, 1, 2) +
236 DirectorySeparator + Info.Checksum + '.svn-base';
237 Subversion.Execute(['export', '-r', Info.Revision, '--force', Info.URL, ExportedFileName]);
238 MakeFileWriteable(PristineFileName);
239 CopyFile(ExportedFileName, PristineFileName);
240 Subversion.Execute(['cleanup']);
241 Result := True;
242 end;
243 }
244 end;
245*)
246end;
247
248function TSvnZero.GetFileInfoByMd5(Md5Hash: string): TSubversionInfo;
249var
250 Database: TSQLite3Database;
251 Statement: TSQLite3Statement;
252begin
253 Database := TSQLite3Database.Create;
254 try
255 Database.Open(GetSvnDir('.') + DirectorySeparator + 'wc.db');
256 Statement := Database.Prepare('SELECT checksum FROM PRISTINE WHERE md5_checksum=''$md5 $' + Md5Hash + '''');
257 try
258 while Statement.Step = SQLITE_ROW do begin
259 Result.Checksum := Statement.ColumnText(0);
260 end;
261 finally
262 Statement.Free;
263 end;
264
265 Statement := Database.Prepare('SELECT repos_path,changed_revision FROM NODES WHERE checksum="' + Result.Checksum + '" LIMIT 1');
266 try
267 while Statement.Step = SQLITE_ROW do begin
268 Result.Path := Statement.ColumnText(0);
269 Result.Revision := Statement.ColumnText(1);
270 end;
271 finally
272 Statement.Free;
273 end;
274
275 Statement := Database.Prepare('SELECT root FROM REPOSITORY LIMIT 1');
276 try
277 while Statement.Step = SQLITE_ROW do begin
278 Result.URL := Statement.ColumnText(0) + '/' + Result.Path;
279 end;
280 finally
281 Statement.Free;
282 end;
283
284 if Result.Checksum.StartsWith('$sha1$') then
285 Result.Checksum := Copy(Result.Checksum, 7);
286 finally
287 Database.Free;
288 end;
289end;
290
291function TSvnZero.GetFileInfoBySha1(Sha1Hash: string): TSubversionInfo;
292var
293 Database: TSQLite3Database;
294 Statement: TSQLite3Statement;
295begin
296 Database := TSQLite3Database.Create;
297 try
298 Database.Open(GetSvnDir('.') + DirectorySeparator + 'wc.db');
299 Result.Checksum := Sha1Hash;
300
301 Statement := Database.Prepare('SELECT repos_path,changed_revision FROM NODES WHERE checksum="$sha1$' + Result.Checksum + '" LIMIT 1');
302 try
303 while Statement.Step = SQLITE_ROW do begin
304 Result.Path := Statement.ColumnText(0);
305 Result.Revision := Statement.ColumnText(1);
306 end;
307 finally
308 Statement.Free;
309 end;
310
311 Statement := Database.Prepare('SELECT root FROM REPOSITORY LIMIT 1');
312 try
313 while Statement.Step = SQLITE_ROW do begin
314 Result.URL := Statement.ColumnText(0) + '/' + Result.Path;
315 end;
316 finally
317 Statement.Free;
318 end;
319
320 if Result.Checksum.StartsWith('$sha1$') then
321 Result.Checksum := Copy(Result.Checksum, 7);
322 finally
323 Database.Free;
324 end;
325end;
326
327end.
328
Note: See TracBrowser for help on using the repository browser.