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