diff --git a/ide/diskdiffsdialog.pas b/ide/diskdiffsdialog.pas index adbe61522c..41d495b957 100644 --- a/ide/diskdiffsdialog.pas +++ b/ide/diskdiffsdialog.pas @@ -291,8 +291,14 @@ begin end else if FileOwner is TLazPackage then begin // compare disk and package APackage:=TLazPackage(FileOwner); - if AltFilename<>'' then - Filename:=AltFilename + if AltFilename<>'' then begin + if CompareFilenames(AltFilename,APackage.Filename)<>0 then + Result^.Diff+=Format(lisLpkHasVanishedOnDiskUsingAsAlternative, [ + LineEnding + +AltFilename+LineEnding + +LineEnding]); + Filename:=AltFilename; + end else if APackage.LPKSource<>nil then Filename:=APackage.LPKSource.Filename else @@ -310,13 +316,13 @@ begin DiffOutput:=TDiffOutput.Create(Source,Result^.TxtOnDisk, [], nil); try - Result^.Diff:=DiffOutput.CreateTextDiff; + Result^.Diff+=DiffOutput.CreateTextDiff; finally DiffOutput.Free; end; except On E: Exception do - Result^.Diff:='\ '+Format(lisDiskDiffErrorReadingFile, [E.Message]); + Result^.Diff+='\ '+Format(lisDiskDiffErrorReadingFile, [E.Message]); end; FCachedDiffs.Add(Result); end; diff --git a/ide/lazarusidestrconsts.pas b/ide/lazarusidestrconsts.pas index 8dd5573cac..1ebb4c92d1 100644 --- a/ide/lazarusidestrconsts.pas +++ b/ide/lazarusidestrconsts.pas @@ -3677,6 +3677,8 @@ resourcestring // disk diff dialog lisDiskDiffErrorReadingFile = 'Error reading file: %s'; + lisLpkHasVanishedOnDiskUsingAsAlternative = 'lpk has vanished on disk. Using' + +' as alternative%s'; lisDiskDiffSomeFilesHaveChangedOnDisk = 'Some files have changed on disk:'; lisDiskDiffChangedFiles = 'Changed files:'; lisDiskDiffClickOnOneOfTheAboveItemsToSeeTheDiff = 'Click on one of the ' diff --git a/packager/basepkgmanager.pas b/packager/basepkgmanager.pas index 172534ce94..0b4386676e 100644 --- a/packager/basepkgmanager.pas +++ b/packager/basepkgmanager.pas @@ -1,4 +1,3 @@ -{ $Id$ } { /*************************************************************************** basepkgmanager.pas diff --git a/packager/lpkcache.pas b/packager/lpkcache.pas index 33341fea1e..bc6a202a8f 100644 --- a/packager/lpkcache.pas +++ b/packager/lpkcache.pas @@ -431,6 +431,7 @@ begin License:=''; Description:=''; PkgType:=lptRunAndDesignTime; + Version.Clear; if FilenameIsAbsolute(LPKFilename) and FileExistsUTF8(LPKFilename) then begin // load the package file try diff --git a/packager/packagelinks.pas b/packager/packagelinks.pas index c1fb98f8c6..5cac1a0a3c 100644 --- a/packager/packagelinks.pas +++ b/packager/packagelinks.pas @@ -138,7 +138,7 @@ type function FindLeftMostNode(LinkTree: TAvgLvlTree; const PkgName: string): TAvgLvlTreeNode; function FindLinkWithPkgNameInTree(LinkTree: TAvgLvlTree; - const PkgName: string): TPackageLink; + const PkgName: string; IgnoreFiles: TFilenameToStringTree): TPackageLink; function FindLinkWithDependencyInTree(LinkTree: TAvgLvlTree; Dependency: TPkgDependency; IgnoreFiles: TFilenameToStringTree): TPackageLink; function FindLinkWithPackageIDInTree(LinkTree: TAvgLvlTree; @@ -166,9 +166,12 @@ type procedure SaveUserLinks; function NeedSaveUserLinks(const ConfigFilename: string): boolean; procedure WriteLinkTree(LinkTree: TAvgLvlTree); - function FindLinkWithPkgName(const PkgName: string): TPackageLink; + function FindLinkWithPkgName(const PkgName: string; + IgnoreFiles: TFilenameToStringTree = nil; + FirstUserLinks: boolean = true): TPackageLink; function FindLinkWithDependency(Dependency: TPkgDependency; - IgnoreFiles: TFilenameToStringTree = nil): TPackageLink; + IgnoreFiles: TFilenameToStringTree = nil; + FirstUserLinks: boolean = true): TPackageLink; function FindLinkWithPackageID(APackageID: TLazPackageID): TPackageLink; procedure IteratePackages(MustExist: boolean; Event: TIteratePackagesEvent; Origins: TPkgLinkOrigins = AllPkgLinkOrigins); @@ -765,16 +768,36 @@ begin end; function TPackageLinks.FindLinkWithPkgNameInTree(LinkTree: TAvgLvlTree; - const PkgName: string): TPackageLink; + const PkgName: string; IgnoreFiles: TFilenameToStringTree): TPackageLink; // find left most link with PkgName var CurNode: TAvgLvlTreeNode; + Link: TPackageLink; begin Result:=nil; if PkgName='' then exit; CurNode:=FindLeftMostNode(LinkTree,PkgName); - if CurNode=nil then exit; - Result:=TPackageLink(CurNode.Data); + while CurNode<>nil do begin + Link:=TPackageLink(CurNode.Data); + if (CompareText(PkgName,Link.Name)=0) + and ((IgnoreFiles=nil) or (not IgnoreFiles.Contains(Link.GetEffectiveFilename))) + then begin + if Result=nil then + Result:=Link + else begin + // there are two packages fitting + if ((Link.LastUsed>Result.LastUsed) + or (Link.Version.Compare(Result.Version)>0)) + and FileExistsCached(Link.GetEffectiveFilename) then + Result:=Link; // this one is better + end; + end; + CurNode:=LinkTree.FindSuccessor(CurNode); + if CurNode=nil then break; + if CompareText(TPackageLink(CurNode.Data).Name,PkgName)<>0 + then + break; + end; end; function TPackageLinks.FindLinkWithDependencyInTree(LinkTree: TAvgLvlTree; @@ -809,10 +832,8 @@ begin CurNode:=LinkTree.FindSuccessor(CurNode); if CurNode=nil then break; if CompareText(TPackageLink(CurNode.Data).Name,Dependency.PackageName)<>0 - then begin - CurNode:=nil; + then break; - end; end; end; @@ -860,19 +881,28 @@ begin IncreaseChangeStamp; end; -function TPackageLinks.FindLinkWithPkgName(const PkgName: string): TPackageLink; +function TPackageLinks.FindLinkWithPkgName(const PkgName: string; + IgnoreFiles: TFilenameToStringTree; FirstUserLinks: boolean): TPackageLink; begin - Result:=FindLinkWithPkgNameInTree(FUserLinksSortID,PkgName); + Result:=nil; + if FirstUserLinks then + Result:=FindLinkWithPkgNameInTree(FUserLinksSortID,PkgName,IgnoreFiles); if Result=nil then - Result:=FindLinkWithPkgNameInTree(FGlobalLinks,PkgName); + Result:=FindLinkWithPkgNameInTree(FGlobalLinks,PkgName,IgnoreFiles); + if (Result=nil) and (not FirstUserLinks) then + Result:=FindLinkWithPkgNameInTree(FUserLinksSortID,PkgName,IgnoreFiles); end; function TPackageLinks.FindLinkWithDependency(Dependency: TPkgDependency; - IgnoreFiles: TFilenameToStringTree): TPackageLink; + IgnoreFiles: TFilenameToStringTree; FirstUserLinks: boolean): TPackageLink; begin - Result:=FindLinkWithDependencyInTree(FUserLinksSortID,Dependency,IgnoreFiles); + Result:=nil; + if FirstUserLinks then + Result:=FindLinkWithDependencyInTree(FUserLinksSortID,Dependency,IgnoreFiles); if Result=nil then Result:=FindLinkWithDependencyInTree(FGlobalLinks,Dependency,IgnoreFiles); + if (Result=nil) and (not FirstUserLinks) then + Result:=FindLinkWithDependencyInTree(FUserLinksSortID,Dependency,IgnoreFiles); //if Result=nil then begin //debugln('TPackageLinks.FindLinkWithDependency A ',Dependency.AsString); // WriteLinkTree(FGlobalLinks); diff --git a/packager/packagesystem.pas b/packager/packagesystem.pas index 16fff35b0d..a9c07853b1 100644 --- a/packager/packagesystem.pas +++ b/packager/packagesystem.pas @@ -4516,7 +4516,7 @@ begin continue; end else begin // lpk has vanished -> search alternative - + NewFilename:=PackageGraph.FindAlternativeLPK(APackage); end; if ListOfPackages=nil then ListOfPackages:=TStringList.Create; @@ -4976,19 +4976,115 @@ end; function TLazPackageGraph.FindAlternativeLPK(APackage: TLazPackage): string; var - Dependency: TPkgDependency; -begin - Result:=''; - // first check for preferred dependencies - Dependency:=APackage.FirstUsedByDependency; - while Dependency<>nil do begin - if (Dependency.DefaultFilename<>'') and Dependency.PreferDefaultFilename - then begin - //PreferredFilename:=Dependency.FindDefaultFilename; + IgnoreFiles: TFilenameToStringTree; - end; - Dependency:=Dependency.NextUsedByDependency; + procedure IgnoreLPK(LPKFilename: string); + begin + IgnoreFiles[LPKFilename]:='1'; end; + + function ParseLPK(var LPKFilename: string; Version: TPkgVersion): boolean; + var + Code: TCodeBuffer; + XMLConfig: TXMLConfig; + Path: String; + FileVersion: Integer; + begin + Result:=false; + LPKFilename:=TrimFilename(LPKFilename); + if IgnoreFiles[LPKFilename]='1' then exit; + IgnoreLPK(LPKFilename); + if not FilenameIsAbsolute(LPKFilename) then exit; + Code:=CodeToolBoss.LoadFile(LPKFilename,true,false); + if Code=nil then exit; + try + XMLConfig:=TXMLConfig.CreateWithSource(LPKFilename,Code.Source); + try + Path:='Package/'; + FileVersion:=XMLConfig.GetValue(Path+'Version',0); + PkgVersionLoadFromXMLConfig(Version,XMLConfig,Path+'Version/',FileVersion); + Result:=true; + finally + XMLConfig.Free; + end; + except + on E: Exception do begin + debugln(['ParseLPK "'+LPKFilename+'": '+E.Message]); + end; + end; + end; + +var + Dependency: TPkgDependency; + Version: TPkgVersion; + PkgLink: TPackageLink; + Filename: String; + BaseDir: String; +begin + Version:=TPkgVersion.Create; + IgnoreFiles:=TFilenameToStringTree.Create(false); + try + // first check for preferred filenames in dependencies + Dependency:=APackage.FirstUsedByDependency; + while Dependency<>nil do begin + if (Dependency.DefaultFilename<>'') and Dependency.PreferDefaultFilename + then begin + Result:=Dependency.FindDefaultFilename; + if ParseLPK(Result,Version) then + exit; + end; + Dependency:=Dependency.NextUsedByDependency; + end; + + // find nearest package link to old lpk + // for example + // if old was /path/to/lazarus/comp/bla.lpk + // then a /path/to/lazarus/comp/design/bla.lpk + // is better than a /path/to/other/lazarus/comp/bla.lpk + Dependency:=APackage.FirstUsedByDependency; + if Dependency<>nil then begin + Result:=''; + BaseDir:=TrimFilename(APackage.Directory); + repeat + PkgLink:=PkgLinks.FindLinkWithDependency(Dependency,IgnoreFiles); + if PkgLink=nil then break; + Filename:=PkgLink.GetEffectiveFilename; + if ParseLPK(Filename,Version) then begin + // candidate found + if (Result='') + or (length(CreateRelativePath(Filename,BaseDir))'' then exit; + end; + + // last check for default filenames in dependencies + Dependency:=APackage.FirstUsedByDependency; + while Dependency<>nil do begin + if (Dependency.DefaultFilename<>'') + and (not Dependency.PreferDefaultFilename) then + begin + Result:=Dependency.FindDefaultFilename; + if ParseLPK(Result,Version) then + exit; + end; + Dependency:=Dependency.NextUsedByDependency; + end; + + // nothing found via dependencies + // search in links + PkgLink:=PkgLinks.FindLinkWithPkgName(APackage.Name,IgnoreFiles,true); + if PkgLink<>nil then begin + Result:=PkgLink.GetEffectiveFilename; + exit; + end; + finally + IgnoreFiles.Free; + Version.Free; + end; + Result:=''; end; procedure TLazPackageGraph.OpenInstalledDependency(Dependency: TPkgDependency;