pkgrepos.pp 21 KB

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