pkgfppkg.pp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. {
  2. This file is part of the fppkg package manager
  3. Copyright (c) 1999-2022 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$IFNDEF FPC_DOTTEDUNITS}
  11. unit pkgFppkg;
  12. {$ENDIF FPC_DOTTEDUNITS}
  13. {$mode objfpc}{$H+}
  14. interface
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses
  17. System.Classes,
  18. System.SysUtils,
  19. System.Contnrs,
  20. FpPkg.Repos,
  21. FpPkg.Messages,
  22. FpPkg.Globals,
  23. FpPkg.Options,
  24. FpPkg.Packages.structure;
  25. {$ELSE FPC_DOTTEDUNITS}
  26. uses
  27. Classes,
  28. SysUtils,
  29. contnrs,
  30. fprepos,
  31. pkgmessages,
  32. pkgglobals,
  33. pkgoptions,
  34. pkgPackagesStructure;
  35. {$ENDIF FPC_DOTTEDUNITS}
  36. type
  37. { TpkgFPpkg }
  38. TpkgPackageKind = (pkgpkInstalled, pkgpkAvailable, pkgpkBoth);
  39. TpkgFPpkg = class(TComponent)
  40. private
  41. FInsideFindBrokenPackages: Integer;
  42. FBrokenPackagesDictionary: TFPHashList;
  43. FFPMakeRepositoryList: TComponentList;
  44. FRepositoryList: TComponentList;
  45. FOptions: TFppkgOptions;
  46. FCompilerOptions: TCompilerOptions;
  47. FFpmakeCompilerOptions: TCompilerOptions;
  48. FCurrentRemoteRepositoryURL: String;
  49. FConfigurationFilename: string;
  50. function IncludeRepositoryTypeForPackageKind(ARepositoryType: TFPRepositoryType;
  51. APackageKind: TpkgPackageKind): Boolean;
  52. procedure ScanPackagesOnDisk(ACompilerOptions: TCompilerOptions; APackageKind: TpkgPackageKind; ARepositoryList: TComponentList);
  53. function CreateRepository(ARepoOptionSection: TFppkgRepositoryOptionSection;
  54. AnOptions: TFppkgOptions; ACompilerOptions: TCompilerOptions): TFPRepository;
  55. function FindPackage(ARepositoryList: TComponentList; APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  56. function SelectRemoteMirror:string;
  57. procedure EnterFindBrokenPackages;
  58. procedure LeaveFindBrokenpackages;
  59. procedure ClearRepositories(ARepositoryList: TComponentList);
  60. function GetConfigurationFilename: string;
  61. public
  62. constructor Create(AOwner: TComponent); override;
  63. destructor Destroy; override;
  64. procedure InitializeGlobalOptions(CfgFile: string);
  65. procedure InitializeCompilerOptions;
  66. procedure LoadLocalAvailableMirrors;
  67. procedure ScanAvailablePackages;
  68. procedure ScanPackages;
  69. function PackageIsBroken(APackage: TFPPackage; out Reason: string; ARepository: TFPRepository): Boolean;
  70. function FPMakeRepoFindPackage(APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  71. function FindPackage(APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  72. function PackageByName(APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  73. function FindRepository(ARepositoryName: string): TFPRepository;
  74. function RepositoryByName(ARepositoryName: string): TFPRepository;
  75. function GetInstallRepository(ASourcePackage: TFPPackage): TFPRepository;
  76. function DetermineSourcePackage(APackageName: String): TFPPackage;
  77. function PackageLocalArchive(APackage:TFPPackage): String;
  78. function PackageBuildPath(APackage:TFPPackage):String;
  79. function GetRemoteRepositoryURL(const AFileName:string):string;
  80. function PackageRemoteArchive(APackage:TFPPackage): String;
  81. procedure ScanInstalledPackagesForAvailablePackages;
  82. procedure CheckFPMakeDependencies;
  83. function FindBrokenPackages(SL:TStrings):Boolean;
  84. property Options: TFppkgOptions read FOptions;
  85. property CompilerOptions: TCompilerOptions read FCompilerOptions;
  86. property FpmakeCompilerOptions: TCompilerOptions read FFpmakeCompilerOptions;
  87. property FPMakeRepositoryList: TComponentList read FFPMakeRepositoryList;
  88. property RepositoryList: TComponentList read FRepositoryList;
  89. property ConfigurationFilename: string read GetConfigurationFilename;
  90. public
  91. end;
  92. implementation
  93. {$IFDEF FPC_DOTTEDUNITS}
  94. uses
  95. Fpmkunit,
  96. FpPkg.XmlRep,
  97. FpPkg.PackageRepos;
  98. {$ELSE FPC_DOTTEDUNITS}
  99. uses
  100. fpmkunit,
  101. fpxmlrep,
  102. pkgrepos;
  103. {$ENDIF FPC_DOTTEDUNITS}
  104. { TpkgFPpkg }
  105. constructor TpkgFPpkg.Create(AOwner: TComponent);
  106. begin
  107. inherited Create(AOwner);
  108. FOptions := TFppkgOptions.Create;
  109. FCompilerOptions := TCompilerOptions.Create;
  110. FFpmakeCompilerOptions := TCompilerOptions.Create;
  111. FRepositoryList := TComponentList.Create(False);
  112. FFPMakeRepositoryList := TComponentList.Create(False);
  113. FBrokenPackagesDictionary := TFPHashList.Create;
  114. end;
  115. destructor TpkgFPpkg.Destroy;
  116. begin
  117. FBrokenPackagesDictionary.Free;
  118. FFPMakeRepositoryList.Free;
  119. FRepositoryList.Free;
  120. FCompilerOptions.Free;
  121. FFpmakeCompilerOptions.Free;
  122. FOptions.Free;
  123. inherited Destroy;
  124. end;
  125. function TpkgFPpkg.IncludeRepositoryTypeForPackageKind(ARepositoryType: TFPRepositoryType;
  126. APackageKind: TpkgPackageKind): Boolean;
  127. begin
  128. Result := ((APackageKind=pkgpkInstalled) and (ARepositoryType = fprtInstalled)) or
  129. ((APackageKind=pkgpkAvailable) and (ARepositoryType = fprtAvailable)) or
  130. (APackageKind=pkgpkBoth);
  131. end;
  132. procedure TpkgFPpkg.ScanPackagesOnDisk(ACompilerOptions: TCompilerOptions;
  133. APackageKind: TpkgPackageKind; ARepositoryList: TComponentList);
  134. var
  135. i: Integer;
  136. RepoOption: TFppkgRepositoryOptionSection;
  137. Repo: TFPRepository;
  138. begin
  139. FOptions.BindToCompilerOptions(ACompilerOptions);
  140. for i := 0 to FOptions.SectionList.Count -1 do
  141. begin
  142. if FOptions.SectionList[i] is TFppkgRepositoryOptionSection then
  143. begin
  144. RepoOption := TFppkgRepositoryOptionSection(FOptions.SectionList[i]);
  145. if IncludeRepositoryTypeForPackageKind(RepoOption.GetRepositoryType, APackageKind) then
  146. begin
  147. Repo := CreateRepository(RepoOption, FOptions, ACompilerOptions);
  148. if Assigned(Repo) then
  149. begin
  150. ARepositoryList.Add(Repo);
  151. if Assigned(Repo.DefaultPackagesStructure) then
  152. Repo.DefaultPackagesStructure.AddPackagesToRepository(Repo);
  153. end;
  154. end;
  155. end;
  156. end;
  157. end;
  158. function TpkgFPpkg.CreateRepository(ARepoOptionSection: TFppkgRepositoryOptionSection;
  159. AnOptions: TFppkgOptions; ACompilerOptions: TCompilerOptions): TFPRepository;
  160. begin
  161. Result := TFPRepository.Create(Self);
  162. Result.InitializeWithOptions(ARepoOptionSection, AnOptions, ACompilerOptions);
  163. end;
  164. procedure TpkgFPpkg.InitializeGlobalOptions(CfgFile: string);
  165. var
  166. GeneratedConfig: boolean;
  167. FirstRepoConf: TFppkgOptionSection;
  168. begin
  169. GeneratedConfig:=false;
  170. // First try specified config file
  171. if (CfgFile<>'') then
  172. begin
  173. if not FileExists(cfgfile) then
  174. Error(SErrNoSuchFile,[cfgfile]);
  175. end
  176. else
  177. begin
  178. // Now try if a local config-file exists
  179. cfgfile:=GetFppkgConfigFile(Options.PreferGlobal,False);
  180. if not FileExists(cfgfile) then
  181. begin
  182. // If not, try to find a global configuration file
  183. cfgfile:=GetFppkgConfigFile(not Options.PreferGlobal,False);
  184. if not FileExists(cfgfile) then
  185. begin
  186. // Create a new configuration file
  187. if not IsSuperUser then // Make a local, not global, configuration file
  188. cfgfile:=GetFppkgConfigFile(False,False);
  189. ForceDirectories(ExtractFilePath(cfgfile));
  190. FOptions.SaveToFile(cfgfile);
  191. GeneratedConfig:=true;
  192. end;
  193. end;
  194. end;
  195. // Load file or create new default configuration
  196. if not GeneratedConfig then
  197. begin
  198. FOptions.LoadFromFile(cfgfile);
  199. end;
  200. FOptions.CommandLineSection.CompilerConfig:=FOptions.GlobalSection.CompilerConfig;
  201. // Tracing of what we've done above, need to be done after the verbosity is set
  202. if GeneratedConfig then
  203. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug,SLogGeneratingGlobalConfig,[cfgfile])
  204. else
  205. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug,SLogLoadingGlobalConfig,[cfgfile]);
  206. FConfigurationFilename := CfgFile;
  207. // Log configuration
  208. FOptions.LogValues(llDebug);
  209. end;
  210. procedure TpkgFPpkg.InitializeCompilerOptions;
  211. var
  212. S : String;
  213. begin
  214. // Load default compiler config
  215. S:=FOptions.GlobalSection.CompilerConfigDir+FOptions.CommandLineSection.CompilerConfig;
  216. FCompilerOptions.UpdateLocalRepositoryOption(FOptions);
  217. if FileExists(S) then
  218. begin
  219. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug,SLogLoadingCompilerConfig,[S]);
  220. FCompilerOptions.LoadCompilerFromFile(S);
  221. if FCompilerOptions.SaveInifileChanges then
  222. // The file is in an old format, try to update the file but ignore
  223. // any failures.
  224. FCompilerOptions.SaveCompilerToFile(S);
  225. end
  226. else
  227. begin
  228. if FCompilerOptions.SaveInifileChanges then
  229. // A new fppkg.cfg has been created, try to create a new compiler-configuration
  230. // file too.
  231. begin
  232. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug,SLogGeneratingCompilerConfig,[S]);
  233. FCompilerOptions.InitCompilerDefaults;
  234. if not FCompilerOptions.SaveCompilerToFile(S) then
  235. Error(SErrMissingCompilerConfig,[S]);
  236. end
  237. else
  238. Error(SErrMissingCompilerConfig,[S]);
  239. end;
  240. // Log compiler configuration
  241. FCompilerOptions.LogValues(llDebug,'');
  242. // Load FPMake compiler config, this is normally the same config as above
  243. S:=FOptions.GlobalSection.CompilerConfigDir+FOptions.GlobalSection.FPMakeCompilerConfig;
  244. FFPMakeCompilerOptions.UpdateLocalRepositoryOption(FOptions);
  245. if FileExists(S) then
  246. begin
  247. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug,SLogLoadingFPMakeCompilerConfig,[S]);
  248. FFPMakeCompilerOptions.LoadCompilerFromFile(S);
  249. if FFPMakeCompilerOptions.SaveInifileChanges then
  250. // The file is in an old format, try to update the file but ignore
  251. // any failures.
  252. FFPMakeCompilerOptions.SaveCompilerToFile(S);
  253. end
  254. else
  255. Error(SErrMissingCompilerConfig,[S]);
  256. // Log compiler configuration
  257. FFPMakeCompilerOptions.LogValues(llDebug,'fpmake-building');
  258. end;
  259. procedure TpkgFPpkg.LoadLocalAvailableMirrors;
  260. var
  261. S : String;
  262. X : TFPXMLMirrorHandler;
  263. begin
  264. if assigned(AvailableMirrors) then
  265. AvailableMirrors.Free;
  266. AvailableMirrors:=TFPMirrors.Create(TFPMirror);
  267. // Repository
  268. S:=Options.GlobalSection.LocalMirrorsFile;
  269. log(llDebug,SLogLoadingMirrorsFile,[S]);
  270. if not FileExists(S) then
  271. exit;
  272. try
  273. X:=TFPXMLMirrorHandler.Create;
  274. With X do
  275. try
  276. LoadFromXml(AvailableMirrors,S);
  277. finally
  278. Free;
  279. end;
  280. except
  281. on E : Exception do
  282. begin
  283. Log(llError,E.Message);
  284. Error(SErrCorruptMirrorsFile,[S]);
  285. end;
  286. end;
  287. end;
  288. procedure TpkgFPpkg.ScanAvailablePackages;
  289. var
  290. Repo: TFPRepository;
  291. InstPackages: TFPCustomPackagesStructure;
  292. begin
  293. if (FOptions.GlobalSection.RemoteMirrorsURL<>'') or
  294. ((FOptions.GlobalSection.RemoteRepository<>'') and (FOptions.GlobalSection.RemoteRepository<>'auto')) then
  295. begin
  296. // In case of a re-scan (for example after an update), remove the old list
  297. Repo := FindRepository('Available');
  298. if Assigned(Repo) then
  299. begin
  300. RepositoryList.Remove(Repo);
  301. Repo.Free;
  302. end;
  303. Repo := TFPRepository.Create(Self);
  304. FRepositoryList.Add(Repo);
  305. Repo.RepositoryName := 'Available';
  306. Repo.Description := 'Packages available for download';
  307. Repo.RepositoryType := fprtAvailable;
  308. InstPackages := TFPRemotePackagesStructure.Create(Self);
  309. InstPackages.InitializeWithOptions(Nil, FOptions, FCompilerOptions);
  310. InstPackages.AddPackagesToRepository(Repo);
  311. Repo.DefaultPackagesStructure := InstPackages;
  312. end;
  313. end;
  314. procedure TpkgFPpkg.ScanPackages;
  315. begin
  316. // There is no need to scan for available packages and add them to the
  317. // FPMakeRepositoryList. Beside that it could lead to problems
  318. // when the scan of one of the available-repositories tries to compile an
  319. // fpmake-executable. (Like TFPUninstalledSourcesAvailablePackagesStructure does)
  320. ClearRepositories(FPMakeRepositoryList);
  321. ScanPackagesOnDisk(FFpmakeCompilerOptions, pkgpkInstalled, FPMakeRepositoryList);
  322. CheckFPMakeDependencies;
  323. ClearRepositories(RepositoryList);
  324. ScanPackagesOnDisk(FCompilerOptions, pkgpkBoth, RepositoryList);
  325. ScanAvailablePackages;
  326. end;
  327. function TpkgFPpkg.PackageIsBroken(APackage: TFPPackage; out Reason: string; ARepository: TFPRepository): Boolean;
  328. var
  329. j, i, ThisRepositoryIndex: Integer;
  330. Dependency: TFPDependency;
  331. Repository: TFPRepository;
  332. DepPackage: TFPPackage;
  333. HashPtr: PtrInt;
  334. begin
  335. result:=false;
  336. Reason := '';
  337. if Assigned(APackage.Repository) and (APackage.Repository.RepositoryType <> fprtInstalled) then
  338. begin
  339. Exit;
  340. end;
  341. EnterFindBrokenPackages;
  342. try
  343. HashPtr := PtrInt(FBrokenPackagesDictionary.Find(APackage.Name));
  344. if HashPtr<>0 then
  345. begin
  346. // Package is already evaluated
  347. Result := (HashPtr = 1);
  348. Exit;
  349. end;
  350. if not Assigned(ARepository) then
  351. begin
  352. // Check with all repositories
  353. ThisRepositoryIndex := RepositoryList.Count -1;
  354. end
  355. else
  356. begin
  357. // We should only check for dependencies in this repository, or repositories
  358. // with a lower priority.
  359. // This behaviour seems obsolete. The idea behind it was that each repository
  360. // should be useable, only using other repositories with a lower priority.
  361. // In practice this does not work, you have to consider the installation
  362. // as a whole, using all repositories. One specific user might not be able
  363. // to 'fix' the global fpc-repository, and so end up with broken packages
  364. // which he/she can not fix. Or packages may be forced to be installed in
  365. // a specific repository.
  366. // The functionality is kept for now, maybe there is a need for it in the
  367. // future... But for now, ARepository will be always nil.
  368. ThisRepositoryIndex := -1;
  369. for i := RepositoryList.Count -1 downto 0 do
  370. begin
  371. if RepositoryList.Items[i] = ARepository then
  372. ThisRepositoryIndex := i;
  373. end;
  374. end;
  375. for j:=0 to APackage.Dependencies.Count-1 do
  376. begin
  377. Dependency:=APackage.Dependencies[j];
  378. if (CompilerOptions.CompilerOS in Dependency.OSes) and
  379. (CompilerOptions.CompilerCPU in Dependency.CPUs) then
  380. begin
  381. DepPackage := nil;
  382. for i := ThisRepositoryIndex downto 0 do
  383. begin
  384. Repository := RepositoryList.Items[i] as TFPRepository;
  385. if Repository.RepositoryType=fprtInstalled then
  386. DepPackage := Repository.FindPackage(Dependency.PackageName);
  387. if Assigned(DepPackage) then
  388. Break;
  389. end;
  390. if assigned(DepPackage) then
  391. begin
  392. if PackageIsBroken(DepPackage, Reason, ARepository) then
  393. begin
  394. log(llInfo,SLogPackageDepBroken,[APackage.Name,APackage.Repository.RepositoryName,Dependency.PackageName,Repository.RepositoryName]);
  395. result:=true;
  396. Reason := Format(SInfoPackageDepBroken, [Dependency.PackageName, Repository.RepositoryName]);
  397. FBrokenPackagesDictionary.Add(APackage.Name, Pointer(1));
  398. exit;
  399. end;
  400. if (Dependency.RequireChecksum<>$ffffffff) and (DepPackage.Checksum<>Dependency.RequireChecksum) then
  401. begin
  402. log(llInfo,SLogPackageChecksumChanged,[APackage.Name,APackage.Repository.RepositoryName,Dependency.PackageName,Repository.RepositoryName]);
  403. result:=true;
  404. Reason := Format(SInfoPackageChecksumChanged, [Dependency.PackageName, Repository.RepositoryName]);
  405. FBrokenPackagesDictionary.Add(APackage.Name, Pointer(1));
  406. exit;
  407. end;
  408. end
  409. else
  410. begin
  411. log(llInfo,SDbgObsoleteDependency,[APackage.Name,Dependency.PackageName]);
  412. result:=true;
  413. Reason :=Format(SInfoObsoleteDependency, [Dependency.PackageName]);
  414. FBrokenPackagesDictionary.Add(APackage.Name, Pointer(1));
  415. exit;
  416. end;
  417. end;
  418. end;
  419. FBrokenPackagesDictionary.Add(APackage.Name, Pointer(2));
  420. finally
  421. LeaveFindBrokenpackages;
  422. end;
  423. end;
  424. function TpkgFPpkg.FPMakeRepoFindPackage(APackageName: string;
  425. APackageKind: TpkgPackageKind): TFPPackage;
  426. begin
  427. Result := FindPackage(FPMakeRepositoryList, APackageName, APackageKind);
  428. end;
  429. function TpkgFPpkg.FindPackage(APackageName: string;
  430. APackageKind: TpkgPackageKind): TFPPackage;
  431. begin
  432. Result := FindPackage(RepositoryList, APackageName, APackageKind);
  433. end;
  434. function TpkgFPpkg.FindPackage(ARepositoryList: TComponentList; APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  435. var
  436. i: Integer;
  437. Repo: TFPRepository;
  438. begin
  439. Result := nil;
  440. for i := ARepositoryList.Count-1 downto 0 do
  441. begin
  442. Repo := ARepositoryList.Items[i] as TFPRepository;
  443. if IncludeRepositoryTypeForPackageKind(Repo.RepositoryType, APackageKind) then
  444. begin
  445. Result := repo.FindPackage(APackageName);
  446. if Assigned(Result) then
  447. Break;
  448. end;
  449. end;
  450. end;
  451. function TpkgFPpkg.SelectRemoteMirror: string;
  452. var
  453. i,j : Integer;
  454. Bucket,
  455. BucketCnt : Integer;
  456. M : TFPMirror;
  457. begin
  458. Result:='';
  459. M:=nil;
  460. if assigned(AvailableMirrors) then
  461. begin
  462. // Create array for selection
  463. BucketCnt:=0;
  464. for i:=0 to AvailableMirrors.Count-1 do
  465. inc(BucketCnt,AvailableMirrors[i].Weight);
  466. // Select random entry
  467. Bucket:=Random(BucketCnt);
  468. M:=nil;
  469. for i:=0 to AvailableMirrors.Count-1 do
  470. begin
  471. for j:=0 to AvailableMirrors[i].Weight-1 do
  472. begin
  473. if Bucket=0 then
  474. begin
  475. M:=AvailableMirrors[i];
  476. break;
  477. end;
  478. Dec(Bucket);
  479. end;
  480. if assigned(M) then
  481. break;
  482. end;
  483. end;
  484. if assigned(M) then
  485. begin
  486. log(llInfo,SLogSelectedMirror,[M.Name]);
  487. Result:=M.URL;
  488. end
  489. else
  490. Error(SErrFailedToSelectMirror);
  491. end;
  492. procedure TpkgFPpkg.EnterFindBrokenPackages;
  493. begin
  494. Assert((FInsideFindBrokenPackages>0) or (FBrokenPackagesDictionary.Count=0));
  495. Inc(FInsideFindBrokenPackages)
  496. end;
  497. procedure TpkgFPpkg.LeaveFindBrokenpackages;
  498. begin
  499. Assert(FInsideFindBrokenPackages>0);
  500. Dec(FInsideFindBrokenPackages);
  501. if FInsideFindBrokenPackages=0 then
  502. FBrokenPackagesDictionary.Clear;
  503. end;
  504. procedure TpkgFPpkg.ClearRepositories(ARepositoryList: TComponentList);
  505. var
  506. i: Integer;
  507. Repo: TFPRepository;
  508. begin
  509. for i := ARepositoryList.Count -1 downto 0 do
  510. begin
  511. Repo := ARepositoryList.Items[i] as TFPRepository;
  512. if Repo.Name <> 'Available' then
  513. begin
  514. ARepositoryList.Delete(i);
  515. Repo.Free;
  516. end;
  517. end;
  518. end;
  519. function TpkgFPpkg.PackageByName(APackageName: string; APackageKind: TpkgPackageKind): TFPPackage;
  520. var
  521. ErrStr: string;
  522. begin
  523. Result := FindPackage(APackageName, APackageKind);
  524. If Result=Nil then
  525. begin
  526. case APackageKind of
  527. pkgpkInstalled : ErrStr:=SErrMissingInstallPackage;
  528. pkgpkAvailable : ErrStr:=SErrMissingAvailablePackage;
  529. pkgpkBoth : ErrStr:=SErrMissingPackage;
  530. end;
  531. Raise EPackage.CreateFmt(ErrStr,[APackageName]);
  532. end;
  533. end;
  534. function TpkgFPpkg.FindRepository(ARepositoryName: string): TFPRepository;
  535. var
  536. i: Integer;
  537. Repo: TFPRepository;
  538. begin
  539. Result := nil;
  540. for i := FRepositoryList.Count-1 downto 0 do
  541. begin
  542. Repo := FRepositoryList.Items[i] as TFPRepository;
  543. if Repo.RepositoryName = ARepositoryName then
  544. begin
  545. Result := Repo;
  546. Break;
  547. end;
  548. end;
  549. end;
  550. function TpkgFPpkg.RepositoryByName(ARepositoryName: string): TFPRepository;
  551. begin
  552. Result := FindRepository(ARepositoryName);
  553. If Result=Nil then
  554. Raise EPackage.CreateFmt(SErrMissingInstallRepo,[ARepositoryName]);
  555. end;
  556. function TpkgFPpkg.GetInstallRepository(ASourcePackage: TFPPackage): TFPRepository;
  557. var
  558. SourceRepository: TFPRepository;
  559. RepoName: string;
  560. i: Integer;
  561. begin
  562. // Determine the repository to install a package into. See the
  563. // repositorylogics.dia file.
  564. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug, SLogDetermineInstallRepo, [ASourcePackage.GetDebugName]);
  565. RepoName := Options.CommandLineSection.InstallRepository;
  566. if RepoName <> '' then
  567. // If an install-repository is given on the command line, this overrides
  568. // everything.
  569. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug, SLogUseCommandLineRepo, [RepoName])
  570. else
  571. begin
  572. // The source-repository is already determined by the source-package, which
  573. // is a member of the source-repository.
  574. SourceRepository := ASourcePackage.Repository;
  575. Assert(Assigned(SourceRepository));
  576. Assert(SourceRepository.RepositoryType = fprtAvailable);
  577. // For now, skip the check for original sources of already installed packages.
  578. Assert(Assigned(SourceRepository.DefaultPackagesStructure));
  579. RepoName := SourceRepository.DefaultPackagesStructure.InstallRepositoryName;
  580. if RepoName<>'' then
  581. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug, SLogUseSourceRepoInstRepo, [RepoName, SourceRepository.RepositoryName])
  582. else
  583. begin
  584. RepoName := Options.GlobalSection.InstallRepository;
  585. if RepoName<>'' then
  586. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug, SLogUseConfigurationRepo, [RepoName])
  587. else
  588. begin
  589. for i := RepositoryList.Count-1 downto 0 do
  590. begin
  591. if (RepositoryList[i] as TFPRepository).RepositoryType = fprtInstalled then
  592. begin
  593. Result := TFPRepository(RepositoryList[i]);
  594. {$IFDEF FPC_DOTTEDUNITS}FpPkg.Globals{$ELSE}pkglobals{$ENDIF}.Log(llDebug, SLogUseLastRepo, [Result.RepositoryName]);
  595. Exit;
  596. end;
  597. end;
  598. raise EPackage.Create(SErrNoInstallRepoAvailable);
  599. end;
  600. end;
  601. end;
  602. Result := RepositoryByName(RepoName);
  603. end;
  604. function TpkgFPpkg.DetermineSourcePackage(APackageName: String): TFPPackage;
  605. begin
  606. Result := FindPackage(APackageName, pkgpkAvailable);
  607. end;
  608. function TpkgFPpkg.PackageLocalArchive(APackage: TFPPackage): String;
  609. begin
  610. if APackage.Name=CurrentDirPackageName then
  611. Error(SErrNoPackageSpecified)
  612. else if APackage.Name=CmdLinePackageName then
  613. Result:=APackage.LocalFileName
  614. else
  615. Result:=Options.GlobalSection.ArchivesDir+APackage.FileName;
  616. end;
  617. procedure TpkgFPpkg.ScanInstalledPackagesForAvailablePackages;
  618. var
  619. i: Integer;
  620. Repo, AvailableRepo: TFPRepository;
  621. AvailStruc: TFPOriginalSourcePackagesStructure;
  622. begin
  623. for i := 0 to FRepositoryList.Count-1 do
  624. begin
  625. Repo := FRepositoryList.Items[i] as TFPRepository;
  626. if Repo.RepositoryType = fprtInstalled then
  627. begin
  628. AvailableRepo := TFPRepository.Create(Self);
  629. FRepositoryList.Add(AvailableRepo);
  630. AvailableRepo.RepositoryType := fprtAvailable;
  631. AvailableRepo.RepositoryName := Repo.RepositoryName + '_source';
  632. AvailableRepo.Description := Repo.Description + ' (original sources)';
  633. AvailStruc := TFPOriginalSourcePackagesStructure.Create(Self, Repo);
  634. AvailStruc.InitializeWithOptions(nil, FOptions, FCompilerOptions);
  635. AvailStruc.InstallRepositoryName := Repo.RepositoryName;
  636. AvailStruc.AddPackagesToRepository(AvailableRepo);
  637. AvailableRepo.DefaultPackagesStructure := AvailStruc;
  638. end;
  639. end;
  640. end;
  641. procedure TpkgFPpkg.CheckFPMakeDependencies;
  642. var
  643. i : Integer;
  644. P,AvailP : TFPPackage;
  645. AvailVerStr : string;
  646. ReqVer : TFPVersion;
  647. begin
  648. // Reset availability
  649. for i:=0 to high(FPMKUnitDeps) do
  650. FPMKUnitDeps[i].available:=false;
  651. // Not version check needed in Recovery mode, we always need to use
  652. // the internal bootstrap procedure
  653. if Options.CommandLineSection.RecoveryMode then
  654. exit;
  655. // Check for fpmkunit dependencies
  656. for i:=0 to high(FPMKUnitDeps) do
  657. begin
  658. P:=FPMakeRepoFindPackage(FPMKUnitDeps[i].package, pkgpkInstalled);
  659. if P<>nil then
  660. begin
  661. AvailP:=FindPackage(FPMKUnitDeps[i].package, pkgpkAvailable);
  662. if AvailP<>nil then
  663. AvailVerStr:=AvailP.Version.AsString
  664. else
  665. AvailVerStr:='<not available>';
  666. ReqVer:=TFPVersion.Create;
  667. try
  668. ReqVer.AsString:=FPMKUnitDeps[i].ReqVer;
  669. log(llDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.Version.AsString,AvailVerStr]);
  670. if ReqVer.CompareVersion(P.Version)<=0 then
  671. FPMKUnitDeps[i].available:=true
  672. else
  673. log(llDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
  674. finally
  675. ReqVer.Free;
  676. end;
  677. end
  678. else
  679. log(llDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
  680. end;
  681. end;
  682. function TpkgFPpkg.FindBrokenPackages(SL: TStrings): Boolean;
  683. var
  684. i,j,k : integer;
  685. P : TFPPackage;
  686. s : string;
  687. Repo: TFPRepository;
  688. begin
  689. SL.Clear;
  690. EnterFindBrokenPackages;
  691. try
  692. for i:=0 to RepositoryList.Count-1 do
  693. begin
  694. Repo := TFPRepository(RepositoryList[i]);
  695. if Repo.RepositoryType = fprtInstalled then
  696. begin
  697. for j := 0 to Repo.PackageCount-1 do
  698. begin
  699. P := Repo.Packages[j];
  700. if (P = FindPackage(P.Name, pkgpkInstalled)) and PackageIsBroken(P, s, nil) then
  701. begin
  702. if P.IsFPMakeAddIn then
  703. // Make sure that FPMakeAddIn's are fixed first, so
  704. // as much packages are compiled with them.
  705. SL.Insert(0, P.Name)
  706. else
  707. SL.Add(P.Name);
  708. end;
  709. end;
  710. end;
  711. end;
  712. finally
  713. LeaveFindBrokenpackages;
  714. end;
  715. Result:=(SL.Count>0);
  716. end;
  717. function TpkgFPpkg.PackageBuildPath(APackage: TFPPackage): String;
  718. begin
  719. if (APackage.Name=CmdLinePackageName) or (APackage.Name=URLPackageName) then
  720. Result:=Options.GlobalSection.BuildDir+ChangeFileExt(ExtractFileName(APackage.LocalFileName),'')
  721. else if Assigned(APackage.PackagesStructure) and (APackage.PackagesStructure.GetBuildPathDirectory(APackage)<>'') then
  722. Result:=APackage.PackagesStructure.GetBuildPathDirectory(APackage)
  723. else
  724. Result:=Options.GlobalSection.BuildDir+APackage.Name;
  725. end;
  726. function TpkgFPpkg.GetRemoteRepositoryURL(const AFileName: string): string;
  727. begin
  728. if FCurrentRemoteRepositoryURL='' then
  729. begin
  730. if Options.GlobalSection.RemoteRepository='auto' then
  731. FCurrentRemoteRepositoryURL:=SelectRemoteMirror
  732. else
  733. FCurrentRemoteRepositoryURL:=Options.GlobalSection.RemoteRepository;
  734. end;
  735. result := FCurrentRemoteRepositoryURL;
  736. if result <> '' then
  737. begin
  738. if result[length(result)]<>'/' then
  739. result := result + '/';
  740. Result:=Result+CompilerOptions.CompilerVersion+'/'+AFileName;
  741. end;
  742. end;
  743. function TpkgFPpkg.PackageRemoteArchive(APackage: TFPPackage): String;
  744. begin
  745. if APackage.Name=CurrentDirPackageName then
  746. Error(SErrNoPackageSpecified)
  747. else if APackage.Name=CmdLinePackageName then
  748. Error(SErrPackageIsLocal);
  749. if APackage.DownloadURL<>'' then
  750. Result:=APackage.DownloadURL
  751. else
  752. Result:=GetRemoteRepositoryURL(APackage.FileName);
  753. end;
  754. function TpkgFPpkg.GetConfigurationFilename: string;
  755. begin
  756. Result := FConfigurationFilename;
  757. end;
  758. end.