{ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Balázs Székely Abstract: Implementation of the serializable package class. Information about the repository packages are stored in a json file. After the JSON is downloaded it gets serialized to a package list.} unit opkman_serializablepackages; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Variants, contnrs, dateutils, fpjson, jsonparser, // LazUtils FileUtil, Laz2_XMLCfg, LazFileUtils, // IdeIntf PackageDependencyIntf, PackageIntf, // OpkMan opkman_common, opkman_const, opkman_options; type TPackageState = ( psRepository, psDownloaded, psExtracted, psInstalled, psError); TPackageStates = set of TPackageState; TChangeType = (ctAdd, ctRemove); TSortType = (stName, stDate); TSortOrder = (soAscendent, soDescendent); {$M+} TPackageVersion = class(TPkgVersion) published property Major; property Minor; property Release; property Build; property IsNullVersion; end; {$M-} { TPackageDependency } TPackageDependency = class(TCollectionItem) private FMaxVersion: TPackageVersion; FMinVersion: TPackageVersion; FPkgFileName: String; procedure SetMinVersion(const AValue: TPackageVersion); procedure SetMaxVersion(const AValue: TPackageVersion); public procedure Assign(ASource: TPersistent); override; constructor Create(ACollection: TCollection); override; destructor Destroy; override; published property PkgFileName: String read FPkgFileName write FPkgFileName; property MinVersion: TPackageVersion read FMinVersion write SetMinVersion; property MaxVersion: TPackageVersion read FMaxVersion write SetMaxVersion; end; { TPackageDependencies } TPackageDependencies = class(TCollection) private function GetDependency(AIndex: Integer): TPackageDependency; procedure SetDependency(AIndex: Integer; const AValue: TPackageDependency); public function GetDependenciesAsString(const AIsDisplayString: Boolean): String; procedure SetDependenciesAsString(const AValue: String); property Dependencies[AIndex: Integer]: TPackageDependency read GetDependency write SetDependency; default; end; { TLazarusPackage } TLazarusPackage = class(TCollectionItem) private FName: String; FDescription: String; FAuthor: String; FLicense: String; FPackageState: TPackageState; FPackageStates: TPackageStates; FPackageType: TLazPackageType; FLazCompatibility: String; FFPCCompatibility: String; FSupportedWidgetSet: String; FPackageRelativePath: String; FPackageAbsolutePath: String; FInstalledFileName: String; FInstalledFileVersion: String; FInstalledFileDescription: String; FInstalledFileLincese: String; FUpdateVersion: String; FForceNotify: Boolean; FInternalVersion: Integer; FInternalVersionOld: Integer; FHasUpdate: Boolean; FVersion: TPackageVersion; FVersionAsString: String; FDependencies: TPackageDependencies; FDependenciesAsString: String; FChecked: Boolean; function GetVersionAsString: String; function GetDependenciesAsString: String; procedure SetVersionAsString(const AValue: String); procedure SetDependenciesAsString(const AValue: String); function GetInstallable: Boolean; public constructor Create; reintroduce; destructor Destroy; override; public procedure RefreshHasUpdate; property Version: TPackageVersion read FVersion write FVersion; property Dependencies: TPackageDependencies read FDependencies write FDependencies; property PackageStates: TPackageStates read FPackageStates write FPackageStates; property PackageState: TPackageState read FPackageState write FPackageState; property InstalledFileName: String read FInstalledFileName write FInstalledFileName; property InstalledFileVersion: String read FInstalledFileVersion write FInstalledFileVersion; property UpdateVersion: String read FUpdateVersion write FUpdateVersion; property PackageAbsolutePath: String read FPackageAbsolutePath write FPackageAbsolutePath; property Checked: Boolean read FChecked write FChecked; property IsInstallable: Boolean read GetInstallable; property ForceNotify: Boolean read FForceNotify write FForceNotify; property InternalVersion: Integer read FInternalVersion write FInternalVersion; property InternalVersionOld: Integer read FInternalVersionOld write FInternalVersionOld; property HasUpdate: Boolean read FHasUpdate write FHasUpdate; property InstalledFileDescription: String read FInstalledFileDescription write FInstalledFileDescription; property InstalledFileLincese: String read FInstalledFileLincese write FInstalledFileLincese; published property Name: String read FName write FName; property Author: String read FAuthor write FAuthor; property Description: String read FDescription write FDescription; property PackageRelativePath: string read FPackageRelativePath write FPackageRelativePath; property VersionAsString: String read GetVersionAsString write SetVersionAsString; property LazCompatibility: String read FLazCompatibility write FLazCompatibility; property FPCCompatibility: String read FFPCCompatibility write FFPCCompatibility; property SupportedWidgetSet: String read FSupportedWidgetSet write FSupportedWidgetSet; property PackageType: TLazPackageType read FPackageType write FPackageType; property License: String read FLicense write FLicense; property DependenciesAsString: String read GetDependenciesAsString write SetDependenciesAsString; end; {TMetaPackage} TMetaPackage = class(TCollectionItem) private FName: String; FDisplayName: String; FCategory: String; FCommunityDescription: String; FRepositoryFileName: String; FRepositoryFileSize: Int64; FRepositoryFileHash: String; FChecked: Boolean; FRepositoryDate: TDateTime; FPackageState: TPackageState; FPackageStates: TPackageStates; FPackageBaseDir: String; FHomePageURL: String; FDownloadURL: String; FDownloadZipURL: String; FHasUpdate: Boolean; FDisableInOPM: Boolean; FSVNURL: String; FUpdateSize: Int64; FIsDirZipped: Boolean; FZippedBaseDir: String; FRating: Integer; FLazarusPackages: TCollection; function GetDownloadable: Boolean; function GetExtractable: Boolean; public constructor Create; reintroduce; destructor Destroy; override; procedure ChangePackageStates(const AChangeType: TChangeType; APackageState: TPackageState); function FindLazarusPackage(const APackageName: String): TLazarusPackage; public property PackageStates: TPackageStates read FPackageStates; property PackageState: TPackageState read FPackageState; property IsDownloadable: Boolean read GetDownloadable; property IsExtractable: Boolean read GetExtractable; property UpdateSize: Int64 read FUpdateSize write FUpdateSize; property IsDirZipped: Boolean read FIsDirZipped write FIsDirZipped; property ZippedBaseDir: String read FZippedBaseDir write FZippedBaseDir; property DownloadZipURL: String read FDownloadZipURL write FDownloadZipURL; property HasUpdate: Boolean read FHasUpdate write FHasUpdate; property DisableInOPM: Boolean read FDisableInOPM write FDisableInOPM; property Rating: Integer read FRating write FRating; published property Name: String read FName write FName; property DisplayName: String read FDisplayName write FDisplayName; property Category: String read FCategory write FCategory; property CommunityDescription: string read FCommunityDescription write FCommunityDescription; property Checked: Boolean read FChecked write FChecked; property RepositoryFileName: String read FRepositoryFileName write FRepositoryFileName; property RepositoryFileSize: int64 read FRepositoryFileSize write FRepositoryFileSize; property RepositoryFileHash: String read FRepositoryFileHash write FRepositoryFileHash; property RepositoryDate: TDateTime read FRepositoryDate write FRepositoryDate; property PackageBaseDir: String read FPackageBaseDir write FPackageBaseDir; property LazarusPackages: TCollection read FLazarusPackages write FLazarusPackages; property HomePageURL: String read FHomePageURL write FHomePageURL; property DownloadURL: String read FDownloadURL write FDownloadURL; property SVNURL: String read FSVNURL write FSVNURL; end; { TSerializablePackages } TFindPackageBy = (fpbPackageName, fpbRepositoryFilename); TSerializablePackages = class private FMetaPackages: TCollection; FLastError: String; FOnProcessJSON: TNotifyEvent; FOnUpdatePackageLinks: TNotifyEvent; function GetCount: Integer; function GetDownloadCount: Integer; function GetExtractCount: Integer; function GetInstallCount: Integer; function GetItem(const AIndex: Integer): TMetaPackage; procedure SetItem(const AIndex: Integer; const AMetaPackage: TMetaPackage); procedure DoGetPackageDependencies(const APkgFileName: String; ASL: TStringList; ALevel: Integer); function JSONToPackageData(const APackageData: TJSONData; var AMetaPackage: TMetaPackage): Boolean; function JSONToLazarusPackages(const APackageData: TJSONData; var AMetaPackage: TMetaPackage): Boolean; function PackageDataToJSON(AMetaPackage: TMetaPackage; var APackageData: TJSONObject): Boolean; function LazarusPackagesToJSON(AMetaPackage: TMetaPackage; var ALazarusPkgsArr: TJSONArray): Boolean; function IsPackageDownloaded(const AMetaPackage: TMetaPackage): Boolean; function IsPackageExtracted(const AMetaPackage: TMetaPackage): Boolean; function IsPackageInstalled(const ALazarusPkg: TLazarusPackage; const APackageBaseDir: String): Boolean; function AtLeastOneLazPkgInstalled(const AMetaPackage: TMetaPackage): Boolean; function GetPackageVersion(const APath: String): String; function GetPackageDescription(const APath: String): String; function GetPackageLicense(const APath: String): String; public constructor Create; destructor Destroy; override; public procedure Clear; function AddMetaPackage(const AName: String): TMetaPackage; procedure DeletePackage(const AIndex: Integer); function AddPackageFromJSON(JSON: TJSONStringType): Boolean; function FindMetaPackage(const AValue: String; const AFindPackageBy: TFindPackageBy): TMetaPackage; function FindMetaPackageByLazarusPackage(const ALazarusPackage: TLazarusPackage): TMetaPackage; function FindPackageIndex(const AValue: String; const AFindPackageBy: TFindPackageBy): Integer; function FindLazarusPackage(const APackageName: String): TLazarusPackage; function JSONToPackages(JSON: TJSONStringType): Boolean; function PackagesToJSON(var JSON: TJSONStringType): Boolean; procedure GetPackageDependencies(const APkgFileName: String; List: TObjectList; Recurse, OnlyUnresolved: Boolean); procedure GetPackageStates; procedure RemoveErrorState; procedure RemoveCheck; procedure MarkRuntimePackages; function Cleanup: Integer; function IsDependencyOk(PackageDependency: TPackageDependency; DependencyPackage: TLazarusPackage): Boolean; function IsInstalledVersionOk(PackageDependency: TPackageDependency; InstalledVersion: String): Boolean; function GetPackageInstallState(const AMetaPackage: TMetaPackage): Integer; overload; procedure DeleteDownloadedZipFiles; procedure Sort(const ASortType: TSortType; const ASortOrder: TSortOrder); function QuickStatistics: String; public property Count: Integer read GetCount; property DownloadCount: Integer read GetDownloadCount; property ExtractCount: Integer read GetExtractCount; property InstallCount: Integer read GetInstallCount; property Items[Index: Integer]: TMetaPackage read GetItem write SetItem; property LastError: String read FlastError; property OnProcessJSON: TNotifyEvent read FOnProcessJSON write FOnProcessJSON; property OnUpdatePackageLinks: TNotifyEvent read FOnUpdatePackageLinks write FOnUpdatePackageLinks; end; var SerializablePackages: TSerializablePackages = nil; implementation { TPackageDependency } procedure TPackageDependency.SetMinVersion(const AValue: TPackageVersion); begin FMinVersion.Assign(AValue); end; procedure TPackageDependency.SetMaxVersion(const AValue: TPackageVersion); begin FMaxVersion.Assign(AValue); end; procedure TPackageDependency.Assign(ASource: TPersistent); var Source: TPackageDependency; begin if ASource is TPackageDependency then begin Source := ASource as TPackageDependency; FPkgFileName := Source.PkgFileName; if Assigned(Source.MinVersion) then FMinVersion.Assign(Source.MinVersion); if Assigned(Source.MaxVersion) then FMaxVersion.Assign(Source.MaxVersion); end else inherited Assign(Source); end; constructor TPackageDependency.Create(ACollection: TCollection); begin inherited Create(ACollection); FMinVersion := TPackageVersion.Create; FMaxVersion := TPackageVersion.Create; end; destructor TPackageDependency.Destroy; begin if Assigned(FMinVersion) then FMinVersion.Free; if Assigned(fMaxVersion) then FMaxVersion.Free; inherited Destroy; end; { TPackageDependencies } function TPackageDependencies.GetDependency(AIndex: Integer): TPackageDependency; begin Result := TPackageDependency(Items[AIndex]); end; procedure TPackageDependencies.SetDependency(AIndex: Integer; const AValue: TPackageDependency); begin Items[AIndex] := AValue; end; function TPackageDependencies.GetDependenciesAsString(const AIsDisplayString: Boolean): String; var I: Integer; MinVer, MaxVer: String; begin Result := ''; for I := 0 to Count - 1 do begin MinVer := ''; MaxVer := ''; if not Dependencies[I].FMinVersion.IsNullVersion then begin if AIsDisplayString then MinVer := '(>=' + IntToStr(Dependencies[I].FMinVersion.Major) + '.' + IntToStr(Dependencies[I].FMinVersion.Minor) + ')' else MinVer := '(' + Dependencies[I].FMinVersion.AsString + ')'; end; if not Dependencies[I].FMaxVersion.IsNullVersion then begin if AIsDisplayString then MaxVer := '(<=' + IntToStr(Dependencies[I].FMaxVersion.Major) + '.' + IntToStr(Dependencies[I].FMaxVersion.Minor) + ')' else MaxVer := '(' + Dependencies[I].FMaxVersion.AsString + ')' end; if Result = '' then Result := Dependencies[I].PkgFileName + MinVer + MaxVer else Result := Result + ', ' + Dependencies[I].PkgFileName + MinVer + MaxVer; end; end; procedure TPackageDependencies.SetDependenciesAsString(const AValue: String); var PackageDependency: TPackageDependency; SL: TStringList; P1, P2: Integer; Str: String; I: Integer; begin SL := TStringList.Create; try SL.Delimiter := ','; SL.DelimitedText := AValue; for I := 0 to SL.Count - 1 do begin Str := Trim(SL.Strings[I]); PackageDependency := TPackageDependency(Self.Add); if not Assigned(PackageDependency.FMinVersion) then PackageDependency.FMinVersion := TPackageVersion.Create; if not Assigned(PackageDependency.FMaxVersion) then PackageDependency.FMaxVersion := TPackageVersion.Create; P1 := Pos('(', Str); P2 := Pos(')', Str); if (P1 <> 0) and (P2 <> 0) then begin PackageDependency.PkgFileName := Trim(Copy(Str, 1, P1 - 1)); PackageDependency.FMinVersion.AsString := Trim(Copy(Str, P1 + 1, P2 - P1 - 1)); System.Delete(Str, 1, P2); if Length(Trim(Str)) > 0 then PackageDependency.FMaxVersion.AsString := Trim(Copy(Str, 2, Length(Str) - 2)); end else PackageDependency.PkgFileName := Trim(Str); end; finally SL.Free; end; end; { TLazarusPackage } function TLazarusPackage.GetVersionAsString: String; begin Result := IntToStr(FVersion.Major) + '.' + IntToStr(FVersion.Minor) + '.' + IntToStr(FVersion.Release) + '.' + IntToStr(FVersion.Build); end; procedure TLazarusPackage.SetVersionAsString(const AValue: String); begin if not Assigned(FVersion) then begin if not Assigned(FVersion) then FVersion := TPackageVersion.Create; FVersion.AsString := AValue; end; FVersionAsString := AValue; end; function TLazarusPackage.GetDependenciesAsString: String; begin Result := FDependencies.GetDependenciesAsString(False); end; procedure TLazarusPackage.SetDependenciesAsString(const AValue: String); begin if not Assigned(FDependencies) then begin FDependencies := TPackageDependencies.Create(TPackageDependency); FDependencies.SetDependenciesAsString(AValue); end; FDependenciesAsString := AValue; end; function TLazarusPackage.GetInstallable: Boolean; begin case PackageAction of paDownloadTo: Result := False; paInstall, paUpdate: Result := (Checked) and (psExtracted in PackageStates) and (not (psError in PackageStates)); end; end; constructor TLazarusPackage.Create; begin FVersion := TPackageVersion.Create; FVersion.Clear; PackageStates := []; FDependencies := TPackageDependencies.Create(TPackageDependency); end; destructor TLazarusPackage.Destroy; begin if Assigned(FVersion) then FreeAndNil(FVersion); if Assigned(FDependencies) then FreeAndNil(FDependencies); inherited Destroy; end; procedure TLazarusPackage.RefreshHasUpdate; begin FHasUpdate := (FUpdateVersion <> '') and (FInstalledFileVersion <> '') and ( ((not FForceNotify) {and (FUpdateVersion > FInstalledFileVersion)}) or ((FForceNotify) and (FInternalVersion > FInternalVersionOld)) ); end; { TMetaPackage } function TMetaPackage.GetDownloadable: Boolean; begin case PackageAction of paDownloadTo, paUpdate: Result := (Checked) and (not (psError in PackageStates)); paInstall: Result := (Checked) and (psRepository in PackageStates) and (not (psError in PackageStates)) and ((Options.ForceDownloadAndExtract) or ((not (psDownloaded in PackageStates)) and (not (psExtracted in PackageStates)))); end; end; function TMetaPackage.GetExtractable: Boolean; begin case PackageAction of paDownloadTo, paUpdate: Result := (Checked) and (not (psError in PackageStates)); paInstall: Result := (Checked) and (psDownloaded in PackageStates) and (not (psError in PackageStates)) and ((Options.ForceDownloadAndExtract) or ((not (psExtracted in PackageStates)) and (not (psInstalled in PackageStates)))); end; end; constructor TMetaPackage.Create; begin FLazarusPackages := TCollection.Create(TLazarusPackage); end; destructor TMetaPackage.Destroy; var I: Integer; begin FLazarusPackages.Clear; for I := FLazarusPackages.Count - 1 downto 0 do FLazarusPackages.Items[I].Free; FLazarusPackages.Free; inherited Destroy; end; procedure TMetaPackage.ChangePackageStates(const AChangeType: TChangeType; APackageState: TPackageState); var I: Integer; LazarusPkg: TLazarusPackage; begin if APackageState = psInstalled then Exit; //propagate states to package files case AChangeType of ctAdd: begin FPackageStates := FPackageStates + [APackageState]; for I := 0 to LazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(LazarusPackages.Items[I]); LazarusPkg.PackageStates := LazarusPkg.PackageStates + [APackageState]; LazarusPkg.PackageState := APackageState; end; end; ctRemove: begin FPackageStates := FPackageStates - [APackageState]; for I := 0 to LazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(LazarusPackages.Items[I]); LazarusPkg.PackageStates := LazarusPkg.PackageStates - [APackageState]; end; end; end; end; function TMetaPackage.FindLazarusPackage(const APackageName: String): TLazarusPackage; var I: Integer; begin for I := 0 to FLazarusPackages.Count - 1 do begin Result := TLazarusPackage(FLazarusPackages.Items[I]); if UpperCase(Result.Name) = UpperCase(APackageName) then Exit; end; Result := nil; end; { TSerializablePackages } constructor TSerializablePackages.Create; begin FMetaPackages := TCollection.Create(TMetaPackage); end; destructor TSerializablePackages.Destroy; begin Clear; FMetaPackages.Free; inherited Destroy; end; procedure TSerializablePackages.Clear; var I: Integer; begin for I := Count - 1 downto 0 do Items[I].Free; FMetaPackages.Clear; end; function TSerializablePackages.GetCount: Integer; begin Result := FMetaPackages.Count; end; function TSerializablePackages.GetDownloadCount: Integer; var I: Integer; begin Result := 0; for I := 0 to Count - 1 do if Items[I].IsDownloadable then Inc(Result); end; function TSerializablePackages.GetExtractCount: Integer; var I: Integer; begin Result := 0; for I := 0 to Count - 1 do if Items[I].IsExtractable then Inc(Result); end; function TSerializablePackages.GetInstallCount: Integer; var I, J: Integer; begin Result := 0; for I := 0 to Count - 1 do for J := 0 to Items[I].FLazarusPackages.Count - 1 do if TLazarusPackage(Items[I].FLazarusPackages.Items[J]).IsInstallable then Inc(Result); end; function TSerializablePackages.GetItem(const AIndex: Integer): TMetaPackage; begin if AIndex > FMetaPackages.Count - 1 then Exit(nil); Result := TMetaPackage(FMetaPackages.Items[AIndex]); end; procedure TSerializablePackages.SetItem(const AIndex: Integer; const AMetaPackage: TMetaPackage); begin if AIndex > FMetaPackages.Count - 1 then Exit; FMetaPackages.Items[AIndex] := AMetaPackage; end; procedure TSerializablePackages.DoGetPackageDependencies(const APkgFileName: String; ASL: TStringList; ALevel: Integer); var LazarusPkg: TLazarusPackage; D2, D1: TPackageDependency; I, J: Integer; begin if (ALevel > 10) then Exit; LazarusPkg := FindLazarusPackage(APkgFileName); if LazarusPkg = nil then Exit; for I := 0 to LazarusPkg.Dependencies.Count - 1 do begin D1 := LazarusPkg.Dependencies[I]; J := ASL.IndexOf(APkgFileName); If J = -1 then begin D2 := TPackageDependency.Create(nil); D2.Assign(D1); ASL.AddObject(D2.PkgFileName, D2); end else begin D2 := ASL.Objects[J] as TPackageDependency; if D1.MinVersion.Compare(D2.MinVersion) > 0 then D2.MinVersion.Assign(D1.MinVersion); end; if (ALevel >= 0) and (J = -1) Then DoGetPackageDependencies(D2.PkgFileName, ASL, ALevel + 1); end; end; function TSerializablePackages.AddMetaPackage(const AName: String): TMetaPackage; var MetaPackage: TMetaPackage; begin MetaPackage := FindMetaPackage(AName, fpbPackageName); if MetaPackage <> nil then begin FLastError := rsMainFrm_PackageNameAlreadyExists; Exit(nil); end; Result := TMetaPackage(FMetaPackages.Add); Result.FLazarusPackages := TCollection.Create(TLazarusPackage); Result.Name := AName; end; procedure TSerializablePackages.DeletePackage(const AIndex: Integer); begin if AIndex > FMetaPackages.Count - 1 then Exit; FMetaPackages.Delete(AIndex); end; function TSerializablePackages.AddPackageFromJSON(JSON: TJSONStringType): Boolean; var Data: TJSONData; Parser: TJSONParser; I: Integer; MetaPackage: TMetaPackage; begin if Trim(JSON) = '' then Exit(False); Result := True; Parser := TJSONParser.Create(JSON){%H-}; try Data := Parser.Parse; try MetaPackage := nil; try if Data.JSONType = jtObject then begin for I := 0 to Data.Count - 1 do begin if Data.Items[I].JSONType = jtObject then begin if not JSONToPackageData(Data.Items[I], MetaPackage) then Result := False; end else if Data.Items[I].JSONType = jtArray then begin if not JSONToLazarusPackages(Data.Items[I], MetaPackage) then Result := False; end; end; end; except Result := False; end; finally Data.Free; end; finally Parser.Free; end; end; function TSerializablePackages.FindMetaPackage(const AValue: String; const AFindPackageBy: TFindPackageBy): TMetaPackage; var I: Integer; NeedToBreak: Boolean; begin Result := nil; for I := 0 to Count - 1 do begin case AFindPackageBy of fpbPackageName: NeedToBreak := UpperCase(Items[I].Name) = UpperCase(AValue); fpbRepositoryFilename: NeedToBreak := UpperCase(Items[I].RepositoryFileName) = UpperCase(AValue) end; if NeedToBreak then begin Result := Items[I]; Break; end; end; end; function TSerializablePackages.FindMetaPackageByLazarusPackage( const ALazarusPackage: TLazarusPackage): TMetaPackage; var I, J: Integer; begin Result := nil; for I := 0 to Count - 1 do begin for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin if ALazarusPackage.Equals(TLazarusPackage(Items[I].FLazarusPackages.Items[J])) then begin Result := Items[I]; Break; end; end; end; end; function TSerializablePackages.FindPackageIndex(const AValue: String; const AFindPackageBy: TFindPackageBy): Integer; var I: Integer; NeedToBreak: Boolean; begin Result := -1; for I := 0 to Count - 1 do begin case AFindPackageBy of fpbPackageName: NeedToBreak := Items[I].Name = AValue; fpbRepositoryFilename: NeedToBreak := Items[I].RepositoryFileName = AValue end; if NeedToBreak then begin Result := I; Break; end; end; end; function TSerializablePackages.FindLazarusPackage(const APackageName: String): TLazarusPackage; var I, J: Integer; begin Result := nil; for I := 0 to Count - 1 do begin for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin if UpperCase(TLazarusPackage(Items[I].FLazarusPackages.Items[J]).Name) = UpperCase(APackageName) then begin Result := TLazarusPackage(Items[I].FLazarusPackages.Items[J]); Break; end; end; end; end; function TSerializablePackages.JSONToPackageData(const APackageData: TJSONData; var AMetaPackage: TMetaPackage): Boolean; var PackageData: TJSONObject; begin Result := True; try PackageData := TJSONObject(APackageData); AMetaPackage := TMetaPackage(FMetaPackages.Add); //need to change AMetaPackage.Name := PackageData.Get('Name'); AMetaPackage.DisplayName := PackageData.Get('DisplayName'); AMetaPackage.Category := PackageData.Get('Category'); AMetaPackage.CommunityDescription := PackageData.Get('CommunityDescription'); AMetaPackage.RepositoryFileName := PackageData.Get('RepositoryFileName'); AMetaPackage.RepositoryFileSize := PackageData.Get('RepositoryFileSize'); AMetaPackage.RepositoryFileHash := PackageData.Get('RepositoryFileHash'); AMetaPackage.RepositoryDate := VarToDateTime(PackageData.Get('RepositoryDate')); AMetaPackage.PackageBaseDir := PackageData.Get('PackageBaseDir'); if AMetaPackage.PackageBaseDir <> '' then AMetaPackage.PackageBaseDir := StringReplace(AMetaPackage.PackageBaseDir, '\/', PathDelim, [rfReplaceAll]);; AMetaPackage.HomePageURL := PackageData.Get('HomePageURL'); AMetaPackage.DownloadURL := PackageData.Get('DownloadURL'); AMetaPackage.SVNURL := PackageData.Get('SVNURL'); except on E: Exception do begin Result := False; FlastError := '"' + AMetaPackage.Name + '": ' + E.Message; end; end; end; function TSerializablePackages.JSONToLazarusPackages(const APackageData: TJSONData; var AMetaPackage: TMetaPackage): Boolean; var LazarusPkgsArr: TJSONArray; LazarusPkgsObj: TJSONObject; LazarusPkg: TLazarusPackage; I: Integer; begin Result := True; try LazarusPkgsArr := TJSONArray(APackageData); AMetaPackage.LazarusPackages := TCollection.Create(TLazarusPackage); for I := 0 to LazarusPkgsArr.Count - 1 do begin if LazarusPkgsArr.Items[I].JSONType = jtObject then begin LazarusPkgsObj := TJSONObject(LazarusPkgsArr.Items[I]); LazarusPkg := TLazarusPackage(AMetaPackage.LazarusPackages.Add); //need to change LazarusPkg.Name := LazarusPkgsObj.Get('Name'); LazarusPkg.Description := LazarusPkgsObj.Get('Description'); LazarusPkg.Author := LazarusPkgsObj.Get('Author'); LazarusPkg.License := LazarusPkgsObj.Get('License'); LazarusPkg.PackageRelativePath := LazarusPkgsObj.Get('RelativeFilePath'); if LazarusPkg.PackageRelativePath <> '' then LazarusPkg.PackageRelativePath := StringReplace(LazarusPkg.PackageRelativePath, '\/', PathDelim, [rfReplaceAll]); LazarusPkg.VersionAsString := LazarusPkgsObj.Get('VersionAsString'); LazarusPkg.LazCompatibility := LazarusPkgsObj.Get('LazCompatibility'); LazarusPkg.FPCCompatibility := LazarusPkgsObj.Get('FPCCompatibility'); LazarusPkg.SupportedWidgetSet := LazarusPkgsObj.Get('SupportedWidgetSet'); LazarusPkg.PackageType := TLazPackageType(LazarusPkgsObj.Get('PackageType')); {the package type wasn't changed in the packagelist.json to preserve compatibility with older versions, we need to convert from old to new Old --> TPackageType = (ptRunAndDesignTime, ptDesignTime, ptRunTime, ptRunTimeOnly); New --> TLazPackageType = (lptRunTime, lptDesignTime, lptRunAndDesignTime, lptRunTimeOnly);} case Ord(LazarusPkg.PackageType) of 0: LazarusPkg.PackageType := lptRunAndDesignTime; 1: LazarusPkg.PackageType := lptDesignTime; 2: LazarusPkg.PackageType := lptRunTime; 3: LazarusPkg.PackageType := lptRunTimeOnly; end; LazarusPkg.DependenciesAsString := LazarusPkgsObj.Get('DependenciesAsString'); end; end; except on E: Exception do begin Result := False; FlastError := '"' + LazarusPkg.Name + '": ' + E.Message; end; end; end; function TSerializablePackages.JSONToPackages(JSON: TJSONStringType): Boolean; var Data: TJSONData; Parser: TJSONParser; I: Integer; MetaPackage: TMetaPackage; begin Clear; if Trim(JSON) = '' then Exit(False); Result := True; Parser := TJSONParser.Create(JSON){%H-}; try Data := Parser.Parse; try MetaPackage := nil; try if Data.JSONType = jtObject then begin for I := 0 to Data.Count - 1 do begin if Assigned(FOnProcessJSON) then FOnProcessJSON(Self); if Data.Items[I].JSONType = jtObject then begin if not JSONToPackageData(Data.Items[I], MetaPackage) then Result := False; end else if Data.Items[I].JSONType = jtArray then begin if not JSONToLazarusPackages(Data.Items[I], MetaPackage) then Result := False; end; end; if Result then GetPackageStates; end; except Result := False; end; finally Data.Free; end; finally Parser.Free; end; if Result then if Assigned(FOnUpdatePackageLinks) then FOnUpdatePackageLinks(Self); end; function TSerializablePackages.LazarusPackagesToJSON(AMetaPackage: TMetaPackage; var ALazarusPkgsArr: TJSONArray): Boolean; var LazarusPkg: TLazarusPackage; LazarusPkgObj: TJSONObject; I: Integer; RelPath: String; begin Result := True; try ALazarusPkgsArr := TJSONArray.Create; for I := 0 to AMetaPackage.FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(AMetaPackage.FLazarusPackages.Items[I]); LazarusPkgObj := TJSONObject.Create; //need to change LazarusPkgObj.Add('Name', LazarusPkg.Name); LazarusPkgObj.Add('Description', LazarusPkg.Description); LazarusPkgObj.Add('Author', LazarusPkg.Author); LazarusPkgObj.Add('License', LazarusPkg.License); RelPath := LazarusPkg.PackageRelativePath; if Trim(RelPath) <> '' then begin RelPath := AppendPathDelim(RelPath); RelPath := StringReplace(RelPath, PathDelim, '\/', [rfReplaceAll]); end; LazarusPkgObj.Add('RelativeFilePath', RelPath); LazarusPkgObj.Add('VersionAsString', LazarusPkg.VersionAsString); LazarusPkgObj.Add('LazCompatibility', LazarusPkg.LazCompatibility); LazarusPkgObj.Add('FPCCompatibility', LazarusPkg.FPCCompatibility); LazarusPkgObj.Add('SupportedWidgetSet', LazarusPkg.SupportedWidgetSet); {the package type wasn't changed in the packagelist.json to preserve compatibility with older versions, we need to convert from new to old New --> TLazPackageType = (lptRunTime, lptDesignTime, lptRunAndDesignTime, lptRunTimeOnly); Old --> TPackageType = (ptRunAndDesignTime, ptDesignTime, ptRunTime, ptRunTimeOnly);} case Ord(LazarusPkg.PackageType) of 0: LazarusPkg.PackageType := lptRunAndDesignTime; 1: LazarusPkg.PackageType := lptDesignTime; 2: LazarusPkg.PackageType := lptRunTime; 3: LazarusPkg.PackageType := lptRunTimeOnly; end; LazarusPkgObj.Add('PackageType', Ord(LazarusPkg.PackageType)); LazarusPkgObj.Add('DependenciesAsString', LazarusPkg.DependenciesAsString); ALazarusPkgsArr.Add(LazarusPkgObj); end; except on E: Exception do begin Result := False; FlastError := '"' + LazarusPkg.Name + '": ' + E.Message; end; end; end; function TSerializablePackages.IsPackageDownloaded(const AMetaPackage: TMetaPackage): Boolean; var FileName: String; begin FileName := Options.LocalRepositoryArchiveExpanded + AMetaPackage.RepositoryFileName; Result := (FileExists(FileName)) and // (MD5Print(MD5File(FileName)) = AMetaPackage.RepositoryFileHash) and (FileUtil.FileSize(FileName) = AMetaPackage.RepositoryFileSize); end; function TSerializablePackages.IsPackageExtracted(const AMetaPackage: TMetaPackage): Boolean; var I: Integer; LazarusPkg: TLazarusPackage; begin Result := True; for I := 0 to AMetaPackage.FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(AMetaPackage.FLazarusPackages.Items[I]); LazarusPkg.FPackageAbsolutePath := Options.LocalRepositoryPackagesExpanded + AMetaPackage.PackageBaseDir + LazarusPkg.FPackageRelativePath + LazarusPkg.Name; if not FileExists(LazarusPkg.FPackageAbsolutePath) then begin Result := False; Break; end; end; end; function TSerializablePackages.GetPackageVersion(const APath: String): String; function VersionBound(const AVersion: Integer): Integer; begin if AVersion > 9999 then Result := 9999 else if AVersion < 0 then Result := 0 else Result := AVersion; end; function GetVersion(const AXMLConfig: TXMLConfig; const APath: String): String; var Major, Minor, Release, Build: Integer; begin Major := VersionBound(AXMLConfig.GetValue(APath + '/Major', 0)); Minor := VersionBound(AXMLConfig.GetValue(APath + '/Minor', 0)); Release := VersionBound(AXMLConfig.GetValue(APath + '/Release', 0)); Build := VersionBound(AXMLConfig.GetValue(APath + '/Build', 0)); Result := IntToStr(Major) + '.' + IntToStr(Minor) + '.' + IntToStr(Release) + '.' + IntToStr(Build); end; var XMLConfig: TXMLConfig; begin Result := '-'; XMLConfig := TXMLConfig.Create(APath); try Result := GetVersion(XMLConfig, 'Package/Version'); finally XMLConfig.Free; end; end; function TSerializablePackages.GetPackageDescription(const APath: String): String; var XMLConfig: TXMLConfig; begin Result := ''; XMLConfig := TXMLConfig.Create(APath); try Result := XMLConfig.GetValue('Package/Description/Value', ''); finally XMLConfig.Free; end; end; function TSerializablePackages.GetPackageLicense(const APath: String): String; var XMLConfig: TXMLConfig; begin Result := ''; XMLConfig := TXMLConfig.Create(APath); try Result := XMLConfig.GetValue('Package/License/Value', ''); finally XMLConfig.Free; end; end; function TSerializablePackages.IsPackageInstalled(const ALazarusPkg: TLazarusPackage; const APackageBaseDir: String): Boolean; function CheckIDEPackages: Boolean; var IDEPkg: TIDEPackage; PkgExt: String; PkgName: String; begin Result := False; PkgExt := ExtractFileExt(ALazarusPkg.Name); PkgName := StringReplace(ALazarusPkg.Name, PkgExt, '', [rfIgnoreCase]); IDEPkg := PackageEditingInterface.IsPackageInstalled(PkgName); if IDEPkg <> nil then begin ALazarusPkg.InstalledFileName := IDEPkg.Filename; ALazarusPkg.InstalledFileVersion := IntToStr(IDEPkg.Version.Major) + '.' + IntToStr(IDEPkg.Version.Minor) + '.' + IntToStr(IDEPkg.Version.Release) + '.' + IntToStr(IDEPkg.Version.Build); if FileExists(ALazarusPkg.InstalledFileName) then begin ALazarusPkg.InstalledFileDescription := GetPackageDescription(IDEPkg.Filename); ALazarusPkg.InstalledFileLincese := GetPackageLicense(IDEPkg.Filename); end; Result := True; end; end; var FileName, RepoPath: String; begin Result := False; case ALazarusPkg.PackageType of lptRunTime, lptRunTimeOnly: begin FileName := StringReplace(ALazarusPkg.Name, '.lpk', '.opkman', [rfIgnoreCase]); RepoPath := Options.LocalRepositoryPackagesExpanded + APackageBaseDir + ALazarusPkg.PackageRelativePath; Result := (psExtracted in ALazarusPkg.PackageStates) and FileExists(RepoPath + FileName); if Result then begin ALazarusPkg.InstalledFileName := RepoPath + ALazarusPkg.Name; if FileExists(ALazarusPkg.InstalledFileName) then begin ALazarusPkg.InstalledFileVersion := GetPackageVersion(ALazarusPkg.InstalledFileName); ALazarusPkg.InstalledFileDescription := GetPackageDescription(ALazarusPkg.InstalledFileName); ALazarusPkg.InstalledFileLincese := GetPackageLicense(ALazarusPkg.InstalledFileName); end; end else Result := CheckIDEPackages end; lptDesignTime, lptRunAndDesignTime: begin Result := CheckIDEPackages end; end; end; function TSerializablePackages.GetPackageInstallState(const AMetaPackage: TMetaPackage): Integer; var I: Integer; LazarusPkg: TLazarusPackage; InstCnt: Integer; begin InstCnt := 0; for I := 0 to AMetaPackage.LazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(AMetaPackage.LazarusPackages.Items[I]); if IsPackageInstalled(LazarusPkg, AMetaPackage.PackageBaseDir) then Inc(InstCnt); end; case InstCnt of 0: Result := 0; 1..High(Integer): if InstCnt < AMetaPackage.LazarusPackages.Count then Result := 2 else Result := 1; end; end; function TSerializablePackages.PackageDataToJSON(AMetaPackage: TMetaPackage; var APackageData: TJSONObject): Boolean; var PackageBaseDir: String; begin //need to change Result := True; try APackageData := TJSONObject.Create; APackageData.Add('Name', AMetaPackage.Name); APackageData.Add('DisplayName', AMetaPackage.DisplayName); APackageData.Add('Category', AMetaPackage.Category); APackageData.Add('CommunityDescription', AMetaPackage.CommunityDescription); APackageData.Add('RepositoryFileName', AMetaPackage.RepositoryFileName); APackageData.Add('RepositoryFileSize', AMetaPackage.RepositoryFileSize); APackageData.Add('RepositoryFileHash', AMetaPackage.RepositoryFileHash); APackageData.Add('RepositoryDate', AMetaPackage.RepositoryDate); PackageBaseDir := AMetaPackage.PackageBaseDir; if Trim(PackageBaseDir) <> '' then begin PackageBaseDir := AppendPathDelim(PackageBaseDir); PackageBaseDir := StringReplace(PackageBaseDir, PathDelim, '\/', [rfReplaceAll]); end; APackageData.Add('PackageBaseDir', PackageBaseDir); APackageData.Add('HomePageURL', AMetaPackage.HomePageURL); APackageData.Add('DownloadURL', AMetaPackage.DownloadURL); APackageData.Add('SVNURL', AMetaPackage.SVNURL); except on E: Exception do begin Result := False; FlastError := '"' + AMetaPackage.Name + '": ' + E.Message; end; end; end; function TSerializablePackages.PackagesToJSON(var JSON: TJSONStringType): Boolean; var PackageObject: TJSONObject; PackageData: TJSONObject; LazarusPkgsArr: TJSONArray; I: Integer; MetaPackage: TMetaPackage; begin Result := True; PackageObject := TJSONObject.Create; try LazarusPkgsArr := nil; PackageData := nil; try for I := 0 to FMetaPackages.Count - 1 do begin MetaPackage := TMetaPackage(FMetaPackages.Items[I]); if not LazarusPackagesToJSON(MetaPackage, LazarusPkgsArr) then Result := False; if not PackageDataToJSON(MetaPackage, PackageData) then Result := False; PackageObject.Add('PackageData' + IntToStr(I), PackageData); PackageObject.Add('PackageFiles' + IntToStr(I), LazarusPkgsArr); end; if Result then JSON := PackageObject.FormatJSON(DefaultFormat, DefaultIndentSize); except Result := False; end; finally PackageObject.Free; end; end; procedure TSerializablePackages.GetPackageDependencies(const APkgFileName: String; List: TObjectList; Recurse, OnlyUnresolved: Boolean); var SL: TStringList; I, J: Integer; PackageName: String; Installed: Boolean; IDEPackage: TIDEPackage; LazarusPkg: TLazarusPackage; begin SL := TStringList.Create; try SL.Sorted := True; DoGetPackageDependencies(APkgFileName, SL, Ord(Recurse) - 1); if OnlyUnresolved then begin for I := SL.Count - 1 downto 0 do begin PackageName := TPackageDependency(SL.Objects[I]).PkgFileName + '.lpk'; Installed := False; for J := 0 to PackageEditingInterface.GetPackageCount - 1 do begin IDEPackage := PackageEditingInterface.GetPackages(J); if UpperCase(ExtractFileName(IDEPackage.Filename)) = UpperCase(PackageName) then begin LazarusPkg := FindLazarusPackage(PackageName); if LazarusPkg <> nil then Installed := IsInstalledVersionOk(TPackageDependency(SL.Objects[I]), LazarusPkg.InstalledFileVersion) else Installed := True; Break; end; end; if Installed then SL.Objects[I].Free else List.Add(SL.Objects[I]) end; end else for I := 0 to SL.Count - 1 do List.Add(SL.Objects[I]); finally SL.Free; end; end; procedure TSerializablePackages.GetPackageStates; var I, J: Integer; LazarusPkg: TLazarusPackage; begin for I := 0 to Count - 1 do begin Items[I].FPackageState := psRepository; Items[I].ChangePackageStates(ctAdd, psRepository); if IsPackageDownloaded(Items[I]) then Items[I].ChangePackageStates(ctAdd, psDownloaded) else Items[I].ChangePackageStates(ctRemove, psDownloaded); if IsPackageExtracted(Items[I]) then Items[I].ChangePackageStates(ctAdd, psExtracted) else Items[I].ChangePackageStates(ctRemove, psExtracted); for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(Items[I].FLazarusPackages.Items[J]); if IsPackageInstalled(LazarusPkg, Items[I].PackageBaseDir) then begin LazarusPkg.PackageStates := LazarusPkg.PackageStates + [psInstalled]; LazarusPkg.PackageState := psInstalled; end else LazarusPkg.PackageStates := LazarusPkg.PackageStates - [psInstalled]; end; end; end; procedure TSerializablePackages.RemoveErrorState; var I, J: Integer; LazarusPkg: TLazarusPackage; begin for I := 0 to Count - 1 do begin if psError in Items[I].PackageStates then Items[I].ChangePackageStates(ctRemove, psError); for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(Items[I].FLazarusPackages.Items[J]); if psError in LazarusPkg.PackageStates then LazarusPkg.PackageStates := LazarusPkg.PackageStates - [psError]; end; end; end; procedure TSerializablePackages.RemoveCheck; var I, J: Integer; MetaPkg: TMetaPackage; LazarusPkg: TLazarusPackage; begin for I := 0 to Count - 1 do begin MetaPkg := TMetaPackage(Items[I]); MetaPkg.Checked := False; for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(Items[I].FLazarusPackages.Items[J]); LazarusPkg.Checked := False; end; end; end; procedure TSerializablePackages.MarkRuntimePackages; var I, J: Integer; FileName: String; LazarusPkg: TLazarusPackage; begin for I := 0 to Count - 1 do begin for J := 0 to Items[I].FLazarusPackages.Count - 1 do begin LazarusPkg := TLazarusPackage(Items[I].FLazarusPackages.Items[J]); if (LazarusPkg.Checked) and (psInstalled in LazarusPkg.PackageStates) and (not (psError in LazarusPkg.PackageStates)) and (LazarusPkg.PackageType in [lptRunTime, lptRunTimeOnly]) then begin FileName := StringReplace(LazarusPkg.Name, '.lpk', '.opkman', [rfIgnoreCase]); FileCreate(Options.LocalRepositoryPackagesExpanded + Items[I].PackageBaseDir + LazarusPkg.PackageRelativePath + FileName); end; end; end; end; function TSerializablePackages.AtLeastOneLazPkgInstalled(const AMetaPackage: TMetaPackage): Boolean; var I: Integer; begin Result := False; for I := 0 to AMetaPackage.LazarusPackages.Count - 1 do begin if IsPackageInstalled(TLazarusPackage(AMetaPackage.FLazarusPackages.Items[I]), AMetaPackage.PackageBaseDir) then begin Result := True; Break; end; end; end; function TSerializablePackages.Cleanup: Integer; var I: Integer; AlreadyCounted: Boolean; begin Result := 0; for I := 0 to Count - 1 do begin if not AtLeastOneLazPkgInstalled(Items[I]) then begin AlreadyCounted := False; if IsPackageDownloaded(Items[I]) then begin if DeleteFile(Options.LocalRepositoryArchiveExpanded + Items[I].RepositoryFileName) then begin Inc(Result); AlreadyCounted := True; end; end; if IsPackageExtracted(Items[I]) then begin if DirectoryExists(Options.LocalRepositoryPackagesExpanded + Items[I].PackageBaseDir) then begin DeleteDirectory(Options.LocalRepositoryPackagesExpanded + Items[I].PackageBaseDir, False); if not AlreadyCounted then Inc(Result); end; end; end; end; end; procedure TSerializablePackages.DeleteDownloadedZipFiles; var I: Integer; begin for I := 0 to Count - 1 do begin case PackageAction of paInstall: begin if IsPackageDownloaded(Items[I]) then DeleteFile(Options.LocalRepositoryArchiveExpanded + Items[I].RepositoryFileName) end; paUpdate: begin if FileExists(Options.LocalRepositoryUpdateExpanded + Items[I].RepositoryFileName) then DeleteFile(Options.LocalRepositoryUpdateExpanded + Items[I].RepositoryFileName) end; end; end; end; function SortByNameAsc(Item1, Item2: TCollectionItem): Integer; var Package1, Package2: TMetaPackage; begin Package1 := TMetaPackage(Item1); Package2 := TMetaPackage(Item2); Result := CompareText(Package1.FDisplayName, Package2.FDisplayName); end; function SortByNameDsc(Item1, Item2: TCollectionItem): Integer; var Package1, Package2: TMetaPackage; begin Package1 := TMetaPackage(Item1); Package2 := TMetaPackage(Item2); Result := CompareText(Package2.FDisplayName, Package1.FDisplayName); end; function SortByDateAsc(Item1, Item2: TCollectionItem): Integer; var Package1, Package2: TMetaPackage; begin Package1 := TMetaPackage(Item1); Package2 := TMetaPackage(Item2); Result := CompareDateTime(Package1.RepositoryDate, Package2.RepositoryDate); end; function SortByDateDsc(Item1, Item2: TCollectionItem): Integer; var Package1, Package2: TMetaPackage; begin Package1 := TMetaPackage(Item1); Package2 := TMetaPackage(Item2); Result := CompareDateTime(Package2.RepositoryDate, Package1.RepositoryDate); end; procedure TSerializablePackages.Sort(const ASortType: TSortType; const ASortOrder: TSortOrder); begin case ASortType of stName: if ASortOrder = soAscendent then FMetaPackages.Sort(@SortByNameAsc) else if ASortOrder = soDescendent then FMetaPackages.Sort(@SortByNameDsc); stDate: if ASortOrder = soAscendent then FMetaPackages.Sort(@SortByDateAsc) else if ASortOrder = soDescendent then FMetaPackages.Sort(@SortByDateDsc) end; end; function TSerializablePackages.QuickStatistics: String; var I, J: Integer; LazPackCnt: Integer; TotSize: Int64; begin LazPackCnt := 0; TotSize := 0; for I := 0 to Count - 1 do begin TotSize := TotSize + Items[I].RepositoryFileSize; for J := 0 to Items[I].FLazarusPackages.Count - 1 do Inc(LazPackCnt); end; Result := Format(rsPackagesFound, [IntToStr(SerializablePackages.Count), IntToStr(LazPackCnt), FormatSize(TotSize)]); end; function TSerializablePackages.IsDependencyOk(PackageDependency: TPackageDependency; DependencyPackage: TLazarusPackage): Boolean; var MinVerOk: Boolean; MaxVerOk: Boolean; begin if PackageDependency.MinVersion.IsNullVersion then MinVerOk := True else MinVerOk := PackageDependency.MinVersion.Compare(DependencyPackage.Version) <= 0; if PackageDependency.MaxVersion.IsNullVersion then MaxVerOk := True else MaxVerOk := PackageDependency.MaxVersion.Compare(DependencyPackage.Version) >= 0; Result := (MinVerOk) and (MaxVerOk) end; function TSerializablePackages.IsInstalledVersionOk(PackageDependency: TPackageDependency; InstalledVersion: String): Boolean; var MinVerOk: Boolean; MaxVerOk: Boolean; begin if PackageDependency.MinVersion.IsNullVersion then MinVerOk := True else MinVerOk := PackageDependency.MinVersion.AsString <= InstalledVersion; if PackageDependency.MaxVersion.IsNullVersion then MaxVerOk := True else MaxVerOk := PackageDependency.MaxVersion.AsString >= InstalledVersion; Result := (MinVerOk) and (MaxVerOk) end; end.