Browse Source

* split repository in InstalledRepository and AvailableRepository
* replace CurrentPackage by PackageName
* remove obsolete execute arguments

git-svn-id: trunk@10610 -

peter 17 years ago
parent
commit
85250cca06

+ 12 - 21
utils/fppkg/fppkg.pp

@@ -30,7 +30,6 @@ Type
 
   TMakeTool = Class(TCustomApplication)
   Private
-    ActionStack  : TActionStack;
     ParaAction   : string;
     ParaPackages : TStringList;
     procedure MaybeCreateLocalDirs;
@@ -174,13 +173,11 @@ Constructor TMakeTool.Create;
 begin
   inherited Create(nil);
   ParaPackages:=TStringList.Create;
-  ActionStack:=TActionStack.Create;
 end;
 
 
 Destructor TMakeTool.Destroy;
 begin
-  FreeAndNil(ActionStack);
   FreeAndNil(ParaPackages);
   inherited Destroy;
 end;
@@ -275,7 +272,6 @@ procedure TMakeTool.DoRun;
 var
   ActionPackage : TFPPackage;
   OldCurrDir : String;
-  Res    : Boolean;
   i      : Integer;
   SL     : TStringList;
 begin
@@ -292,14 +288,14 @@ begin
     if not FileExists(GlobalOptions.LocalPackagesFile) then
       begin
         try
-          pkghandler.ExecuteAction(nil,'update');
+          pkghandler.ExecuteAction('','update');
         except
           on E: Exception do
             Log(vlWarning,E.Message);
         end;
       end;
-    LoadLocalMirrors;
-    LoadLocalRepository;
+    LoadLocalAvailableMirrors;
+    LoadLocalAvailableRepository;
     FindInstalledPackages(FPMakeCompilerOptions,true);
     CheckFPMakeDependencies;
     // We only need to reload the status when we use a different
@@ -319,8 +315,8 @@ begin
 
     if ParaPackages.Count=0 then
       begin
-        Log(vlDebug,SLogCommandLineAction,['[<currentdir>]',ParaAction]);
-        res:=pkghandler.ExecuteAction(nil,ParaAction);
+        ActionPackage:=InstalledRepository.AddPackage(CurrentDirPackageName);
+        pkghandler.ExecuteAction(CurrentDirPackageName,ParaAction);
       end
     else
       begin
@@ -329,26 +325,21 @@ begin
           begin
             if FileExists(ParaPackages[i]) then
               begin
-                ActionPackage:=LoadOrCreatePackage(ChangeFileExt(ExtractFileName(ParaPackages[i]),''));
-                ActionPackage.FileName:=ExpandFileName(ParaPackages[i]);
-                ActionPackage.IsLocalPackage:=true;
-                res:=pkghandler.ExecuteAction(ActionPackage,ParaAction);
-                FreeAndNil(ActionPackage);
+                ActionPackage:=InstalledRepository.AddPackage(CmdLinePackageName);
+                ActionPackage.LocalFileName:=ExpandFileName(ParaPackages[i]);
+                pkghandler.ExecuteAction(CmdLinePackageName,ParaAction);
               end
             else
               begin
-                ActionPackage:=CurrentRepository.PackageByName(ParaPackages[i]);
-                Log(vlDebug,SLogCommandLineAction,['['+ActionPackage.Name+']',ParaAction]);
-                res:=pkghandler.ExecuteAction(ActionPackage,ParaAction);
+                Log(vlDebug,SLogCommandLineAction,['['+ParaPackages[i]+']',ParaAction]);
+                pkghandler.ExecuteAction(ParaPackages[i],ParaAction);
               end;
-            if not res then
-              break;
           end;
       end;
 
     // Recompile all packages dependent on this package
-    if res and (ParaAction='install') then
-      pkghandler.ExecuteAction(nil,'fixbroken');
+    if (ParaAction='install') then
+      pkghandler.ExecuteAction('','fixbroken');
 
     Terminate;
 

+ 8 - 99
utils/fppkg/fprepos.pp

@@ -122,9 +122,8 @@ type
     FOSes : TOSES;
     FCPUs : TCPUS;
     // Installation info
-    FInstalledVersion  : TFPVersion;
-    FInstalledChecksum : cardinal;
-    FIsLocalPackage : Boolean;
+    FChecksum : cardinal;
+    FLocalFileName : String;
     function GetFileName: String;
     procedure SetName(const AValue: String);
     procedure SetVersion(const AValue: TFPVersion);
@@ -134,7 +133,7 @@ type
     Procedure LoadFromStream(Stream : TStream; Streamversion : Integer); override;
     Procedure SaveToStream(Stream : TStream); override;
     Procedure Assign(Source : TPersistent); override;
-    Function AddDependency(Const APackageName : String; AMinVersion : String = '') : TFPDependency;
+    Function AddDependency(Const APackageName : String; const AMinVersion : String = '') : TFPDependency;
     Property Dependencies : TFPDependencies Read FDependencies;
   Published
     Property Name : String Read FName Write SetName;
@@ -147,10 +146,9 @@ type
     Property Email : String Read FEmail Write FEmail;
     Property OSes : TOSes Read FOSes Write FOses;
     Property CPUs : TCPUs Read FCPUs Write FCPUs;
-    Property InstalledVersion : TFPVersion Read FInstalledVersion Write FInstalledVersion;
-    Property InstalledChecksum : Cardinal Read FInstalledChecksum Write FInstalledChecksum;
+    Property Checksum : Cardinal Read FChecksum Write FChecksum;
     // Manual package from commandline not in official repository
-    Property IsLocalPackage : Boolean Read FIsLocalPackage Write FIsLocalPackage;
+    Property LocalFileName : String Read FLocalFileName Write FLocalFileName;
   end;
 
   { TFPPackages }
@@ -194,14 +192,6 @@ type
     Procedure LoadFromFile(const AFileName : String);
     Procedure SaveToFile(const AFileName : String);
     Procedure Save;
-    // Loading and Saving version numbers: List of Name=Value pairs.
-    procedure ClearStatus;
-{$ifdef STATUSFILE}
-    Procedure LoadStatusFromStream(Stream : TStream); virtual;
-    Procedure SaveStatusToStream(Stream : TStream); virtual;
-    Procedure LoadStatusFromFile(const AFileName : String);
-    Procedure SaveStatusToFile(const AFileName : String);
-{$endif STATUSFILE}
     // Package management
     Function IndexOfPackage(const APackageName : String) : Integer;
     Function FindPackage(const APackageName : String) : TFPPackage;
@@ -484,8 +474,7 @@ constructor TFPPackage.Create(ACollection: TCollection);
 begin
   inherited Create(ACollection);
   FVersion:=TFPVersion.Create;
-  FInstalledVersion:=TFPVersion.Create;
-  FInstalledChecksum:=$ffffffff;
+  FChecksum:=$ffffffff;
   FOSes:=AllOSes;
   FCPUs:=AllCPUs;
   FDependencies:=TFPDependencies.Create(TFPDependency);
@@ -496,7 +485,6 @@ destructor TFPPackage.Destroy;
 begin
   FreeAndNil(FDependencies);
   FreeAndNil(FVersion);
-  FreeAndNil(FInstalledVersion);
   inherited Destroy;
 end;
 
@@ -621,7 +609,7 @@ begin
       Description:=P.Description;
       ExternalURL:=P.ExternalURL;
       FileName:=P.FileName;
-      InstalledVersion.Assign(P.Installedversion);
+      Checksum:=P.Checksum;
       Dependencies.Clear;
       Dependencies.Assign(P.Dependencies);
     end
@@ -630,7 +618,7 @@ begin
 end;
 
 
-function TFPPackage.AddDependency(const APackageName: String;AMinVersion: String): TFPDependency;
+function TFPPackage.AddDependency(Const APackageName : String; const AMinVersion : String = ''): TFPDependency;
 begin
   Result:=Dependencies.AddDependency(APackageName,AMinVersion);
 end;
@@ -808,85 +796,6 @@ begin
 end;
 
 
-procedure TFPRepository.ClearStatus;
-Var
-  I : Integer;
-begin
-  For I:=0 to PackageCount-1 do
-    With Packages[i] do
-      InstalledVersion.Clear;
-end;
-
-
-{$ifdef STATUSFILE}
-procedure TFPRepository.LoadStatusFromStream(Stream: TStream);
-Var
-  L : TStrings;
-  I : Integer;
-  N,V : String;
-begin
-  L:=TStringList.Create;
-  Try
-    L.LoadFromStream(Stream);
-    For I:=0 to L.Count-1 do
-      begin
-      L.GetNameValue(I,N,V);
-      If (N<>'') and (V<>'') then
-        PackageByName(N).InstalledVersion.AsString:=V;
-      end;
-  Finally
-    L.Free;
-  end;
-end;
-
-
-procedure TFPRepository.SaveStatusToStream(Stream: TStream);
-Var
-  L : TStrings;
-  I : Integer;
-begin
-  L:=TStringList.Create;
-  Try
-    For I:=0 to PackageCount-1 do
-      With Packages[i] do
-        if not InstalledVersion.Empty then
-          L.Add(Name+'='+InstalledVersion.AsString);
-    L.SaveToStream(Stream);
-  Finally
-    L.Free;
-  end;
-end;
-
-
-procedure TFPRepository.LoadStatusFromFile(const AFileName: String);
-Var
-  F : TFileStream;
-begin
-  F:=TFileStream.Create(AFileName,fmOpenRead);
-  Try
-    LoadStatusFromStream(F);
-  Finally
-    F.Free;
-  end;
-end;
-
-
-procedure TFPRepository.SaveStatusToFile(const AFileName: String);
-Var
-  F : TFileStream;
-begin
-  If FileExists(AFileName) and BackupFiles then
-    BackupFile(AFileName);
-  F:=TFileStream.Create(AFileName,fmCreate);
-  Try
-    SaveStatusToStream(F);
-  Finally
-    F.Free;
-  end;
-end;
-{$endif STATUSFILE}
-
-
 function TFPRepository.IndexOfPackage(const APackageName: String): Integer;
 begin
   Result:=FPackages.IndexOfPackage(APackageName);

+ 117 - 108
utils/fppkg/pkgcommands.pp

@@ -23,176 +23,178 @@ type
 
   TCommandAddConfig = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandUpdate }
 
   TCommandUpdate = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandShowAll }
 
   TCommandShowAll = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandShowAvail }
 
   TCommandShowAvail = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandScanPackages }
 
   TCommandScanPackages = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandDownload }
 
   TCommandDownload = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandUnzip }
 
   TCommandUnzip = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandCompile }
 
   TCommandCompile = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandBuild }
 
   TCommandBuild = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandInstall }
 
   TCommandInstall = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandClean }
 
   TCommandClean = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandArchive }
 
   TCommandArchive = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandInstallDependencies }
 
   TCommandInstallDependencies = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TCommandFixBroken }
 
   TCommandFixBroken = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
-function TCommandAddConfig.Execute(const Args:TActionArgs):boolean;
+procedure TCommandAddConfig.Execute;
 begin
 {
   Log(vlInfo,SLogGeneratingCompilerConfig,[S]);
   Options.InitCompilerDefaults(Args[2]);
   Options.SaveCompilerToFile(S);
 }
-  Result:=true;
 end;
 
 
-function TCommandUpdate.Execute(const Args:TActionArgs):boolean;
+procedure TCommandUpdate.Execute;
 var
   PackagesURL :  String;
 begin
   // Download mirrors.xml
   Log(vlCommands,SLogDownloading,[GlobalOptions.RemoteMirrorsURL,GlobalOptions.LocalMirrorsFile]);
   DownloadFile(GlobalOptions.RemoteMirrorsURL,GlobalOptions.LocalMirrorsFile);
-  LoadLocalMirrors;
+  LoadLocalAvailableMirrors;
   // Download packages.xml
   PackagesURL:=GetRemoteRepositoryURL(PackagesFileName);
   Log(vlCommands,SLogDownloading,[PackagesURL,GlobalOptions.LocalPackagesFile]);
   DownloadFile(PackagesURL,GlobalOptions.LocalPackagesFile);
   // Read the repository again
-  LoadLocalRepository;
+  LoadLocalAvailableRepository;
   // no need to log errors again
   FindInstalledPackages(CompilerOptions,False);
-  Result:=true;
 end;
 
 
-function TCommandShowAll.Execute(const Args:TActionArgs):boolean;
+procedure TCommandShowAll.Execute;
 begin
-  ListLocalRepository(true);
-  Result:=true;
+  ListInstalledPackages;
 end;
 
 
-function TCommandShowAvail.Execute(const Args:TActionArgs):boolean;
+procedure TCommandShowAvail.Execute;
 begin
-  ListLocalRepository(false);
-  Result:=true;
+  ListAvailablePackages;
 end;
 
 
-function TCommandScanPackages.Execute(const Args:TActionArgs):boolean;
+procedure TCommandScanPackages.Execute;
 begin
   RebuildRemoteRepository;
   ListRemoteRepository;
   SaveRemoteRepository;
-  Result:=true;
 end;
 
 
-function TCommandDownload.Execute(const Args:TActionArgs):boolean;
+procedure TCommandDownload.Execute;
+var
+  P : TFPPackage;
 begin
-  if not assigned(CurrentPackage) then
+  if PackageName='' then
     Error(SErrNoPackageSpecified);
-  if not FileExists(PackageLocalArchive) then
-    ExecuteAction(CurrentPackage,'downloadpackage',Args);
-  Result:=true;
+  P:=AvailableRepository.PackageByName(PackageName);
+  if not FileExists(PackageLocalArchive(P)) then
+    ExecuteAction(PackageName,'downloadpackage');
 end;
 
 
-function TCommandUnzip.Execute(const Args:TActionArgs):boolean;
+procedure TCommandUnzip.Execute;
 Var
   BuildDir : string;
   ArchiveFile : String;
+  P : TFPPackage;
 begin
-  BuildDir:=PackageBuildPath;
-  ArchiveFile:=PackageLocalArchive;
-  if not assigned(CurrentPackage) then
+  if PackageName='' then
     Error(SErrNoPackageSpecified);
+  if IsLocalPackage then
+    P:=InstalledRepository.PackageByName(PackageName)
+  else
+    P:=AvailableRepository.PackageByName(PackageName);
+  BuildDir:=PackageBuildPath(P);
+  ArchiveFile:=PackageLocalArchive(P);
   if not FileExists(ArchiveFile) then
-    ExecuteAction(CurrentPackage,'downloadpackage');
+    ExecuteAction(PackageName,'downloadpackage');
   { Create builddir, remove it first if needed }
   if DirectoryExists(BuildDir) then
     DeleteDir(BuildDir);
@@ -202,130 +204,141 @@ begin
   With TUnZipper.Create do
     try
       Log(vlCommands,SLogUnzippping,[ArchiveFile]);
-      OutputPath:=PackageBuildPath;
+      OutputPath:=PackageBuildPath(P);
       UnZipAllFiles(ArchiveFile);
     Finally
       Free;
     end;
-  Result:=true;
 end;
 
 
-function TCommandCompile.Execute(const Args:TActionArgs):boolean;
+procedure TCommandCompile.Execute;
 begin
-  if assigned(CurrentPackage) then
+  if PackageName<>'' then
     begin
       // For local files we need the information inside the zip to get the
       // dependencies
-      if CurrentPackage.IsLocalPackage then
+      if IsLocalPackage then
         begin
-          ExecuteAction(CurrentPackage,'unzip',Args);
-          ExecuteAction(CurrentPackage,'installdependencies',Args);
+          ExecuteAction(PackageName,'unzip');
+          ExecuteAction(PackageName,'installdependencies');
         end
       else
         begin
-          ExecuteAction(CurrentPackage,'installdependencies',Args);
-          ExecuteAction(CurrentPackage,'unzip',Args);
+          ExecuteAction(PackageName,'installdependencies');
+          ExecuteAction(PackageName,'unzip');
         end;
     end;
-  ExecuteAction(CurrentPackage,'fpmakecompile',Args);
-  Result:=true;
+  ExecuteAction(PackageName,'fpmakecompile');
 end;
 
 
-function TCommandBuild.Execute(const Args:TActionArgs):boolean;
+procedure TCommandBuild.Execute;
 begin
-  if assigned(CurrentPackage) then
+  if PackageName<>'' then
     begin
       // For local files we need the information inside the zip to get the
       // dependencies
-      if CurrentPackage.IsLocalPackage then
+      if IsLocalPackage then
         begin
-          ExecuteAction(CurrentPackage,'unzip',Args);
-          ExecuteAction(CurrentPackage,'installdependencies',Args);
+          ExecuteAction(PackageName,'unzip');
+          ExecuteAction(PackageName,'installdependencies');
         end
       else
         begin
-          ExecuteAction(CurrentPackage,'installdependencies',Args);
-          ExecuteAction(CurrentPackage,'unzip',Args);
+          ExecuteAction(PackageName,'installdependencies');
+          ExecuteAction(PackageName,'unzip');
         end;
     end;
-  ExecuteAction(CurrentPackage,'fpmakebuild',Args);
-  Result:=true;
+  ExecuteAction(PackageName,'fpmakebuild');
 end;
 
 
-function TCommandInstall.Execute(const Args:TActionArgs):boolean;
+procedure TCommandInstall.Execute;
 var
-  S : String;
+  UFN,S : String;
+  P   : TFPPackage;
 begin
-  if assigned(CurrentPackage) then
-    ExecuteAction(CurrentPackage,'build',Args);
-  ExecuteAction(CurrentPackage,'fpmakeinstall',Args);
-  // Update version information from generated fpunits.conf
-  if assigned(CurrentPackage) then
+  if PackageName<>'' then
     begin
+      ExecuteAction(PackageName,'build');
+      ExecuteAction(PackageName,'fpmakeinstall');
+      if IsLocalPackage then
+        begin
+          // Load package name from manifest
+          if not FileExists(ManifestFileName) then
+            ExecuteAction(PackageName,'fpmakemanifest');
+          P:=LoadManifestFromFile(ManifestFileName);
+          S:=P.Name;
+          FreeAndNil(P);
+        end
+      else
+        S:=PackageName;
+      P:=InstalledRepository.FindPackage(S);
+      if not assigned(P) then
+        P:=InstalledRepository.AddPackage(S);
       if GlobalOptions.InstallGlobal then
-        S:=CompilerOptions.GlobalUnitDir
+        UFN:=CompilerOptions.GlobalUnitDir
       else
-        S:=CompilerOptions.LocalUnitDir;
-      S:=IncludeTrailingPathDelimiter(S)+CurrentPackage.Name+PathDelim+UnitConfigFileName;
-      LoadUnitConfigFromFile(CurrentPackage,S);
-    end;
-  Result:=true;
+        UFN:=CompilerOptions.LocalUnitDir;
+      UFN:=IncludeTrailingPathDelimiter(UFN)+S+PathDelim+UnitConfigFileName;
+      LoadUnitConfigFromFile(P,UFN);
+    end
+  else
+    ExecuteAction(PackageName,'fpmakeinstall');
 end;
 
 
-function TCommandClean.Execute(const Args:TActionArgs):boolean;
+procedure TCommandClean.Execute;
 begin
-  ExecuteAction(CurrentPackage,'fpmakeclean',Args);
-  Result:=true;
+  ExecuteAction(PackageName,'fpmakeclean');
 end;
 
 
-function TCommandArchive.Execute(const Args:TActionArgs):boolean;
+procedure TCommandArchive.Execute;
 begin
-  ExecuteAction(CurrentPackage,'fpmakearchive',Args);
-  Result:=true;
+  ExecuteAction(PackageName,'fpmakearchive');
 end;
 
 
-function TCommandInstallDependencies.Execute(const Args:TActionArgs):boolean;
+procedure TCommandInstallDependencies.Execute;
 var
   i : Integer;
   MissingDependency,
   D : TFPDependency;
   P,
-  DepPackage : TFPPackage;
+  InstalledP,
+  AvailP : TFPPackage;
   L : TStringList;
   status : string;
 begin
-  if not assigned(CurrentPackage) then
+  if PackageName='' then
     Error(SErrNoPackageSpecified);
   // Load dependencies for local packages
-  if CurrentPackage.IsLocalPackage then
+  if IsLocalPackage then
     begin
-      ExecuteAction(CurrentPackage,'fpmakemanifest',Args);
-      P:=LoadPackageManifest(ManifestFileName);
-      // Update CurrentPackage
-      CurrentPackage.Assign(P);
-      CurrentPackage.IsLocalPackage:=true;
-    end;
+      ExecuteAction(PackageName,'fpmakemanifest');
+      P:=LoadManifestFromFile(ManifestFileName);
+    end
+  else
+    P:=AvailableRepository.PackageByName(PackageName);
   // Find and List dependencies
   MissingDependency:=nil;
   L:=TStringList.Create;
-  for i:=0 to CurrentPackage.Dependencies.Count-1 do
+  for i:=0 to P.Dependencies.Count-1 do
     begin
-      D:=CurrentPackage.Dependencies[i];
+      D:=P.Dependencies[i];
       if (CompilerOptions.CompilerOS in D.OSes) and
          (CompilerOptions.CompilerCPU in D.CPUs) then
         begin
-          DepPackage:=CurrentRepository.PackageByName(D.PackageName);
+          InstalledP:=InstalledRepository.FindPackage(D.PackageName);
           // Need installation?
-          if (DepPackage.InstalledVersion.Empty) or
-             (DepPackage.InstalledVersion.CompareVersion(D.MinVersion)<0) then
+          if not assigned(InstalledP) or
+             (InstalledP.Version.CompareVersion(D.MinVersion)<0) then
             begin
-              if DepPackage.Version.CompareVersion(D.MinVersion)<0 then
+              AvailP:=AvailableRepository.FindPackage(D.PackageName);
+              if not assigned(AvailP) or
+                 (AvailP.Version.CompareVersion(D.MinVersion)<0) then
                 begin
                   status:='Not Available!';
                   MissingDependency:=D;
@@ -333,21 +346,22 @@ begin
               else
                 begin
                   status:='Updating';
-                  L.Add(DepPackage.Name);
+                  L.Add(D.PackageName);
                 end;
             end
           else
             begin
-              if PackageIsBroken(DepPackage) then
+              if PackageIsBroken(InstalledP) then
                 begin
                   status:='Broken, recompiling';
-                  L.Add(DepPackage.Name);
+                  L.Add(D.PackageName);
                 end
               else
                 status:='OK';
             end;
           Log(vlInfo,SLogPackageDependency,
-              [D.PackageName,D.MinVersion.AsString,DepPackage.InstalledVersion.AsString,DepPackage.Version.AsString,status]);
+              [D.PackageName,D.MinVersion.AsString,PackageInstalledVersionStr(D.PackageName),
+               PackageAvailableVersionStr(D.PackageName),status]);
         end
       else
         Log(vlDebug,SDbgPackageDependencyOtherTarget,[D.PackageName,MakeTargetString(CompilerOptions.CompilerCPU,CompilerOptions.CompilerOS)]);
@@ -357,19 +371,16 @@ begin
     Error(SErrNoPackageAvailable,[MissingDependency.PackageName,MissingDependency.MinVersion.AsString]);
   // Install needed updates
   for i:=0 to L.Count-1 do
-    begin
-      DepPackage:=CurrentRepository.PackageByName(L[i]);
-      ExecuteAction(DepPackage,'install');
-    end;
+    ExecuteAction(L[i],'install');
   FreeAndNil(L);
-  Result:=true;
+  if IsLocalPackage then
+    FreeAndNil(P);
 end;
 
 
-function TCommandFixBroken.Execute(const Args:TActionArgs):boolean;
+procedure TCommandFixBroken.Execute;
 var
   i : integer;
-  P : TFPPackage;
   SL : TStringList;
 begin
   SL:=TStringList.Create;
@@ -379,13 +390,11 @@ begin
       break;
     for i:=0 to SL.Count-1 do
       begin
-        P:=CurrentRepository.PackageByName(SL[i]);
-        ExecuteAction(P,'build');
-        ExecuteAction(P,'install');
+        ExecuteAction(SL[i],'build');
+        ExecuteAction(SL[i],'install');
       end;
   until false;
   FreeAndNil(SL);
-  Result:=true;
 end;
 
 

+ 9 - 5
utils/fppkg/pkgdownload.pp

@@ -30,7 +30,7 @@ Type
 
   TDownloadPackage = Class(TPackagehandler)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 procedure RegisterDownloader(const AName:string;Downloaderclass:TBaseDownloaderClass);
@@ -44,9 +44,11 @@ implementation
 uses
   contnrs,
   uriparser,
+  fprepos,
   pkgglobals,
   pkgoptions,
-  pkgmessages;
+  pkgmessages,
+  pkgrepos;
 
 var
   DownloaderList  : TFPHashList;
@@ -157,15 +159,17 @@ end;
 
 { TDownloadPackage }
 
-function TDownloadPackage.Execute(const Args:TActionArgs):boolean;
+procedure TDownloadPackage.Execute;
 var
   DownloaderClass : TBaseDownloaderClass;
+  P : TFPPackage;
 begin
+  P:=AvailableRepository.PackageByName(PackageName);
   DownloaderClass:=GetDownloader(GlobalOptions.Downloader);
   with DownloaderClass.Create(nil) do
     try
-      Log(vlCommands,SLogDownloading,[PackageRemoteArchive,PackageLocalArchive]);
-      Download(PackageRemoteArchive,PackageLocalArchive);
+      Log(vlCommands,SLogDownloading,[PackageRemoteArchive(P),PackageLocalArchive(P)]);
+      Download(PackageRemoteArchive(P),PackageLocalArchive(P));
     finally
       Free;
     end;

+ 36 - 41
utils/fppkg/pkgfpmake.pp

@@ -13,16 +13,15 @@ uses
   fprepos,
   pkgoptions,
   pkgglobals,
-  pkgmessages;
+  pkgmessages,
+  pkgrepos;
 
 type
   { TFPMakeCompiler }
 
   TFPMakeCompiler = Class(TPackagehandler)
-  Private
-    Procedure CompileFPMake;
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
@@ -38,7 +37,7 @@ type
 
   TFPMakeRunnerCompile = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
@@ -46,7 +45,7 @@ type
 
   TFPMakeRunnerBuild = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
@@ -54,7 +53,7 @@ type
 
   TFPMakeRunnerInstall = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
@@ -62,21 +61,21 @@ type
 
   TFPMakeRunnerClean = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TFPMakeRunnerManifest }
 
   TFPMakeRunnerManifest = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
   { TFPMakeRunnerArchive }
 
   TFPMakeRunnerArchive = Class(TFPMakeRunner)
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
    TMyMemoryStream=class(TMemoryStream)
@@ -120,7 +119,7 @@ end;
 
 { TFPMakeCompiler }
 
-Procedure TFPMakeCompiler.CompileFPMake;
+Procedure TFPMakeCompiler.Execute;
 var
   OOptions : string;
 
@@ -161,9 +160,11 @@ Var
   FPMakeSrc : string;
   NeedFPMKUnitSource,
   HaveFpmake : boolean;
+  P : TFPPackage;
 begin
+  P:=InstalledRepository.PackageByName(PackageName);
   OOptions:='';
-  SetCurrentDir(PackageBuildPath);
+  SetCurrentDir(PackageBuildPath(P));
   // Check for fpmake source
   FPMakeBin:='fpmake'+ExeExt;
   FPMakeSrc:='fpmake.pp';
@@ -236,18 +237,11 @@ begin
 end;
 
 
-function TFPMakeCompiler.Execute(const Args:TActionArgs):boolean;
-begin
-{$warning TODO Check arguments}
-  CompileFPMake;
-  result:=true;
-end;
-
-
 { TFPMakeRunner }
 
 Function TFPMakeRunner.RunFPMake(const Command:string) : Integer;
 Var
+  P : TFPPackage;
   FPMakeBin,
   OOptions : string;
 
@@ -261,15 +255,18 @@ Var
 begin
   OOptions:='';
   // Does the current package support this CPU-OS?
-  if assigned(CurrentPackage) then
+  if PackageName<>'' then
+    P:=InstalledRepository.PackageByName(PackageName)
+  else
+    P:=nil;
+  if assigned(P) then
     begin
-      if not(CompilerOptions.CompilerOS in CurrentPackage.OSes) or
-         not(CompilerOptions.CompilerCPU in CurrentPackage.CPUs) then
-        Error(SErrPackageDoesNotSupportTarget,[CurrentPackage.Name,
-            MakeTargetString(CompilerOptions.CompilerCPU,CompilerOptions.CompilerOS)]);
+      if not(CompilerOptions.CompilerOS in P.OSes) or
+         not(CompilerOptions.CompilerCPU in P.CPUs) then
+        Error(SErrPackageDoesNotSupportTarget,[P.Name,MakeTargetString(CompilerOptions.CompilerCPU,CompilerOptions.CompilerOS)]);
     end;
   { Maybe compile fpmake executable? }
-  ExecuteAction(CurrentPackage,'compilefpmake');
+  ExecuteAction(PackageName,'compilefpmake');
   { Create options }
   AddOption('--nofpccfg');
   if vlInfo in LogLevels then
@@ -286,51 +283,49 @@ begin
   AddOption('--globalunitdir='+CompilerOptions.GlobalUnitDir);
   { Run FPMake }
   FPMakeBin:='fpmake'+ExeExt;
-  SetCurrentDir(PackageBuildPath);
+  SetCurrentDir(PackageBuildPath(P));
   Result:=ExecuteProcess(FPMakeBin,Command+' '+OOptions);
   if Result<>0 then
     Error(SErrExecutionFPMake,[Command]);
 end;
 
 
-function TFPMakeRunnerCompile.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerCompile.Execute;
 begin
-  result:=(RunFPMake('compile')=0);
+  RunFPMake('compile');
 end;
 
 
-function TFPMakeRunnerBuild.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerBuild.Execute;
 begin
-  result:=(RunFPMake('build')=0);
+  RunFPMake('build');
 end;
 
 
-function TFPMakeRunnerInstall.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerInstall.Execute;
 begin
-  result:=(RunFPMake('install')=0);
+  RunFPMake('install');
 end;
 
 
-function TFPMakeRunnerClean.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerClean.Execute;
 begin
-  result:=(RunFPMake('clean')=0);
+  RunFPMake('clean');
 end;
 
 
-function TFPMakeRunnerManifest.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerManifest.Execute;
 begin
-  result:=(RunFPMake('manifest')=0);
+  RunFPMake('manifest');
 end;
 
 
-function TFPMakeRunnerArchive.Execute(const Args:TActionArgs):boolean;
+procedure TFPMakeRunnerArchive.Execute;
 begin
-  result:=(RunFPMake('archive')=0);
+  RunFPMake('archive');
 end;
 
 
-
-
 initialization
   RegisterPkgHandler('compilefpmake',TFPMakeCompiler);
   RegisterPkgHandler('fpmakecompile',TFPMakeRunnerCompile);

+ 74 - 156
utils/fppkg/pkghandler.pp

@@ -10,52 +10,31 @@ uses
   pkgoptions,
   fprepos;
 
-type
-  { TActionStack }
-
-  TActionArgs = array of string;
-
-  TActionStackItem = record
-    ActionPackage : TFPPackage;
-    Action : string;
-    Args   : TActionArgs;
-  end;
-  PActionStackItem = ^TActionStackItem;
-
-  TActionStack = class
-  private
-    FList : TFPList;
-  public
-    constructor Create;
-    destructor Destroy;override;
-    procedure Push(APackage:TFPPackage;const AAction:string;const Args:TActionArgs);
-    procedure Push(APackage:TFPPackage;const AAction:string;const Args:array of string);
-    function  Pop(out APackage:TFPPackage;out AAction:string;out Args:TActionArgs):boolean;
-  end;
-
+const
+  CmdLinePackageName='<cmdline>';
+  CurrentDirPackageName='<currentdir>';
 
+type
   { TPackageHandler }
 
   TPackageHandler = Class(TComponent)
   private
-    FCurrentPackage : TFPPackage;
+    FPackageName : string;
+    FIsLocalPackage : boolean;
   Protected
     Procedure Log(Level: TLogLevel;Msg : String);
     Procedure Log(Level: TLogLevel;Fmt : String; const Args : array of const);
     Procedure Error(Msg : String);
     Procedure Error(Fmt : String; const Args : array of const);
-    procedure ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil);
     Function ExecuteProcess(Const Prog,Args:String):Integer;
     Procedure SetCurrentDir(Const ADir:String);
-    function PackageBuildPath:String;
-    function PackageRemoteArchive:String;
-    function PackageLocalArchive:String;
-    function PackageManifestFile:String;
   Public
-    Constructor Create(AOwner:TComponent;APackage:TFPPackage); virtual;
+    Constructor Create(AOwner:TComponent;const APackageName:string); virtual;
     function PackageLogPrefix:String;
-    Function Execute(const Args:TActionArgs):boolean; virtual; abstract;
-    Property CurrentPackage:TFPPackage Read FCurrentPackage Write FCurrentPackage;
+    procedure ExecuteAction(const APackageName,AAction:string);
+    procedure Execute; virtual; abstract;
+    Property PackageName:string Read FPackageName;
+    Property IsLocalPackage:boolean Read FIsLocalPackage Write FIsLocalPackage;
   end;
   TPackageHandlerClass = class of TPackageHandler;
 
@@ -64,7 +43,12 @@ type
 // Actions/PkgHandler
 procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
 function GetPkgHandler(const AAction:string):TPackageHandlerClass;
-function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
+procedure ExecuteAction(const APackageName,AAction:string);
+
+function PackageBuildPath(APackage:TFPPackage):String;
+function PackageRemoteArchive(APackage:TFPPackage): String;
+function PackageLocalArchive(APackage:TFPPackage): String;
+function PackageManifestFile(APackage:TFPPackage): String;
 
 
 Implementation
@@ -99,203 +83,137 @@ begin
 end;
 
 
-function ExecuteAction(APackage:TFPPackage;const AAction:string;const Args:TActionArgs=nil):Boolean;
+procedure ExecuteAction(const APackageName,AAction:string);
 var
   pkghandlerclass : TPackageHandlerClass;
-  i : integer;
-  logargs : string;
   FullActionName : string;
 begin
-  result:=false;
   // Check if we have already executed or are executing the action
-  if assigned(Apackage) then
-    FullActionName:=APackage.Name+AAction
-  else
-    FullActionName:=AAction;
+  FullActionName:=APackageName+AAction;
   if ExecutedActions.Find(FullActionName)<>nil then
     begin
       Log(vlDebug,'Already executed or executing action '+FullActionName);
-      result:=true;
       exit;
     end;
   ExecutedActions.Add(FullActionName,Pointer(PtrUInt(1)));
   // Create action handler class
   pkghandlerclass:=GetPkgHandler(AAction);
-  With pkghandlerclass.Create(nil,APackage) do
+  With pkghandlerclass.Create(nil,APackageName) do
     try
-      logargs:='';
-      for i:=Low(Args) to High(Args) do
-        begin
-          if logargs='' then
-            logargs:=Args[i]
-          else
-            logargs:=logargs+','+Args[i];
-        end;
-      Log(vlDebug,SLogRunAction+' start',[AAction,logargs]);
-      result:=Execute(Args);
-      Log(vlDebug,SLogRunAction+' end',[AAction,logargs]);
+      if (APackageName=CmdLinePackageName) or
+         (APackageName=CurrentDirPackageName) then
+        IsLocalPackage:=true;
+      Log(vlDebug,SLogRunAction+' start',[AAction]);
+      Execute;
+      Log(vlDebug,SLogRunAction+' end',[AAction]);
     finally
       Free;
     end;
 end;
 
 
-{ TPackageHandler }
-
-constructor TPackageHandler.Create(AOwner:TComponent;APackage:TFPPackage);
-begin
-  inherited Create(AOwner);
-  FCurrentPackage:=APackage;
-end;
-
-Function TPackageHandler.ExecuteProcess(Const Prog,Args:String):Integer;
-begin
-  Log(vlCommands,SLogExecute,[Prog,Args]);
-  Result:=SysUtils.ExecuteProcess(Prog,Args);
-end;
-
-
-Procedure TPackageHandler.SetCurrentDir(Const ADir:String);
+function PackageBuildPath(APackage:TFPPackage):String;
 begin
-  Log(vlCommands,SLogChangeDir,[ADir]);
-  if not SysUtils.SetCurrentDir(ADir) then
-    Error(SErrChangeDirFailed,[ADir]);
-end;
-
-
-function TPackageHandler.PackageBuildPath:String;
-begin
-  if CurrentPackage=nil then
+  if APackage.Name=CurrentDirPackageName then
     Result:='.'
+  else if APackage.Name=CmdLinePackageName then
+    Result:=GlobalOptions.BuildDir+ChangeFileExt(ExtractFileName(APackage.LocalFileName),'')
   else
-    Result:=GlobalOptions.BuildDir+CurrentPackage.Name;
+    Result:=GlobalOptions.BuildDir+APackage.Name;
 end;
 
-function TPackageHandler.PackageRemoteArchive: String;
+
+function PackageRemoteArchive(APackage:TFPPackage): String;
 begin
-  if not assigned(CurrentPackage) then
-    Error(SErrNoPackageSpecified);
-  if CurrentPackage.IsLocalPackage then
+  if APackage.Name=CurrentDirPackageName then
+    Error(SErrNoPackageSpecified)
+  else if APackage.Name=CmdLinePackageName then
     Error(SErrPackageIsLocal);
-  if CurrentPackage.ExternalURL<>'' then
-    Result:=CurrentPackage.ExternalURL
+  if APackage.ExternalURL<>'' then
+    Result:=APackage.ExternalURL
   else
-    Result:=GetRemoteRepositoryURL(CurrentPackage.FileName);
+    Result:=GetRemoteRepositoryURL(APackage.FileName);
 end;
 
-function TPackageHandler.PackageLocalArchive: String;
+
+function PackageLocalArchive(APackage:TFPPackage): String;
 begin
-  if not assigned(CurrentPackage) then
-    Error(SErrNoPackageSpecified);
-  if CurrentPackage.IsLocalPackage then
-    Result:=CurrentPackage.FileName
+  if APackage.Name=CurrentDirPackageName then
+    Error(SErrNoPackageSpecified)
+  else if APackage.Name=CmdLinePackageName then
+    Result:=APackage.LocalFileName
   else
-    Result:=GlobalOptions.ArchivesDir+CurrentPackage.FileName;
+    Result:=GlobalOptions.ArchivesDir+APackage.FileName;
 end;
 
 
-function TPackageHandler.PackageManifestFile: String;
+function PackageManifestFile(APackage:TFPPackage): String;
 begin
   Result:=ManifestFileName;
 end;
 
 
-function TPackageHandler.PackageLogPrefix:String;
-begin
-  if assigned(CurrentPackage) then
-    Result:='['+CurrentPackage.Name+'] '
-  else
-//    Result:='[<currentdir>] ';
-    Result:='';
-end;
-
-
-Procedure TPackageHandler.Log(Level:TLogLevel; Msg:String);
-begin
-  pkgglobals.Log(Level,PackageLogPrefix+Msg);
-end;
 
+{ TPackageHandler }
 
-Procedure TPackageHandler.Log(Level:TLogLevel; Fmt:String; const Args:array of const);
+constructor TPackageHandler.Create(AOwner:TComponent;const APackageName:string);
 begin
-  pkgglobals.Log(Level,PackageLogPrefix+Fmt,Args);
+  inherited Create(AOwner);
+  FPackageName:=APackageName;
 end;
 
-
-Procedure TPackageHandler.Error(Msg:String);
+Function TPackageHandler.ExecuteProcess(Const Prog,Args:String):Integer;
 begin
-  pkgglobals.Error(PackageLogPrefix+Msg);
+  Log(vlCommands,SLogExecute,[Prog,Args]);
+  Result:=SysUtils.ExecuteProcess(Prog,Args);
 end;
 
 
-Procedure TPackageHandler.Error(Fmt:String; const Args:array of const);
+Procedure TPackageHandler.SetCurrentDir(Const ADir:String);
 begin
-  pkgglobals.Error(PackageLogPrefix+Fmt,Args);
+  Log(vlCommands,SLogChangeDir,[ADir]);
+  if not SysUtils.SetCurrentDir(ADir) then
+    Error(SErrChangeDirFailed,[ADir]);
 end;
 
 
-procedure TPackageHandler.ExecuteAction(APackage: TFPPackage; const AAction: string; const Args: TActionArgs=nil);
+function TPackageHandler.PackageLogPrefix:String;
 begin
-  pkghandler.ExecuteAction(APackage,AAction,Args);
+  if PackageName<>'' then
+    Result:='['+PackageName+'] '
+  else
+    Result:='';
 end;
 
 
-{ TActionStack }
-
-constructor TActionStack.Create;
+procedure TPackageHandler.ExecuteAction(const APackageName,AAction:string);
 begin
-  FList:=TFPList.Create;
+  // Needed to override TComponent.ExecuteAction method
+  pkghandler.ExecuteAction(APackageName,AAction);
 end;
 
 
-destructor TActionStack.Destroy;
+Procedure TPackageHandler.Log(Level:TLogLevel; Msg:String);
 begin
-  FreeAndNil(FList);
+  pkgglobals.Log(Level,PackageLogPrefix+Msg);
 end;
 
 
-procedure TActionStack.Push(APackage:TFPPackage;const AAction:string;const Args:TActionArgs);
-var
-  ActionItem : PActionStackItem;
+Procedure TPackageHandler.Log(Level:TLogLevel; Fmt:String; const Args:array of const);
 begin
-  New(ActionItem);
-  ActionItem^.ActionPackage:=APackage;
-  ActionItem^.Action:=AAction;
-  ActionItem^.Args:=Args;
-  FList.Add(ActionItem);
+  pkgglobals.Log(Level,PackageLogPrefix+Fmt,Args);
 end;
 
 
-procedure TActionStack.Push(APackage:TFPPackage;const AAction:string;const Args:array of string);
-var
-  ActionArgs : TActionArgs;
-  i : integer;
+Procedure TPackageHandler.Error(Msg:String);
 begin
-  SetLength(ActionArgs,high(Args)+1);
-  for i:=low(Args) to high(Args) do
-    ActionArgs[i]:=Args[i];
-  Push(APackage,AAction,ActionArgs);
+  pkgglobals.Error(PackageLogPrefix+Msg);
 end;
 
 
-function TActionStack.Pop(out APackage:TFPPackage;out AAction:string;out Args:TActionArgs):boolean;
-var
-  ActionItem : PActionStackItem;
-  Idx : integer;
+Procedure TPackageHandler.Error(Fmt:String; const Args:array of const);
 begin
-  Result:=false;
-  if FList.Count=0 then
-    exit;
-  // Retrieve Item from stack
-  Idx:=FList.Count-1;
-  ActionItem:=PActionStackItem(FList[Idx]);
-  FList.Delete(Idx);
-  // Copy contents and dispose stack item
-  APackage:=ActionItem^.ActionPackage;
-  AAction:=ActionItem^.Action;
-  Args:=ActionItem^.Args;
-  dispose(ActionItem);
-  Result:=true;
+  pkgglobals.Error(PackageLogPrefix+Fmt,Args);
 end;
 
 

+ 2 - 1
utils/fppkg/pkgmessages.pp

@@ -49,11 +49,12 @@ Resourcestring
   SErrCWDFailed              = 'FTP CWD "%s" command failed.';
   SErrGETFailed              = 'FTP GET "%s" command failed.';
   SErrBrokenPackagesFound    = 'Found broken packages, run "fppkg fixbroken" first';
+  SErrManifestNoSinglePackage = 'Manifest file "%s" does not contain exactly one package';
 
   SLogGeneratingFPMake       = 'Generating fpmake.pp';
   SLogNotCompilingFPMake     = 'Skipping compiling of fpmake.pp, fpmake executable already exists';
   SLogCommandLineAction      = 'Adding action from commandline: "%s %s"';
-  SLogRunAction              = 'Action: "%s %s"';
+  SLogRunAction              = 'Action: "%s"';
   SLogExecute                = 'Executing: "%s %s"';
   SLogChangeDir              = 'CurrentDir: "%s"';
   SLogDownloading            = 'Downloading "%s" to "%s"';

+ 2 - 3
utils/fppkg/pkgmkconv.pp

@@ -42,7 +42,7 @@ Type
     procedure ConvertFile(const AFileName: String; Src: TStrings; Dir,OS : String);
     Procedure ConvertFile(Const Source,Dest: String);
   Public
-    Function Execute(const Args:TActionArgs):boolean;override;
+    Procedure Execute;override;
   end;
 
 
@@ -696,13 +696,12 @@ begin
   end;
 end;
 
-function TMakeFileConverter.Execute(const Args:TActionArgs):boolean;
+procedure TMakeFileConverter.Execute;
 begin
   if not FileExists('fpmake.pp') then
     ConvertFile('Makefile.fpc','fpmake.pp')
   else
     Error(SErrConvertFPMakeExists);
-  result:=true;
 end;
 
 begin

+ 201 - 121
utils/fppkg/pkgrepos.pp

@@ -10,24 +10,27 @@ uses
 
 function GetRemoteRepositoryURL(const AFileName:string):string;
 
-procedure LoadLocalMirrors;
-procedure LoadLocalRepository;
-function  LoadOrCreatePackage(const AName:string):TFPPackage;
+procedure LoadLocalAvailableMirrors;
+procedure LoadLocalAvailableRepository;
 procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
-function  LoadPackageManifest(const AManifestFN:string):TFPPackage;
+function LoadManifestFromFile(const AManifestFN:string):TFPPackage;
 procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boolean=true);
 function  PackageIsBroken(APackage:TFPPackage):boolean;
 function  FindBrokenPackages(SL:TStrings):Boolean;
 procedure CheckFPMakeDependencies;
-procedure ListLocalRepository(all:boolean=false);
+function  PackageInstalledVersionStr(const AName:String):string;
+function  PackageAvailableVersionStr(const AName:String):string;
+procedure ListAvailablePackages;
+procedure ListInstalledPackages;
 
 procedure ListRemoteRepository;
 procedure RebuildRemoteRepository;
 procedure SaveRemoteRepository;
 
 var
-  CurrentMirrors    : TFPMirrors;
-  CurrentRepository : TFPRepository;
+  AvailableMirrors    : TFPMirrors;
+  AvailableRepository,
+  InstalledRepository : TFPRepository;
 
 
 implementation
@@ -45,14 +48,14 @@ uses
 var
   CurrentRemoteRepositoryURL : String;
 
-procedure LoadLocalMirrors;
+procedure LoadLocalAvailableMirrors;
 var
   S : String;
   X : TFPXMLMirrorHandler;
 begin
-  if assigned(CurrentMirrors) then
-    CurrentMirrors.Free;
-  CurrentMirrors:=TFPMirrors.Create(TFPMirror);
+  if assigned(AvailableMirrors) then
+    AvailableMirrors.Free;
+  AvailableMirrors:=TFPMirrors.Create(TFPMirror);
 
   // Repository
   S:=GlobalOptions.LocalMirrorsFile;
@@ -63,7 +66,7 @@ begin
     X:=TFPXMLMirrorHandler.Create;
     With X do
       try
-        LoadFromXml(CurrentMirrors,S);
+        LoadFromXml(AvailableMirrors,S);
       finally
         Free;
       end;
@@ -86,22 +89,22 @@ var
 begin
   Result:='';
   M:=nil;
-  if assigned(CurrentMirrors) then
+  if assigned(AvailableMirrors) then
    begin
      // Create array for selection
      BucketCnt:=0;
-     for i:=0 to CurrentMirrors.Count-1 do
-       inc(BucketCnt,CurrentMirrors[i].Weight);
+     for i:=0 to AvailableMirrors.Count-1 do
+       inc(BucketCnt,AvailableMirrors[i].Weight);
      // Select random entry
      Bucket:=Random(BucketCnt);
      M:=nil;
-     for i:=0 to CurrentMirrors.Count-1 do
+     for i:=0 to AvailableMirrors.Count-1 do
        begin
-         for j:=0 to CurrentMirrors[i].Weight-1 do
+         for j:=0 to AvailableMirrors[i].Weight-1 do
            begin
              if Bucket=0 then
                begin
-                 M:=CurrentMirrors[i];
+                 M:=AvailableMirrors[i];
                  break;
                end;
              Dec(Bucket);
@@ -163,55 +166,11 @@ begin
 end;
 
 
-procedure LoadLocalRepository;
-var
-  S : String;
-  X : TFPXMLRepositoryHandler;
-begin
-  if assigned(CurrentRepository) then
-    CurrentRepository.Free;
-  CurrentRepository:=TFPRepository.Create(Nil);
-  // Repository
-  S:=GlobalOptions.LocalPackagesFile;
-  Log(vlDebug,SLogLoadingPackagesFile,[S]);
-  if not FileExists(S) then
-    exit;
-  try
-    X:=TFPXMLRepositoryHandler.Create;
-    With X do
-      try
-        LoadFromXml(CurrentRepository,S);
-      finally
-        Free;
-      end;
-  except
-    on E : Exception do
-      begin
-        Log(vlError,E.Message);
-        Error(SErrCorruptPackagesFile,[S]);
-      end;
-  end;
-end;
-
-
-function LoadOrCreatePackage(const AName:string):TFPPackage;
-begin
-  result:=CurrentRepository.FindPackage(AName);
-  if not assigned(result) then
-    begin
-      result:=CurrentRepository.AddPackage(AName);
-      result.IsLocalPackage:=true;
-    end;
-end;
-
-
-function LoadPackageManifest(const AManifestFN:string):TFPPackage;
+function LoadManifestFromFile(const AManifestFN:string):TFPPackage;
 var
   X : TFPXMLRepositoryHandler;
-  i : integer;
-  DoAdd : Boolean;
-  NewP : TFPPackage;
   NewPackages : TFPPackages;
+  NewP,P : TFPPackage;
 begin
   result:=nil;
   NewPackages:=TFPPackages.Create(TFPPackage);
@@ -219,27 +178,19 @@ begin
   try
     X.LoadFromXml(NewPackages,AManifestFN);
     // Update or Add packages to repository
-    for i:=0 to NewPackages.Count-1 do
+    if NewPackages.Count=1 then
       begin
-        NewP:=NewPackages[i];
-        DoAdd:=True;
-        result:=CurrentRepository.FindPackage(NewP.Name);
-        if assigned(result) then
-          begin
-            if NewP.Version.CompareVersion(result.Version)<0 then
-              begin
-                Writeln(Format('Ignoring package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,result.Version.AsString]));
-                DoAdd:=False;
-              end
-            else
-              Writeln(Format('Updating package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,result.Version.AsString]));
-          end
-        else
-          result:=CurrentRepository.PackageCollection.AddPackage(NewP.Name);
+        NewP:=NewPackages[0];
+        // Prevent duplicate names
+{        P:=InstalledRepository.FindPackage(NewP.Name);
+        if not assigned(P) then
+          P:=InstalledRepository.AddPackage(NewP.Name); }
+        result:=TFPPackage.Create(nil);
         // Copy contents
-        if DoAdd then
-          result.Assign(NewP);
-      end;
+        result.Assign(NewP);
+      end
+    else
+      Error(SErrManifestNoSinglePackage,[AManifestFN]);
   finally
     X.Free;
     NewPackages.Free;
@@ -262,12 +213,12 @@ begin
 {$warning TODO Maybe check also CPU-OS}
     // Read fpunits.conf
     V:=L.Values['version'];
-    APackage.InstalledVersion.AsString:=V;
+    APackage.Version.AsString:=V;
     V:=L.Values['checksum'];
     if V<>'' then
-      APackage.InstalledChecksum:=StrToInt(V)
+      APackage.Checksum:=StrToInt(V)
     else
-      APackage.InstalledChecksum:=$ffffffff;
+      APackage.Checksum:=$ffffffff;
     // Load dependencies
     V:=L.Values['depends'];
     DepSL:=TStringList.Create;
@@ -304,13 +255,16 @@ end;
 
 procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boolean=true);
 
-  procedure LogDuplicatePackages(APackage:TFPPackage;const AFileName: String);
+  function AddInstalledPackage(const AName,AFileName: String):TFPPackage;
   begin
-    // Log packages found in multiple locations (local and global) ?
-    if not APackage.InstalledVersion.Empty then
+    result:=InstalledRepository.FindPackage(AName);
+    if not assigned(result) then
+      result:=InstalledRepository.AddPackage(AName)
+    else
       begin
+        // Log packages found in multiple locations (local and global) ?
         if showdups then
-          Log(vlDebug,SDbgPackageMultipleLocations,[APackage.Name,ExtractFilePath(AFileName)]);
+          Log(vlDebug,SDbgPackageMultipleLocations,[result.Name,ExtractFilePath(AFileName)]);
       end;
   end;
 
@@ -323,7 +277,7 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
     Try
       ReadIniFile(AFileName,L);
       V:=L.Values['version'];
-      APackage.InstalledVersion.AsString:=V;
+      APackage.Version.AsString:=V;
     Finally
       L.Free;
     end;
@@ -347,8 +301,7 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
               UF:=UD+UnitConfigFileName;
               if FileExistsLog(UF) then
                 begin
-                  P:=LoadOrCreatePackage(SR.Name);
-                  LogDuplicatePackages(P,UF);
+                  P:=AddInstalledPackage(SR.Name,UF);
                   LoadUnitConfigFromFile(P,UF)
                 end
               else
@@ -357,8 +310,7 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
                   UF:=UD+'Package.fpc';
                   if FileExistsLog(UF) then
                     begin
-                      P:=LoadOrCreatePackage(SR.Name);
-                      LogDuplicatePackages(P,UF);
+                      P:=AddInstalledPackage(SR.Name,UF);
                       LoadPackagefpcFromFile(P,UF);
                     end;
                 end;
@@ -368,7 +320,9 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
   end;
 
 begin
-  CurrentRepository.ClearStatus;
+  if assigned(InstalledRepository) then
+    InstalledRepository.Free;
+  InstalledRepository:=TFPRepository.Create(nil);
   // First scan the global directory
   // The local directory will overwrite the versions
   if ACompilerOptions.GlobalUnitDir<>'' then
@@ -391,11 +345,11 @@ begin
       if (CompilerOptions.CompilerOS in D.OSes) and
          (CompilerOptions.CompilerCPU in D.CPUs) then
         begin
-          DepPackage:=CurrentRepository.FindPackage(D.PackageName);
+          DepPackage:=InstalledRepository.FindPackage(D.PackageName);
           // Don't stop on missing dependencies
           if assigned(DepPackage) then
             begin
-              if (DepPackage.InstalledChecksum<>D.RequireChecksum) then
+              if (DepPackage.Checksum<>D.RequireChecksum) then
                 begin
                   Log(vlInfo,SLogPackageChecksumChanged,[APackage.Name,D.PackageName]);
                   result:=true;
@@ -415,15 +369,11 @@ var
   P : TFPPackage;
 begin
   SL.Clear;
-  for i:=0 to CurrentRepository.PackageCount-1 do
+  for i:=0 to InstalledRepository.PackageCount-1 do
     begin
-      P:=CurrentRepository.Packages[i];
-      // Process only installed packages
-      if not P.InstalledVersion.Empty then
-        begin
-          if PackageIsBroken(P) then
-            SL.Add(P.Name);
-        end;
+      P:=InstalledRepository.Packages[i];
+      if PackageIsBroken(P) then
+        SL.Add(P.Name);
     end;
   Result:=(SL.Count>0);
 end;
@@ -432,7 +382,8 @@ end;
 procedure CheckFPMakeDependencies;
 var
   i : Integer;
-  P : TFPPackage;
+  P,AvailP : TFPPackage;
+  AvailVerStr : string;
   ReqVer : TFPVersion;
 begin
   // Reset availability
@@ -445,13 +396,18 @@ begin
   // Check for fpmkunit dependencies
   for i:=1 to FPMKUnitDepCount do
     begin
-      P:=CurrentRepository.FindPackage(FPMKUnitDeps[i].package);
+      P:=InstalledRepository.FindPackage(FPMKUnitDeps[i].package);
       if P<>nil then
         begin
+          AvailP:=AvailableRepository.FindPackage(FPMKUnitDeps[i].package);
+          if P<>nil then
+            AvailVerStr:=AvailP.Version.AsString
+          else
+            AvailVerStr:='<not available>';
           ReqVer:=TFPVersion.Create;
           ReqVer.AsString:=FPMKUnitDeps[i].ReqVer;
-          Log(vlDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.InstalledVersion.AsString,P.Version.AsString]);
-          if ReqVer.CompareVersion(P.InstalledVersion)<=0 then
+          Log(vlDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.Version.AsString,AvailVerStr]);
+          if ReqVer.CompareVersion(P.Version)<=0 then
             FPMKUnitDepAvailable[i]:=true
           else
             Log(vlDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
@@ -462,19 +418,102 @@ begin
 end;
 
 
-procedure ListLocalRepository(all:boolean=false);
+{*****************************************************************************
+                           Local Available Repository
+*****************************************************************************}
+
+procedure LoadLocalAvailableRepository;
+var
+  S : String;
+  X : TFPXMLRepositoryHandler;
+begin
+  if assigned(AvailableRepository) then
+    AvailableRepository.Free;
+  AvailableRepository:=TFPRepository.Create(Nil);
+  // Repository
+  S:=GlobalOptions.LocalPackagesFile;
+  Log(vlDebug,SLogLoadingPackagesFile,[S]);
+  if not FileExists(S) then
+    exit;
+  try
+    X:=TFPXMLRepositoryHandler.Create;
+    With X do
+      try
+        LoadFromXml(AvailableRepository,S);
+      finally
+        Free;
+      end;
+  except
+    on E : Exception do
+      begin
+        Log(vlError,E.Message);
+        Error(SErrCorruptPackagesFile,[S]);
+      end;
+  end;
+end;
+
+
+function PackageAvailableVersionStr(const AName:String):string;
+var
+  P : TFPPackage;
+begin
+  P:=InstalledRepository.FindPackage(AName);
+  if P<>nil then
+    result:=P.Version.AsString
+  else
+    result:='-';
+end;
+
+
+function PackageInstalledVersionStr(const AName:String):string;
 var
   P : TFPPackage;
+begin
+  P:=InstalledRepository.FindPackage(AName);
+  if P<>nil then
+    result:=P.Version.AsString
+  else
+    result:='-';
+end;
+
+
+
+procedure ListAvailablePackages;
+var
+  InstalledP,
+  AvailP : TFPPackage;
   i : integer;
   SL : TStringList;
 begin
   SL:=TStringList.Create;
   SL.Sorted:=true;
-  for i:=0 to CurrentRepository.PackageCount-1 do
+  for i:=0 to AvailableRepository.PackageCount-1 do
     begin
-      P:=CurrentRepository.Packages[i];
-      if all or (P.Version.CompareVersion(P.InstalledVersion)>0) then
-        SL.Add(Format('%-20s %-12s %-12s',[P.Name,P.InstalledVersion.AsString,P.Version.AsString]));
+      AvailP:=AvailableRepository.Packages[i];
+      InstalledP:=InstalledRepository.FindPackage(AvailP.Name);
+      if not assigned(InstalledP) or
+         (AvailP.Version.CompareVersion(InstalledP.Version)>0) then
+        SL.Add(Format('%-20s %-12s %-12s',[AvailP.Name,PackageInstalledVersionStr(AvailP.Name),AvailP.Version.AsString]));
+    end;
+  Writeln(Format('%-20s %-12s %-12s',['Name','Installed','Available']));
+  for i:=0 to SL.Count-1 do
+    Writeln(SL[i]);
+  FreeAndNil(SL);
+end;
+
+
+procedure ListInstalledPackages;
+var
+  P : TFPPackage;
+  i : integer;
+  SL : TStringList;
+begin
+  SL:=TStringList.Create;
+  SL.Sorted:=true;
+  for i:=0 to InstalledRepository.PackageCount-1 do
+    begin
+      P:=InstalledRepository.Packages[i];
+      SL.Add(Format('%-20s %-12s %-12s',[P.Name,P.Version.AsString,PackageAvailableVersionStr(P.Name)]));
     end;
   Writeln(Format('%-20s %-12s %-12s',['Name','Installed','Available']));
   for i:=0 to SL.Count-1 do
@@ -487,6 +526,7 @@ end;
                            Remote Repository
 *****************************************************************************}
 
+
 procedure ListRemoteRepository;
 var
   P : TFPPackage;
@@ -495,9 +535,9 @@ var
 begin
   SL:=TStringList.Create;
   SL.Sorted:=true;
-  for i:=0 to CurrentRepository.PackageCount-1 do
+  for i:=0 to InstalledRepository.PackageCount-1 do
     begin
-      P:=CurrentRepository.Packages[i];
+      P:=InstalledRepository.Packages[i];
       SL.Add(Format('%-20s %-12s %-20s',[P.Name,P.Version.AsString,P.FileName]));
     end;
   Writeln(Format('%-20s %-12s %-20s',['Name','Available','FileName']));
@@ -509,14 +549,54 @@ end;
 
 procedure RebuildRemoteRepository;
 
+  procedure LoadPackageManifest(const AManifestFN:string);
+  var
+    X : TFPXMLRepositoryHandler;
+    i : integer;
+    DoAdd : Boolean;
+    P,NewP : TFPPackage;
+    NewPackages : TFPPackages;
+  begin
+    NewPackages:=TFPPackages.Create(TFPPackage);
+    X:=TFPXMLRepositoryHandler.Create;
+    try
+      X.LoadFromXml(NewPackages,AManifestFN);
+      // Update or Add packages to repository
+      for i:=0 to NewPackages.Count-1 do
+        begin
+          NewP:=NewPackages[i];
+          DoAdd:=True;
+          P:=InstalledRepository.FindPackage(NewP.Name);
+          if assigned(P) then
+            begin
+              if NewP.Version.CompareVersion(P.Version)<0 then
+                begin
+                  Writeln(Format('Ignoring package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,P.Version.AsString]));
+                  DoAdd:=False;
+                end
+              else
+                Writeln(Format('Updating package %s-%s (old %s)',[NewP.Name,NewP.Version.AsString,P.Version.AsString]));
+            end
+          else
+            P:=InstalledRepository.PackageCollection.AddPackage(NewP.Name);
+          // Copy contents
+          if DoAdd then
+            P.Assign(NewP);
+        end;
+    finally
+      X.Free;
+      NewPackages.Free;
+    end;
+  end;
+
 var
   i : integer;
   ArchiveSL : TStringList;
   ManifestSL : TStringList;
 begin
-  if assigned(CurrentRepository) then
-    CurrentRepository.Free;
-  CurrentRepository:=TFPRepository.Create(Nil);
+  if assigned(InstalledRepository) then
+    InstalledRepository.Free;
+  InstalledRepository:=TFPRepository.Create(Nil);
   try
     ManifestSL:=TStringList.Create;
     ManifestSL.Add(ManifestFileName);
@@ -564,7 +644,7 @@ begin
   X:=TFPXMLRepositoryHandler.Create;
   With X do
     try
-      SaveToXml(CurrentRepository,'packages.xml');
+      SaveToXml(InstalledRepository,'packages.xml');
     finally
       Free;
     end;