source: trunk/UFormMain.pas

Last change on this file was 2, checked in by chronos, 7 years ago
  • Modified: Much faster parsing of lshistory output using state machine.
File size: 8.9 KB
Line 
1unit UFormMain;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus,
9 ComCtrls, ExtCtrls, StdCtrls, UExternalTool, fgl, UXMLUtils, UJobProgressView,
10 dateutils, URegistry, Registry;
11
12type
13 THistoryItem = class
14 HumanName: string;
15 UserName: string;
16 Time: TDateTime;
17 Operation: string;
18 Location: string;
19 Comment: string;
20 ElementType: string;
21 Command: string;
22 LabelName: string;
23 end;
24
25 THistoryItems = class(TFPGObjectList<THistoryItem>)
26 end;
27
28 { TFormMain }
29
30 TFormMain = class(TForm)
31 ButtonBrowse: TButton;
32 ButtonLoadHistory: TButton;
33 ButtonBuild: TButton;
34 EditDir: TEdit;
35 JobProgressView1: TJobProgressView;
36 Label1: TLabel;
37 ListView1: TListView;
38 Panel1: TPanel;
39 procedure ButtonBrowseClick(Sender: TObject);
40 procedure ButtonBuildClick(Sender: TObject);
41 procedure ButtonLoadHistoryClick(Sender: TObject);
42 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
43 procedure FormCreate(Sender: TObject);
44 procedure FormDestroy(Sender: TObject);
45 procedure FormShow(Sender: TObject);
46 procedure ListView1Data(Sender: TObject; Item: TListItem);
47 private
48 procedure LoadConfig;
49 function ParseLine(var Line: string; Separator: string): string;
50 procedure JobBuild(Job: TJob);
51 procedure JobLoad(Job: TJob);
52 procedure Load;
53 procedure Build;
54 function EscapeString(Text: string): string;
55 procedure SaveConfig;
56 public
57 History: THistoryItems;
58 BaseDir: string;
59 procedure ReloadList;
60 end;
61
62var
63 FormMain: TFormMain;
64
65
66implementation
67
68const
69 DefaultRegKey = '\Software\Chronosoft\CC2SVN';
70
71{$R *.lfm}
72
73{ TFormMain }
74
75procedure TFormMain.FormShow(Sender: TObject);
76begin
77 LoadConfig;
78 ReloadList;
79end;
80
81procedure TFormMain.ButtonBrowseClick(Sender: TObject);
82var
83 OutDir: string;
84begin
85 if SelectDirectory('Select ClearCase directory', EditDir.Text, OutDir) then
86 EditDir.Text := OutDir;
87end;
88
89procedure TFormMain.ButtonBuildClick(Sender: TObject);
90begin
91 Build;
92end;
93
94procedure TFormMain.ButtonLoadHistoryClick(Sender: TObject);
95begin
96 Load;
97 ReloadList;
98end;
99
100procedure TFormMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
101begin
102 SaveConfig;
103end;
104
105procedure TFormMain.FormCreate(Sender: TObject);
106begin
107 History := THistoryItems.Create;
108end;
109
110procedure TFormMain.FormDestroy(Sender: TObject);
111begin
112 FreeAndNil(History);
113end;
114
115procedure TFormMain.ListView1Data(Sender: TObject; Item: TListItem);
116begin
117 if Item.Index < History.Count then
118 with THistoryItem(History[Item.Index]) do begin
119 Item.Caption := DateTimeToStr(Time);
120 Item.SubItems.Add(UserName);
121 Item.SubItems.Add(Operation);
122 Item.SubItems.Add(Location);
123 Item.SubItems.Add(ElementType);
124 Item.SubItems.Add(Command);
125 Item.SubItems.Add(Comment);
126 Item.SubItems.Add(LabelName);
127 end;
128end;
129
130procedure TFormMain.Load;
131begin
132 JobProgressView1.Clear;
133 JobProgressView1.AddJob('Load ClearCase history', JobLoad);
134 JobProgressView1.Start;
135end;
136
137procedure TFormMain.JobBuild(Job: TJob);
138var
139 I: Integer;
140 FileName: string;
141 SourceFileName: string;
142 Lines: TStringList;
143 PendingChanges: Boolean;
144 LastUserName: string;
145 LastComment: string;
146 LastTime: TDateTime;
147const
148 CommitCombineTimeTolerance = 5 * OneMinute;
149
150procedure CommitChanges(UserName, Comment: string; Time: TDateTime);
151begin
152 if UserName <> '' then begin
153 SVN(['add', '*', '-q', '--force'], GetCurrentDir + '\work');
154 SVN(['commit', '-m "' + EscapeString(Comment) + '"', '--username', UserName], GetCurrentDir + '\work');
155 SVN(['propset', 'svn:date', '--revprop', '-r', 'HEAD', DateTimeToXMLTime(Time, False)], GetCurrentDir + '\work');
156 end;
157 PendingChanges := False;
158end;
159
160begin
161 Job.Progress.Max := History.Count;
162 BaseDir := EditDir.Text;
163 ExecuteProcessOut(SVNAdminPath, ['create', 'repo']);
164
165 // Allow change of svn:date property
166 Lines := TStringList.Create;
167 Lines.Text := 'exit /b 0';
168 Lines.SaveToFile(GetCurrentDir + '\repo\hooks\pre-revprop-change.bat');
169 Lines.Free;
170
171 PendingChanges := False;
172 SVN(['checkout', 'file:///' + GetCurrentDir + '\repo', GetCurrentDir + '\work']);
173 for I := History.Count - 1 downto 0 do
174 with THistoryItem(History[I]) do begin
175 if Operation = 'create version' then begin
176 FileName := GetCurrentDir + '\work\trunk\' + Location;
177 if Pos('@@', FileName) > 0 then
178 FileName := Copy(FileName, 1, Pos('@@', FileName) - 1);
179 ForceDirectories(ExtractFileDir(FileName));
180 SourceFileName := BaseDir + DirectorySeparator + Location;
181 if FileExists(SourceFileName) and
182 (Length(SourceFileName) >= 2) and
183 not ((SourceFileName[Length(SourceFileName)] = '0') and
184 (SourceFileName[Length(SourceFileName) - 1] = '\')) then begin
185 // Merge multiple check-ins to single commit if
186 // comment is the same and
187 // username is the same
188 // time between commits is less then defined tolerance
189 if (LastComment <> Comment) or
190 (LastUserName <> UserName) or
191 (LastTime < (Time - CommitCombineTimeTolerance)) then
192 CommitChanges(LastUserName, LastComment, LastTime);
193
194 CopyFile(SourceFileName, FileName);
195 PendingChanges := True;
196
197 LastUserName := UserName;
198 LastComment := Comment;
199 LastTime := Time;
200 end;
201 end;
202 Job.Progress.Increment;
203 if Job.Terminate then Break;
204 end;
205 if PendingChanges then CommitChanges(LastUserName, LastComment, LastTime);
206end;
207
208procedure TFormMain.JobLoad(Job: TJob);
209type
210 TParseState = (psTime, psHumanName, psUserName, psOperation, psLocation,
211 psElementType, psCommand, psComment, psNewLine);
212var
213 Lines: TStringList;
214 HistoryItem: THistoryItem;
215 Content: string;
216 State: TParseState;
217 Text: string;
218 StartIndex: Integer;
219 I: Integer;
220begin
221 Lines := TStringList.Create;
222{$IF 0}
223 Lines.Text := ClearTool(['lshistory', '-recurse', '-minor', '-nco',
224 '-fmt "%d|%Fu|%u|%e|%n|%m|%o|%Nc|\n"'], EditDir.Text);
225{$ELSE}
226 Lines.LoadFromFile('log.txt');
227{$ENDIF}
228 Content := Lines.Text;
229 Job.Progress.Max := Length(Content);
230 StartIndex := 1;
231 State := psTime;
232 I := 1;
233 while I < Length(Content) do begin
234 if Content[I] = '|' then begin
235 Text := Copy(Content, StartIndex, I - StartIndex);
236 StartIndex := I + 1;
237 if State = psTime then begin
238 HistoryItem := THistoryItem.Create;
239 HistoryItem.Time := XMLTimeToDateTime(Text);
240 State := psHumanName;
241 end else
242 if State = psHumanName then begin
243 HistoryItem.HumanName := Text;
244 State := psUserName;
245 end else
246 if State = psUserName then begin
247 HistoryItem.UserName := Text;
248 State := psOperation;
249 end else
250 if State = psOperation then begin
251 HistoryItem.Operation := Text;
252 State := psLocation;
253 end else
254 if State = psLocation then begin
255 HistoryItem.Location := Text;
256 State := psElementType;
257 end else
258 if State = psElementType then begin
259 HistoryItem.ElementType := Text;
260 State := psCommand;
261 end else
262 if State = psCommand then begin
263 HistoryItem.Command := Text;
264 State := psComment;
265 end else
266 if State = psComment then begin
267 HistoryItem.Comment := Text;
268 History.Add(HistoryItem);
269 State := psNewLine;
270 end;
271 end else
272 if State = psNewLine then begin
273 if Content[I] = #10 then begin
274 State := psTime;
275 StartIndex := I + 1;
276 end;
277 end;
278 Inc(I);
279
280 Job.Progress.Value := I;
281 if Job.Terminate then Break;
282 end;
283 Lines.Free;
284end;
285
286procedure TFormMain.Build;
287begin
288 JobProgressView1.Clear;
289 JobProgressView1.AddJob('Build SVN versions', JobBuild);
290 JobProgressView1.Start;
291end;
292
293function TFormMain.EscapeString(Text: string): string;
294begin
295 Result := StringReplace(Text, '"', '\"', [rfReplaceAll]);
296end;
297
298procedure TFormMain.ReloadList;
299begin
300 ListView1.Items.Count := History.Count;
301 ListView1.Refresh;
302end;
303
304function TFormMain.ParseLine(var Line: string; Separator: string): string;
305begin
306 Result := Copy(Line, 1, Pos(Separator, Line) - 1);
307 Delete(Line, 1, Length(Result) + Length(Separator));
308end;
309
310procedure TFormMain.SaveConfig;
311begin
312 with TRegistryEx.Create do
313 try
314 RootKey := HKEY_CURRENT_USER;
315 OpenKey(DefaultRegKey, True);
316 WriteString('CCDir', EditDir.Text);
317 finally
318 Free;
319 end;
320end;
321
322procedure TFormMain.LoadConfig;
323begin
324 ClearToolPath := 'C:\Program Files\IBM\RationalSDLC\ClearCase\bin\cleartool.exe';
325 with TRegistryEx.Create do
326 try
327 RootKey := HKEY_CURRENT_USER;
328 OpenKey(DefaultRegKey, True);
329 EditDir.Text := ReadStringWithDefault('CCDir', EditDir.Text);
330 finally
331 Free;
332 end;
333end;
334
335end.
336
Note: See TracBrowser for help on using the repository browser.