pkgrepos.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. unit pkgrepos;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. SysUtils,Classes,
  6. fprepos,pkgoptions;
  7. function GetRemoteRepositoryURL(const AFileName:string):string;
  8. procedure LoadLocalAvailableMirrors;
  9. procedure LoadLocalAvailableRepository;
  10. procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
  11. function LoadManifestFromFile(const AManifestFN:string):TFPPackage;
  12. procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boolean=true);
  13. function PackageIsBroken(APackage:TFPPackage):boolean;
  14. function FindBrokenPackages(SL:TStrings):Boolean;
  15. procedure CheckFPMakeDependencies;
  16. function PackageInstalledVersionStr(const AName:String;const ShowUsed: boolean = false;const Local: boolean = false):string;
  17. function PackageInstalledStateStr(const AName:String):string;
  18. function PackageAvailableVersionStr(const AName:String):string;
  19. procedure ListAvailablePackages;
  20. procedure ListPackages(const ShowGlobalAndLocal: boolean);
  21. procedure ListRemoteRepository;
  22. procedure RebuildRemoteRepository;
  23. procedure SaveRemoteRepository;
  24. var
  25. AvailableMirrors : TFPMirrors;
  26. AvailableRepository,
  27. InstalledRepository : TFPRepository;
  28. implementation
  29. uses
  30. zipper,
  31. fpxmlrep,
  32. pkgglobals,
  33. pkgmessages;
  34. {*****************************************************************************
  35. Mirror Selection
  36. *****************************************************************************}
  37. var
  38. CurrentRemoteRepositoryURL : String;
  39. procedure LoadLocalAvailableMirrors;
  40. var
  41. S : String;
  42. X : TFPXMLMirrorHandler;
  43. begin
  44. if assigned(AvailableMirrors) then
  45. AvailableMirrors.Free;
  46. AvailableMirrors:=TFPMirrors.Create(TFPMirror);
  47. // Repository
  48. S:=GlobalOptions.LocalMirrorsFile;
  49. Log(vlDebug,SLogLoadingMirrorsFile,[S]);
  50. if not FileExists(S) then
  51. exit;
  52. try
  53. X:=TFPXMLMirrorHandler.Create;
  54. With X do
  55. try
  56. LoadFromXml(AvailableMirrors,S);
  57. finally
  58. Free;
  59. end;
  60. except
  61. on E : Exception do
  62. begin
  63. Log(vlError,E.Message);
  64. Error(SErrCorruptMirrorsFile,[S]);
  65. end;
  66. end;
  67. end;
  68. function SelectRemoteMirror:string;
  69. var
  70. i,j : Integer;
  71. Bucket,
  72. BucketCnt : Integer;
  73. M : TFPMirror;
  74. begin
  75. Result:='';
  76. M:=nil;
  77. if assigned(AvailableMirrors) then
  78. begin
  79. // Create array for selection
  80. BucketCnt:=0;
  81. for i:=0 to AvailableMirrors.Count-1 do
  82. inc(BucketCnt,AvailableMirrors[i].Weight);
  83. // Select random entry
  84. Bucket:=Random(BucketCnt);
  85. M:=nil;
  86. for i:=0 to AvailableMirrors.Count-1 do
  87. begin
  88. for j:=0 to AvailableMirrors[i].Weight-1 do
  89. begin
  90. if Bucket=0 then
  91. begin
  92. M:=AvailableMirrors[i];
  93. break;
  94. end;
  95. Dec(Bucket);
  96. end;
  97. if assigned(M) then
  98. break;
  99. end;
  100. end;
  101. if assigned(M) then
  102. begin
  103. Log(vlInfo,SLogSelectedMirror,[M.Name]);
  104. Result:=M.URL;
  105. end
  106. else
  107. Error(SErrFailedToSelectMirror);
  108. end;
  109. function GetRemoteRepositoryURL(const AFileName:string):string;
  110. begin
  111. if CurrentRemoteRepositoryURL='' then
  112. begin
  113. if GlobalOptions.RemoteRepository='auto' then
  114. CurrentRemoteRepositoryURL:=SelectRemoteMirror
  115. else
  116. CurrentRemoteRepositoryURL:=GlobalOptions.RemoteRepository;
  117. end;
  118. Result:=CurrentRemoteRepositoryURL+AFileName;
  119. end;
  120. {*****************************************************************************
  121. Local Repository
  122. *****************************************************************************}
  123. procedure ReadIniFile(Const AFileName: String;L:TStrings);
  124. Var
  125. F : TFileStream;
  126. Line : String;
  127. I,P,PC : Integer;
  128. begin
  129. F:=TFileStream.Create(AFileName,fmOpenRead);
  130. Try
  131. L.LoadFromStream(F);
  132. // Fix lines.
  133. For I:=L.Count-1 downto 0 do
  134. begin
  135. Line:=L[I];
  136. P:=Pos('=',Line);
  137. PC:=Pos(';',Line); // Comment line.
  138. If (P=0) or ((PC<>0) and (PC<P)) then
  139. L.Delete(I)
  140. else
  141. L[i]:=Trim(System.Copy(Line,1,P-1)+'='+Trim(System.Copy(Line,P+1,Length(Line)-P)));
  142. end;
  143. Finally
  144. F.Free;
  145. end;
  146. end;
  147. function LoadManifestFromFile(const AManifestFN:string):TFPPackage;
  148. var
  149. X : TFPXMLRepositoryHandler;
  150. NewPackages : TFPPackages;
  151. NewP,P : TFPPackage;
  152. begin
  153. result:=nil;
  154. NewPackages:=TFPPackages.Create(TFPPackage);
  155. X:=TFPXMLRepositoryHandler.Create;
  156. try
  157. X.LoadFromXml(NewPackages,AManifestFN);
  158. // Update or Add packages to repository
  159. if NewPackages.Count=1 then
  160. begin
  161. NewP:=NewPackages[0];
  162. // Prevent duplicate names
  163. { P:=InstalledRepository.FindPackage(NewP.Name);
  164. if not assigned(P) then
  165. P:=InstalledRepository.AddPackage(NewP.Name); }
  166. result:=TFPPackage.Create(nil);
  167. // Copy contents
  168. result.Assign(NewP);
  169. end
  170. else
  171. Error(SErrManifestNoSinglePackage,[AManifestFN]);
  172. finally
  173. X.Free;
  174. NewPackages.Free;
  175. end;
  176. end;
  177. procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
  178. Var
  179. L,DepSL : TStrings;
  180. DepName,
  181. V : String;
  182. DepChecksum : Cardinal;
  183. i,j,k : integer;
  184. D : TFPDependency;
  185. begin
  186. L:=TStringList.Create;
  187. Try
  188. ReadIniFile(AFileName,L);
  189. {$warning TODO Maybe check also CPU-OS}
  190. // Read fpunits.conf
  191. V:=L.Values['version'];
  192. APackage.Version.AsString:=V;
  193. APackage.IsFPMakeAddIn:=Upcase(L.Values['FPMakeAddIn'])='Y';
  194. V:=L.Values['checksum'];
  195. if V<>'' then
  196. APackage.Checksum:=StrToInt(V)
  197. else
  198. APackage.Checksum:=$ffffffff;
  199. // Load dependencies
  200. V:=L.Values['depends'];
  201. DepSL:=TStringList.Create;
  202. DepSL.CommaText:=V;
  203. for i:=0 to DepSL.Count-1 do
  204. begin
  205. DepName:=DepSL[i];
  206. k:=Pos('|',DepName);
  207. if k>0 then
  208. begin
  209. DepChecksum:=StrToInt(Copy(DepName,k+1,Length(DepName)-k));
  210. DepName:=Copy(DepName,1,k-1);
  211. end
  212. else
  213. DepChecksum:=$ffffffff;
  214. D:=nil;
  215. for j:=0 to APackage.Dependencies.Count-1 do
  216. begin
  217. D:=APackage.Dependencies[j];
  218. if D.PackageName=DepName then
  219. break;
  220. D:=nil;
  221. end;
  222. if not assigned(D) then
  223. D:=APackage.AddDependency(DepName,'');
  224. D.RequireChecksum:=DepChecksum;
  225. end;
  226. DepSL.Free;
  227. Finally
  228. L.Free;
  229. end;
  230. end;
  231. procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boolean=true);
  232. function AddInstalledPackage(const AName,AFileName: String; const Local: boolean):TFPPackage;
  233. begin
  234. result:=InstalledRepository.FindPackage(AName);
  235. if not assigned(result) then
  236. result:=InstalledRepository.AddPackage(AName)
  237. else
  238. begin
  239. result.UnusedVersion:=result.Version;
  240. // Log packages found in multiple locations (local and global) ?
  241. if showdups then
  242. Log(vlDebug,SDbgPackageMultipleLocations,[result.Name,ExtractFilePath(AFileName)]);
  243. end;
  244. result.InstalledLocally:=Local;
  245. end;
  246. procedure LoadPackagefpcFromFile(APackage:TFPPackage;const AFileName: String);
  247. Var
  248. L : TStrings;
  249. V : String;
  250. begin
  251. L:=TStringList.Create;
  252. Try
  253. ReadIniFile(AFileName,L);
  254. V:=L.Values['version'];
  255. APackage.Version.AsString:=V;
  256. Finally
  257. L.Free;
  258. end;
  259. end;
  260. Procedure AddFPMakeAddIn(APackage: TFPPackage);
  261. begin
  262. Log(vlDebug,SLogFoundFPMakeAddin,[APackage.Name]);
  263. setlength(FPMKUnitDeps,length(FPMKUnitDeps)+1);
  264. FPMKUnitDeps[high(FPMKUnitDeps)].package:=APackage.Name;
  265. FPMKUnitDeps[high(FPMKUnitDeps)].reqver:=APackage.Version.AsString;
  266. FPMKUnitDeps[high(FPMKUnitDeps)].def:='HAS_PACKAGE_'+APackage.Name;
  267. end;
  268. function CheckUnitDir(const AUnitDir:string; const Local: boolean):boolean;
  269. var
  270. SR : TSearchRec;
  271. P : TFPPackage;
  272. UD,UF : String;
  273. begin
  274. Result:=false;
  275. if FindFirst(IncludeTrailingPathDelimiter(AUnitDir)+AllFiles,faDirectory,SR)=0 then
  276. begin
  277. Log(vlDebug,SLogFindInstalledPackages,[AUnitDir]);
  278. repeat
  279. if ((SR.Attr and faDirectory)=faDirectory) and (SR.Name<>'.') and (SR.Name<>'..') then
  280. begin
  281. UD:=IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(AUnitDir)+SR.Name);
  282. // Try new fpunits.conf
  283. UF:=UD+UnitConfigFileName;
  284. if FileExistsLog(UF) then
  285. begin
  286. P:=AddInstalledPackage(SR.Name,UF,Local);
  287. LoadUnitConfigFromFile(P,UF);
  288. if P.IsFPMakeAddIn then
  289. AddFPMakeAddIn(P);
  290. end
  291. else
  292. begin
  293. // Try Old style Package.fpc
  294. UF:=UD+'Package.fpc';
  295. if FileExistsLog(UF) then
  296. begin
  297. P:=AddInstalledPackage(SR.Name,UF,Local);
  298. LoadPackagefpcFromFile(P,UF);
  299. end;
  300. end;
  301. end;
  302. until FindNext(SR)<>0;
  303. end;
  304. end;
  305. begin
  306. if assigned(InstalledRepository) then
  307. InstalledRepository.Free;
  308. InstalledRepository:=TFPRepository.Create(nil);
  309. // First scan the global directory
  310. // The local directory will overwrite the versions
  311. if ACompilerOptions.GlobalUnitDir<>'' then
  312. CheckUnitDir(ACompilerOptions.GlobalUnitDir, False);
  313. if ACompilerOptions.LocalUnitDir<>'' then
  314. CheckUnitDir(ACompilerOptions.LocalUnitDir, True);
  315. end;
  316. function PackageIsBroken(APackage:TFPPackage):boolean;
  317. var
  318. j : integer;
  319. D : TFPDependency;
  320. DepPackage : TFPPackage;
  321. begin
  322. result:=false;
  323. for j:=0 to APackage.Dependencies.Count-1 do
  324. begin
  325. D:=APackage.Dependencies[j];
  326. if (CompilerOptions.CompilerOS in D.OSes) and
  327. (CompilerOptions.CompilerCPU in D.CPUs) then
  328. begin
  329. DepPackage:=InstalledRepository.FindPackage(D.PackageName);
  330. // Don't stop on missing dependencies
  331. if assigned(DepPackage) then
  332. begin
  333. if (DepPackage.Checksum<>D.RequireChecksum) then
  334. begin
  335. Log(vlInfo,SLogPackageChecksumChanged,[APackage.Name,D.PackageName]);
  336. result:=true;
  337. exit;
  338. end;
  339. end
  340. else
  341. Log(vlDebug,SDbgObsoleteDependency,[D.PackageName]);
  342. end;
  343. end;
  344. end;
  345. function FindBrokenPackages(SL:TStrings):Boolean;
  346. var
  347. i : integer;
  348. P : TFPPackage;
  349. begin
  350. SL.Clear;
  351. for i:=0 to InstalledRepository.PackageCount-1 do
  352. begin
  353. P:=InstalledRepository.Packages[i];
  354. if PackageIsBroken(P) then
  355. SL.Add(P.Name);
  356. end;
  357. Result:=(SL.Count>0);
  358. end;
  359. procedure CheckFPMakeDependencies;
  360. var
  361. i : Integer;
  362. P,AvailP : TFPPackage;
  363. AvailVerStr : string;
  364. ReqVer : TFPVersion;
  365. begin
  366. // Reset availability
  367. for i:=0 to high(FPMKUnitDeps) do
  368. FPMKUnitDeps[i].available:=false;
  369. // Not version check needed in Recovery mode, we always need to use
  370. // the internal bootstrap procedure
  371. if GlobalOptions.RecoveryMode then
  372. exit;
  373. // Check for fpmkunit dependencies
  374. for i:=0 to high(FPMKUnitDeps) do
  375. begin
  376. P:=InstalledRepository.FindPackage(FPMKUnitDeps[i].package);
  377. if P<>nil then
  378. begin
  379. AvailP:=AvailableRepository.FindPackage(FPMKUnitDeps[i].package);
  380. if AvailP<>nil then
  381. AvailVerStr:=AvailP.Version.AsString
  382. else
  383. AvailVerStr:='<not available>';
  384. ReqVer:=TFPVersion.Create;
  385. ReqVer.AsString:=FPMKUnitDeps[i].ReqVer;
  386. Log(vlDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.Version.AsString,AvailVerStr]);
  387. if ReqVer.CompareVersion(P.Version)<=0 then
  388. FPMKUnitDeps[i].available:=true
  389. else
  390. Log(vlDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
  391. end
  392. else
  393. Log(vlDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
  394. end;
  395. end;
  396. {*****************************************************************************
  397. Local Available Repository
  398. *****************************************************************************}
  399. procedure LoadLocalAvailableRepository;
  400. var
  401. S : String;
  402. X : TFPXMLRepositoryHandler;
  403. begin
  404. if assigned(AvailableRepository) then
  405. AvailableRepository.Free;
  406. AvailableRepository:=TFPRepository.Create(Nil);
  407. // Repository
  408. S:=GlobalOptions.LocalPackagesFile;
  409. Log(vlDebug,SLogLoadingPackagesFile,[S]);
  410. if not FileExists(S) then
  411. exit;
  412. try
  413. X:=TFPXMLRepositoryHandler.Create;
  414. With X do
  415. try
  416. LoadFromXml(AvailableRepository,S);
  417. finally
  418. Free;
  419. end;
  420. except
  421. on E : Exception do
  422. begin
  423. Log(vlError,E.Message);
  424. Error(SErrCorruptPackagesFile,[S]);
  425. end;
  426. end;
  427. end;
  428. function PackageAvailableVersionStr(const AName:String):string;
  429. var
  430. P : TFPPackage;
  431. begin
  432. P:=AvailableRepository.FindPackage(AName);
  433. if P<>nil then
  434. result:=P.Version.AsString
  435. else
  436. result:='-';
  437. end;
  438. function PackageInstalledVersionStr(const AName:String;const ShowUsed: boolean = false;const Local: boolean = false):string;
  439. var
  440. P : TFPPackage;
  441. begin
  442. P:=InstalledRepository.FindPackage(AName);
  443. if P<>nil then
  444. begin
  445. if not ShowUsed then
  446. result:=P.Version.AsString
  447. else if Local=p.InstalledLocally then
  448. result:=P.Version.AsString
  449. else if not P.UnusedVersion.Empty then
  450. result:=P.UnusedVersion.AsString
  451. else
  452. result:='-';
  453. end
  454. else
  455. result:='-';
  456. end;
  457. function PackageInstalledStateStr(const AName:String):string;
  458. var
  459. P : TFPPackage;
  460. begin
  461. result := '';
  462. P:=InstalledRepository.FindPackage(AName);
  463. if (P<>nil) and PackageIsBroken(P) then
  464. result:='B';
  465. end;
  466. procedure ListAvailablePackages;
  467. var
  468. InstalledP,
  469. AvailP : TFPPackage;
  470. i : integer;
  471. SL : TStringList;
  472. begin
  473. SL:=TStringList.Create;
  474. SL.Sorted:=true;
  475. for i:=0 to AvailableRepository.PackageCount-1 do
  476. begin
  477. AvailP:=AvailableRepository.Packages[i];
  478. InstalledP:=InstalledRepository.FindPackage(AvailP.Name);
  479. if not assigned(InstalledP) or
  480. (AvailP.Version.CompareVersion(InstalledP.Version)>0) then
  481. SL.Add(Format('%-20s %-12s %-12s',[AvailP.Name,PackageInstalledVersionStr(AvailP.Name),AvailP.Version.AsString]));
  482. end;
  483. Writeln(Format('%-20s %-12s %-12s',['Name','Installed','Available']));
  484. for i:=0 to SL.Count-1 do
  485. Writeln(SL[i]);
  486. FreeAndNil(SL);
  487. end;
  488. procedure ListPackages(const ShowGlobalAndLocal: boolean);
  489. var
  490. i : integer;
  491. SL : TStringList;
  492. PackageName : String;
  493. begin
  494. SL:=TStringList.Create;
  495. SL.Sorted:=true;
  496. SL.Duplicates:=dupIgnore;
  497. for i:=0 to AvailableRepository.PackageCount-1 do
  498. SL.Add(AvailableRepository.Packages[i].Name);
  499. for i:=0 to InstalledRepository.PackageCount-1 do
  500. SL.Add(InstalledRepository.Packages[i].Name);
  501. if ShowGlobalAndLocal then
  502. Writeln(Format('%-20s %-14s %-14s %-3s %-12s',['Name','Installed (G)','Installed (L)','','Available']))
  503. else
  504. Writeln(Format('%-20s %-12s %-3s %-12s',['Name','Installed','','Available']));
  505. for i:=0 to SL.Count-1 do
  506. begin
  507. PackageName:=SL[i];
  508. if (PackageName<>CmdLinePackageName) and (PackageName<>CurrentDirPackageName) then
  509. begin
  510. if ShowGlobalAndLocal then
  511. Writeln(Format('%-20s %-14s %-14s %-3s %-12s',[PackageName,PackageInstalledVersionStr(PackageName,True,False),PackageInstalledVersionStr(PackageName,True,True),PackageInstalledStateStr(PackageName),PackageAvailableVersionStr(PackageName)]))
  512. else
  513. Writeln(Format('%-20s %-12s %-3s %-12s',[PackageName,PackageInstalledVersionStr(PackageName),PackageInstalledStateStr(PackageName),PackageAvailableVersionStr(PackageName)]));
  514. end;
  515. end;
  516. FreeAndNil(SL);
  517. end;
  518. {*****************************************************************************
  519. Remote Repository
  520. *****************************************************************************}
  521. procedure ListRemoteRepository;
  522. var
  523. P : TFPPackage;
  524. i : integer;
  525. SL : TStringList;
  526. begin
  527. SL:=TStringList.Create;
  528. SL.Sorted:=true;
  529. for i:=0 to InstalledRepository.PackageCount-1 do
  530. begin
  531. P:=InstalledRepository.Packages[i];
  532. SL.Add(Format('%-20s %-12s %-20s',[P.Name,P.Version.AsString,P.FileName]));
  533. end;
  534. Writeln(Format('%-20s %-12s %-20s',['Name','Available','FileName']));
  535. for i:=0 to SL.Count-1 do
  536. Writeln(SL[i]);
  537. FreeAndNil(SL);
  538. end;
  539. procedure RebuildRemoteRepository;
  540. procedure LoadPackageManifest(const AManifestFN:string);
  541. var
  542. X : TFPXMLRepositoryHandler;
  543. i : integer;
  544. DoAdd : Boolean;
  545. P,NewP : TFPPackage;
  546. NewPackages : TFPPackages;
  547. begin
  548. NewPackages:=TFPPackages.Create(TFPPackage);
  549. X:=TFPXMLRepositoryHandler.Create;
  550. try
  551. X.LoadFromXml(NewPackages,AManifestFN);
  552. // Update or Add packages to repository
  553. for i:=0 to NewPackages.Count-1 do
  554. begin
  555. NewP:=NewPackages[i];
  556. DoAdd:=True;
  557. P:=InstalledRepository.FindPackage(NewP.Name);
  558. if assigned(P) then
  559. begin
  560. if NewP.Version.CompareVersion(P.Version)<0 then
  561. begin
  562. Writeln(Format('Ignoring package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,P.Version.AsString]));
  563. DoAdd:=False;
  564. end
  565. else
  566. Writeln(Format('Updating package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,P.Version.AsString]));
  567. end
  568. else
  569. P:=InstalledRepository.PackageCollection.AddPackage(NewP.Name);
  570. // Copy contents
  571. if DoAdd then
  572. P.Assign(NewP);
  573. end;
  574. finally
  575. X.Free;
  576. NewPackages.Free;
  577. end;
  578. end;
  579. var
  580. i : integer;
  581. ArchiveSL : TStringList;
  582. ManifestSL : TStringList;
  583. begin
  584. if assigned(InstalledRepository) then
  585. InstalledRepository.Free;
  586. InstalledRepository:=TFPRepository.Create(Nil);
  587. try
  588. ManifestSL:=TStringList.Create;
  589. ManifestSL.Add(ManifestFileName);
  590. { Find all archives }
  591. ArchiveSL:=TStringList.Create;
  592. SearchFiles(ArchiveSL,'*.zip');
  593. if ArchiveSL.Count=0 then
  594. Error('No archive files found');
  595. { Process all archives }
  596. for i:=0 to ArchiveSL.Count-1 do
  597. begin
  598. Writeln('Processing ',ArchiveSL[i]);
  599. { Unzip manifest.xml }
  600. With TUnZipper.Create do
  601. try
  602. Log(vlCommands,SLogUnzippping,[ArchiveSL[i]]);
  603. OutputPath:='.';
  604. UnZipFiles(ArchiveSL[i],ManifestSL);
  605. Finally
  606. Free;
  607. end;
  608. { Load manifest.xml }
  609. if FileExists(ManifestFileName) then
  610. begin
  611. LoadPackageManifest(ManifestFileName);
  612. DeleteFile(ManifestFileName);
  613. end
  614. else
  615. Writeln('No manifest found in archive ',ArchiveSL[i]);
  616. end;
  617. finally
  618. ArchiveSL.Free;
  619. ManifestSL.Free;
  620. end;
  621. end;
  622. procedure SaveRemoteRepository;
  623. var
  624. X : TFPXMLRepositoryHandler;
  625. begin
  626. // Repository
  627. Writeln('Saving repository in packages.xml');
  628. X:=TFPXMLRepositoryHandler.Create;
  629. With X do
  630. try
  631. SaveToXml(InstalledRepository,'packages.xml');
  632. finally
  633. Free;
  634. end;
  635. end;
  636. end.