{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: PackageUtils.pas, released on 2004-03-29. The Initial Developer of the Original Code is Andreas Hausladen (Andreas dott Hausladen att gmx dott de) Portions created by Andreas Hausladen are Copyright (C) 2004 Andreas Hausladen. All Rights Reserved. Contributor(s): - You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Known Issues: -----------------------------------------------------------------------------} // $Id: PackageUtils.pas 10610 2006-05-19 13:35:08Z elahn $ unit PackageUtils; {$I jvcl.inc} interface uses SysUtils, Classes, Contnrs, JvSimpleXml, Utils, DelphiData, Intf, GenerateUtils, PackageInformation; type TPackageTarget = class; TProjectGroup = class; TPackageGroupArray = array[{Personal:}Boolean, {Kind:}TPackageGroupKind] of TProjectGroup; /// /// TFrameworks contains all possible package lists for the target. If /// Items[x] is nil then there is no .bpg file for this target kind. /// TFrameworks = class(TObject) private FItems: TPackageGroupArray; FTargetConfig: ITargetConfig; function GetCount: Integer; function GetItem(Personal: Boolean; Kind: TPackageGroupKind): TProjectGroup; public constructor Create(ATargetConfig: ITargetConfig); destructor Destroy; override; property Items[Personal: Boolean; Kind: TPackageGroupKind] : TProjectGroup read GetItem; property Count: Integer read GetCount; property TargetConfig: ITargetConfig read FTargetConfig; end; /// /// TPackageTarget contains a .bpl target and the .xml file in the /// Info property. This class is used to specify if the package should be /// compiled and/or installed. But it does not perform these actions itself. /// TPackageTarget = class(TBpgPackageTarget) private FLockInstallChange: Integer; FJvDependencies: TStringList; // Strings[]: "JvXxxx-"[D|R] | "JvQXxxx-"[D|R] // Objects[]: TRequiredPackage FJclDependencies: TStringList; // Strings[]: "JvXxxx-"[D|R] | "JvQXxxx-"[D|R] // Objects[]: TRequiredPackage FCompile: Boolean; FInstall: Boolean; function GetDcpName: string; procedure SetCompile(Value: Boolean); procedure SetInstall(const Value: Boolean); function GetJclDependenciesReqPkg(Index: Integer): TRequiredPackage; function GetJvDependenciesReqPkg(Index: Integer): TRequiredPackage; function GetOwner: TProjectGroup; protected procedure GetDependencies; override; // is called after alle package targets are created public constructor Create(AOwner: TPackageGroup; const ATargetName, ASourceName: string); override; destructor Destroy; override; function FindRuntimePackage: TPackageTarget; property JvDependencies: TStringList read FJvDependencies; property JvDependenciesReqPkg[Index: Integer]: TRequiredPackage read GetJvDependenciesReqPkg; property JclDependencies: TStringList read FJclDependencies; property JclDependenciesReqPkg[Index: Integer]: TRequiredPackage read GetJclDependenciesReqPkg; property Compile: Boolean read FCompile write SetCompile; property Install: Boolean read FInstall write SetInstall; property DcpName: string read GetDcpName; property Owner: TProjectGroup read GetOwner; end; /// /// TProjectGroup contains the data from a .bpg (Borland Package Group) file. /// TProjectGroup = class(TPackageGroup) private FTargetConfig: ITargetConfig; FOnCompileChange: TNotifyEvent; function GetPackages(Index: Integer): TPackageTarget; function GetTarget: TCompileTarget; protected function GetIsVCLX: Boolean; override; procedure DoInstallChange; virtual; function GetPackageTargetClass: TBpgPackageTargetClass; override; public constructor Create(ATargetConfig: ITargetConfig; const AFilename: string); function GetBplNameOf(Package: TRequiredPackage): string; override; function FindPackageByXmlName(const XmlName: string): TPackageTarget; { FindPackageByXmlName returns the TPackageTarget object that contains the specified .xml file. } property Packages[Index: Integer]: TPackageTarget read GetPackages; default; property TargetConfig: ITargetConfig read FTargetConfig; property Target: TCompileTarget read GetTarget; property OnCompileChange: TNotifyEvent read FOnCompileChange; end; implementation function BplNameToGenericName(const BplName: string): string; var I, Len : Integer; begin // obtain package name used in the xml file Result := ChangeFileExt(BplName, ''); // Remove numbers from the end of the package name Len := Length(Result); I := Len-1; while (I > 0) and (Result[I] in ['0'..'9']) do Dec(I); Delete(Result, I+1, Len-I-1); // Replace the environment character by a dash Result[Length(Result) - 1] := '-'; if Result[3] = 'Q' then Delete(Result, 3, 1); end; { TFrameworks } constructor TFrameworks.Create(ATargetConfig: ITargetConfig); var Kind: TPackageGroupKind; begin inherited Create; FTargetConfig := ATargetConfig; for Kind := pkFirst to pkLast do begin { Delphi 5 and the Personal Editions do not have CLX support. } if (Kind = pkClx) and ((TargetConfig.Target.Version < 6) or (TargetConfig.Target.IsPersonal)) then Continue; if FileExists(TargetConfig.GetBpgFilename(False, Kind)) then FItems[False, Kind] := TProjectGroup.Create(TargetConfig, TargetConfig.GetBpgFilename(False, Kind)); if FileExists(TargetConfig.GetBpgFilename(True, Kind)) then FItems[True, Kind] := TProjectGroup.Create(TargetConfig, TargetConfig.GetBpgFilename(True, Kind)); end; end; destructor TFrameworks.Destroy; var Kind: TPackageGroupKind; begin for Kind := pkFirst to pkLast do begin FItems[False, Kind].Free; FItems[True, Kind].Free; end; inherited Destroy; end; function TFrameworks.GetCount: Integer; begin Result := Length(FItems); end; function TFrameworks.GetItem(Personal: Boolean; Kind: TPackageGroupKind): TProjectGroup; begin Result := FItems[Personal, Kind]; end; { TProjectGroup } constructor TProjectGroup.Create(ATargetConfig: ITargetConfig; const AFilename: string); begin FTargetConfig := ATargetConfig; inherited Create(AFilename, ATargetConfig.JVCLPackagesXmlDir, ATargetConfig.TargetSymbol); end; procedure TProjectGroup.DoInstallChange; begin if Assigned(FOnCompileChange) then FOnCompileChange(Self); end; function TProjectGroup.FindPackageByXmlName(const XmlName: string): TPackageTarget; begin Result := TPackageTarget(inherited FindPackageByXmlName(XmlName)); end; function TProjectGroup.GetBplNameOf(Package: TRequiredPackage): string; begin if StartsWith(Package.Name, 'Jv', True) then Result := inherited GetBplNameOf(Package) else Result := Package.Name; end; function TProjectGroup.GetIsVCLX: Boolean; begin Result := Pos('clx', LowerCase(BpgName)) > 0; end; function TProjectGroup.GetPackages(Index: Integer): TPackageTarget; begin Result := TPackageTarget(inherited Packages[Index]); end; function TProjectGroup.GetPackageTargetClass: TBpgPackageTargetClass; begin Result := TPackageTarget; end; function TProjectGroup.GetTarget: TCompileTarget; begin Result := TargetConfig.Target; end; function SortProc_PackageTarget(Item1, Item2: Pointer): Integer; var p1, p2: TPackageTarget; begin p1 := Item1; p2 := Item2; Result := CompareText(p1.Info.DisplayName, p2.Info.DisplayName); if Result = 0 then begin if ProjectTypeIsDesign(p1.Info.ProjectType) and not ProjectTypeIsDesign(p2.Info.ProjectType) then Result := 1 else if not ProjectTypeIsDesign(p1.Info.ProjectType) and ProjectTypeIsDesign(p2.Info.ProjectType) then Result := -1; end; end; { TPackageTarget } constructor TPackageTarget.Create(AOwner: TPackageGroup; const ATargetName, ASourceName: string); begin inherited Create(AOwner, ATargetName, ASourceName); FJvDependencies := TStringList.Create; FJvDependencies.Sorted := True; FJclDependencies := TStringList.Create; FJclDependencies.Sorted := True; FCompile := True; end; destructor TPackageTarget.Destroy; begin FJvDependencies.Free; FJclDependencies.Free; inherited Destroy; end; /// /// GetDependencies obtains the JVCL (JvXxx) and JCL ([D|C]JCLxx) dependencies /// from the PackageInfo data. Only the JvXxx packages that are for this target /// are added to the JvDependencies list. And only the [D|C]JCLxxx packages are /// added to the JclDependencies list that are for this target. All items in /// JvDependencies are physical files and are a valid JVCL target. All items in /// JclDependencies must not be physical files. /// function TPackageTarget.FindRuntimePackage: TPackageTarget; begin Result := TPackageTarget(inherited FindRuntimePackage); end; function TPackageTarget.GetDcpName: string; begin Result := ChangeFileExt(ExtractFileName(SourceName), '.dcp'); end; procedure TPackageTarget.GetDependencies; var i: Integer; begin FJvDependencies.Clear; for i := 0 to Info.RequireCount - 1 do begin // JVCL dependencies if StartsWith(Info.Requires[i].Name, 'Jv', True) then // do not localize begin if FileExists(Info.XmlDir + '\' + Info.Requires[i].Name + '.xml') and // do not localize (Owner.FindPackagebyXmlName(Info.Requires[i].Name) <> nil) and Info.Requires[i].IsRequiredByTarget(Owner.TargetSymbol) then begin FJvDependencies.AddObject(Info.Requires[i].Name, Info.Requires[i]); end; end else // is it a JCL dependency if StartsWith(Info.Requires[i].Name, 'Jcl', True) or // do not localize StartsWith(Info.Requires[i].Name, 'JclD', True) or // do not localize StartsWith(Info.Requires[i].Name, 'JclC', True) then // do not localize begin if Info.Requires[i].IsRequiredByTarget(Owner.TargetSymbol) then FJclDependencies.AddObject(Info.Requires[i].Name, Info.Requires[i]); end; end; end; function TPackageTarget.GetJclDependenciesReqPkg(Index: Integer): TRequiredPackage; begin Result := TRequiredPackage(JclDependencies.Objects[Index]); end; function TPackageTarget.GetJvDependenciesReqPkg(Index: Integer): TRequiredPackage; begin Result := TRequiredPackage(JvDependencies.Objects[Index]); end; function TPackageTarget.GetOwner: TProjectGroup; begin Result := TProjectGroup(inherited Owner); end; procedure TPackageTarget.SetCompile(Value: Boolean); var i: Integer; Pkg: TPackageTarget; begin if Value <> FCompile then begin FCompile := Value; if not FCompile then FInstall := False; Inc(FLockInstallChange); try if FCompile then begin // activate packages on which this package depend on for i := 0 to JvDependencies.Count - 1 do begin Pkg := Owner.FindPackagebyXmlName(JvDependencies[i]); if Pkg <> nil then Pkg.SetCompile(True); end; end else begin // deactivate all packages which depend on this package for i := 0 to Owner.Count - 1 do begin Pkg := Owner.Packages[i]; if Pkg <> Self then begin if Pkg.JvDependencies.IndexOf(Info.Name) <> -1 then Pkg.Compile := False; end; end; end; finally Dec(FLockInstallChange); end; if FLockInstallChange = 0 then Owner.DoInstallChange; end; end; procedure TPackageTarget.SetInstall(const Value: Boolean); begin if ProjectTypeIsDesign(Info.ProjectType) then FInstall := Value else FInstall := False; // runtime packages are not installable. if Value then Compile := True; end; initialization BplNameToGenericNameHook := BplNameToGenericName; ExpandPackageTargets := ExpandTargets; end.