1 {
2 ***************************************************************************
3 * *
4 * This source is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This code is distributed in the hope that it will be useful, but *
10 * WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * General Public License for more details. *
13 * *
14 * A copy of the GNU General Public License is available on the World *
15 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
16 * obtain it by writing to the Free Software Foundation, *
17 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
18 * *
19 ***************************************************************************
20
21 Author: Balázs Székely
22 Abstract:
23 Common functions, procedures.
24 }
25 unit opkman_common;
26
27 {$mode objfpc}{$H+}
28
29 interface
30
31 uses
32 Classes, SysUtils, contnrs,
33 // LCL
34 Dialogs, Forms, Controls,
35 // LazUtils
36 LazFileUtils,
37 // IdeIntf
38 LazIDEIntf, PackageIntf,
39 // OpkMan
40 opkman_const, opkman_options;
41
42 type
43 TPackageAction = (paDownloadTo, paInstall, paUpdate);
44
45 TPackageData = class(TObject)
46 FName: String;
47 FPackageBaseDir: String;
48 FPackageRelativePath: String;
49 FFullPath: String;
50 end;
51
52 const
53 MaxCategories = 28;
54 Categories: array[0..MaxCategories - 1] of String = (
55 rsMainFrm_VSTText_PackageCategory0,
56 rsMainFrm_VSTText_PackageCategory1,
57 rsMainFrm_VSTText_PackageCategory2,
58 rsMainFrm_VSTText_PackageCategory3,
59 rsMainFrm_VSTText_PackageCategory4,
60 rsMainFrm_VSTText_PackageCategory5,
61 rsMainFrm_VSTText_PackageCategory6,
62 rsMainFrm_VSTText_PackageCategory7,
63 rsMainFrm_VSTText_PackageCategory8,
64 rsMainFrm_VSTText_PackageCategory9,
65 rsMainFrm_VSTText_PackageCategory10,
66 rsMainFrm_VSTText_PackageCategory11,
67 rsMainFrm_VSTText_PackageCategory12,
68 rsMainFrm_VSTText_PackageCategory13,
69 rsMainFrm_VSTText_PackageCategory14,
70 rsMainFrm_VSTText_PackageCategory15,
71 rsMainFrm_VSTText_PackageCategory16,
72 rsMainFrm_VSTText_PackageCategory17,
73 rsMainFrm_VSTText_PackageCategory18,
74 rsMainFrm_VSTText_PackageCategory19,
75 rsMainFrm_VSTText_PackageCategory20,
76 rsMainFrm_VSTText_PackageCategory21,
77 rsMainFrm_VSTText_PackageCategory22,
78 rsMainFrm_VSTText_PackageCategory23,
79 rsMainFrm_VSTText_PackageCategory24,
80 rsMainFrm_VSTText_PackageCategory25,
81 rsMainFrm_VSTText_PackageCategory26,
82 rsMainFrm_VSTText_PackageCategory27);
83 //needed for localized filter, since the JSON contains only english text
84 CategoriesEng: array[0..MaxCategories - 1] of String = (
85 'Charts and Graphs',
86 'Cryptography',
87 'DataControls',
88 'Date and Time',
89 'Dialogs',
90 'Edit and Memos',
91 'Files and Drives',
92 'GUIContainers',
93 'Graphics',
94 'Grids',
95 'Indicators and Gauges',
96 'Labels',
97 'LazIDEPlugins',
98 'List and Combo Boxes',
99 'ListViews and TreeViews',
100 'Menus',
101 'Multimedia',
102 'Networking',
103 'Panels',
104 'Reporting',
105 'Science',
106 'Security',
107 'Shapes',
108 'Sizers and Scrollers',
109 'System',
110 'Tabbed Components',
111 'Other',
112 'Games and Game Engines');
113
114 var
115 LocalRepositoryConfigFile: String;
116 LocalRepositoryUpdatesFile: String;
117 PackageAction: TPackageAction;
118 InstallPackageList: TObjectList;
119
MessageDlgExnull120 function MessageDlgEx(const AMsg: String; ADlgType: TMsgDlgType; AButtons:
121 TMsgDlgButtons; AParent: TForm): TModalResult;
122 procedure InitLocalRepository;
SecToHourAndMinnull123 function SecToHourAndMin(const ASec: LongInt): String;
FormatSizenull124 function FormatSize(Size: Int64): String;
FormatSpeednull125 function FormatSpeed(Speed: LongInt): String;
GetPackageTypeStringnull126 function GetPackageTypeString(aPackageType: TLazPackageType): String;
GetDirSizenull127 function GetDirSize(const ADirName: String; var AFileCnt, ADirCnt: Integer): Int64;
128 procedure FindPackages(const ADirName: String; APackageList: TStrings);
129 procedure FindAllFilesEx(const ADirName: String; AFileList: TStrings);
FixProtocolnull130 function FixProtocol(const AURL: String): String;
IsDirectoryEmptynull131 function IsDirectoryEmpty(const ADirectory: String): Boolean;
132
133 implementation
134
MessageDlgExnull135 function MessageDlgEx(const AMsg: string; ADlgType: TMsgDlgType;
136 AButtons: TMsgDlgButtons; AParent: TForm): TModalResult;
137 var
138 MsgFrm: TForm;
139 begin
140 MsgFrm := CreateMessageDialog(AMsg, ADlgType, AButtons);
141 try
142 MsgFrm.FormStyle := fsSystemStayOnTop;
143 if AParent <> nil then
144 begin
145 MsgFrm.Position := poDefaultSizeOnly;
146 MsgFrm.Left := AParent.Left + (AParent.Width - MsgFrm.Width) div 2;
147 MsgFrm.Top := AParent.Top + (AParent.Height - MsgFrm.Height) div 2;
148 end
149 else
150 MsgFrm.Position := poWorkAreaCenter;
151 Result := MsgFrm.ShowModal;
152 finally
153 MsgFrm.Free
154 end;
155 end;
156
157 procedure InitLocalRepository;
158 var
159 LocalRepo, LocalRepoConfig: String;
160 begin
161 LocalRepo := AppendPathDelim(AppendPathDelim(LazarusIDE.GetPrimaryConfigPath) + cLocalRepository);
162 if not DirectoryExists(LocalRepo) then
163 CreateDir(LocalRepo);
164
165 LocalRepoConfig := AppendPathDelim(LocalRepo + cLocalRepositoryConfig);
166 if not DirectoryExists(LocalRepoConfig) then
167 CreateDir(LocalRepoConfig);
168 LocalRepositoryConfigFile := LocalRepoConfig + cLocalRepositoryConfigFile;
169 LocalRepositoryUpdatesFile := LocalRepoConfig + cLocalRepositoryUpdatesFile;
170 end;
171
SecToHourAndMinnull172 function SecToHourAndMin(const ASec: LongInt): String;
173 var
174 Hour, Min, Sec: LongInt;
175 begin
176 Hour := Trunc(ASec/3600);
177 Min := Trunc((ASec - Hour*3600)/60);
178 Sec := ASec - Hour*3600 - 60*Min;
179 Result := IntToStr(Hour) + 'h: ' + IntToStr(Min) + 'm: ' + IntToStr(Sec) + 's';
180 end;
181
FormatSizenull182 function FormatSize(Size: Int64): String;
183 const
184 KB = 1024;
185 MB = 1024 * KB;
186 GB = 1024 * MB;
187 begin
188 if Size < KB then
189 Result := FormatFloat('#,##0 Bytes', Size)
190 else if Size < MB then
191 Result := FormatFloat('#,##0.0 KB', Size / KB)
192 else if Size < GB then
193 Result := FormatFloat('#,##0.0 MB', Size / MB)
194 else
195 Result := FormatFloat('#,##0.0 GB', Size / GB);
196 end;
197
FormatSpeednull198 function FormatSpeed(Speed: LongInt): String;
199 const
200 KB = 1024;
201 MB = 1024 * KB;
202 GB = 1024 * MB;
203 begin
204 if Speed < KB then
205 Result := FormatFloat('#,##0 bits/s', Speed)
206 else if Speed < MB then
207 Result := FormatFloat('#,##0.0 kB/s', Speed / KB)
208 else if Speed < GB then
209 Result := FormatFloat('#,##0.0 MB/s', Speed / MB)
210 else
211 Result := FormatFloat('#,##0.0 GB/s', Speed / GB);
212 end;
213
GetPackageTypeStringnull214 function GetPackageTypeString(aPackageType: TLazPackageType): String;
215 begin
216 case aPackageType of
217 lptRunAndDesignTime: Result := rsMainFrm_VSTText_PackageType0;
218 lptDesignTime: Result := rsMainFrm_VSTText_PackageType1;
219 lptRunTime: Result := rsMainFrm_VSTText_PackageType2;
220 lptRunTimeOnly: Result := rsMainFrm_VSTText_PackageType3;
221 end;
222 end;
223
GetDirSizenull224 function GetDirSize(const ADirName: String; var AFileCnt, ADirCnt: Integer): Int64;
225 var
226 DirSize: Int64;
227
228 procedure GetSize(const ADirName: String);
229 var
230 SR: TSearchRec;
231 DirName: String;
232 begin
233 DirName := AppendPathDelim(ADirName);
234 if FindFirst(DirName + '*', faAnyFile - faDirectory, SR) = 0 then
235 begin
236 try
237 repeat
238 Inc(AFileCnt);
239 DirSize:= DirSize + SR.Size;
240 until FindNext(SR) <> 0;
241 finally
242 FindClose(SR);
243 end;
244 end;
245 if FindFirst(DirName + '*', faAnyFile, SR) = 0 then
246 begin
247 try
248 repeat
249 if ((SR.Attr and faDirectory) <> 0) and (SR.Name <> '.') and (SR.Name <> '..') then
250 begin
251 Inc(ADirCnt);
252 GetSize(DirName + SR.Name);
253 end;
254 until FindNext(SR) <> 0;
255 finally
256 FindClose(SR);
257 end;
258 end;
259 end;
260 begin
261 DirSize := 0;
262 AFileCnt := 0;
263 ADirCnt := 0;
264 GetSize(ADirName);
265 Result := DirSize;
266 end;
267
268 procedure FindPackages(const ADirName: String; APackageList: TStrings);
269 var
270 BaseDir, BasePath: String;
271 SLExcludedFolders: TStringList;
272
IsAllowednull273 function IsAllowed(AName: String): Boolean;
274 var
275 I: Integer;
276 begin
277 Result := True;
278 for I := 0 to SLExcludedFolders.Count - 1 do
279 begin
280 if UpperCase(SLExcludedFolders.Strings[I]) = UpperCase(AName) then
281 begin
282 Result := False;
283 Break;
284 end;
285 end;
286 end;
287
288 procedure FindFiles(const ADirName: String);
289 var
290 SR: TSearchRec;
291 Path: String;
292 PackageData: TPackageData;
293 begin
294 Path := AppendPathDelim(ADirName);
295 if FindFirst(Path + '*', faAnyFile - faDirectory, SR) = 0 then
296 begin
297 try
298 repeat
299 if (UpperCase(ExtractFileExt(SR.Name)) = UpperCase('.lpk')) then
300 begin
301 PackageData := TPackageData.Create;
302 PackageData.FName := SR.Name;
303 PackageData.FPackageBaseDir := BaseDir;
304 PackageData.FPackageRelativePath := StringReplace(Path, BasePath, '', [rfIgnoreCase, rfReplaceAll]);
305 if Trim(PackageData.FPackageRelativePath) <> '' then
306 begin
307 if PackageData.FPackageRelativePath[Length(PackageData.FPackageRelativePath)] = PathDelim then
308 PackageData.FPackageRelativePath := Copy(PackageData.FPackageRelativePath, 1, Length(PackageData.FPackageRelativePath) - 1);
309 PackageData.FPackageRelativePath := PackageData.FPackageRelativePath;
310 end;
311 PackageData.FFullPath := Path + SR.Name;
312 APackageList.AddObject(PackageData.FName, PackageData);
313 end;
314 until FindNext(SR) <> 0;
315 finally
316 FindClose(SR);
317 end;
318 end;
319
320 if FindFirst(Path + '*', faAnyFile, SR) = 0 then
321 begin
322 try
323 repeat
324 if ((SR.Attr and faDirectory) <> 0) and (SR.Name <> '.') and (SR.Name <> '..') then
325 if IsAllowed(SR.Name) then
326 FindFiles(Path + SR.Name);
327 until FindNext(SR) <> 0;
328 finally
329 FindClose(SR);
330 end;
331 end;
332 end;
333
334 begin
335 BasePath := AppendPathDelim(ADirName);
336 if ADirName[Length(ADirName)] = PathDelim then
337 BaseDir := ExtractFileName(Copy(ADirName, 1, Length(ADirName) - 1))
338 else
339 BaseDir := ExtractFileName(ADirName);
340
341 SLExcludedFolders := TStringList.Create;
342 try
343 SLExcludedFolders.Delimiter := ',';
344 SLExcludedFolders.StrictDelimiter := True;
345 SLExcludedFolders.DelimitedText := Options.ExcludedFolders;
346 FindFiles(ADirName);
347 finally
348 SLExcludedFolders.Free;
349 end;
350 end;
351
352 procedure FindAllFilesEx(const ADirName: String; AFileList: TStrings);
353 var
354 SLExcludedFiles: TStringList;
355 SLExcludedFolders: TStringList;
356
IsAllowednull357 function IsAllowed(const AName: String; const AIsDir: Boolean): Boolean;
358 var
359 I: Integer;
360 begin
361 Result := True;
362 if not AIsDir then
363 begin
364 for I := 0 to SLExcludedFiles.Count - 1 do
365 begin
366 if UpperCase(SLExcludedFiles.Strings[I]) = UpperCase(ExtractFileExt(AName)) then
367 begin
368 Result := False;
369 Break;
370 end;
371 end;
372 end
373 else
374 begin
375 for I := 0 to SLExcludedFolders.Count - 1 do
376 if UpperCase(SLExcludedFolders.Strings[I]) = UpperCase(AName) then
377 begin
378 Result := False;
379 Break;
380 end;
381 end;
382 end;
383
384 procedure FindFiles(const ADirName: String);
385 var
386 SR: TSearchRec;
387 Path: String;
388 begin
389 Path := AppendPathDelim(ADirName);
390 if FindFirst(Path + '*', faAnyFile - faDirectory, SR) = 0 then
391 begin
392 try
393 repeat
394 if IsAllowed(SR.Name, False) then
395 AFileList.Add(Path + SR.Name);
396 until FindNext(SR) <> 0;
397 finally
398 FindClose(SR);
399 end;
400 end;
401
402 if FindFirst(Path + '*', faAnyFile, SR) = 0 then
403 begin
404 try
405 repeat
406 if ((SR.Attr and faDirectory) <> 0) and (SR.Name <> '.') and (SR.Name <> '..') then
407 if IsAllowed(SR.Name, True) then
408 FindFiles(Path + SR.Name);
409 until FindNext(SR) <> 0;
410 finally
411 FindClose(SR);
412 end;
413 end;
414 end;
415
416 var
417 I, P: Integer;
418 Ext: String;
419 begin
420 SLExcludedFiles := TStringList.Create;
421 try
422 SLExcludedFiles.Delimiter := ',';
423 SLExcludedFiles.StrictDelimiter := True;
424 SLExcludedFiles.DelimitedText := Options.ExcludedFiles;
425 for I := 0 to SLExcludedFiles.Count - 1 do
426 begin
427 P := Pos('*.', SLExcludedFiles.Strings[I]);
428 if P > 0 then
429 begin
430 Ext := Copy(SLExcludedFiles.Strings[I], 2, Length(SLExcludedFiles.Strings[I]));
431 if Trim(Ext) = '.' then
432 Ext := '';
433 end
434 else
435 Ext := '.' + SLExcludedFiles.Strings[I];
436 SLExcludedFiles.Strings[I] := Ext;
437 end;
438 SLExcludedFolders := TStringList.Create;
439 try
440 SLExcludedFolders.Delimiter := ',';
441 SLExcludedFolders.StrictDelimiter := True;
442 SLExcludedFolders.DelimitedText := Options.ExcludedFolders;
443 FindFiles(ADirName);
444 finally
445 SLExcludedFolders.Free;
446 end;
447 finally
448 SLExcludedFiles.Free;
449 end;
450 end;
451
FixProtocolnull452 function FixProtocol(const AURL: String): String;
453 begin
454 Result := AURL;
455 if (Pos('http://', Result) = 0) and (Pos('https://', Result) = 0) then
456 Result := 'https://' + Result;
457 end;
458
IsDirectoryEmptynull459 function IsDirectoryEmpty(const ADirectory: String): Boolean;
460 var
461 SearchRec: TSearchRec;
462 SearchRes: Longint;
463 begin
464 Result := true;
465 SearchRes := FindFirst(IncludeTrailingPathDelimiter(ADirectory) + AllFilesMask, faAnyFile, SearchRec);
466 try
467 while SearchRes = 0 do
468 begin
469 if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
470 begin
471 Result := False;
472 Break;
473 end;
474 SearchRes := FindNext(SearchRec);
475 end;
476 finally
477 SysUtils.FindClose(SearchRec);
478 end;
479 end;
480
481 end.
482
483