Jelajahi Sumber

Merged revisions 10348,10352-10356,10358-10360,10364-10366,10369-10370,10373-10374,10376-10381,10387-10391,10393-10394,10398,10400,10402-10403,10423,10427,10430,10436,10441,10444-10446,10452,10472,10477,10486,10489-10491,10503,10507,10509-10515,10522,10525-10527,10530-10531,10534,10537-10540,10543,10547,10553,10555,10561-10563,10565-10566,10570,10592-10596,10606,10610 via svnmerge from
svn+ssh://svn.freepascal.org/FPC/svn/fpc/trunk

........
r10348 | Almindor | 2008-02-17 18:04:15 +0100 (Sun, 17 Feb 2008) | 1 line

* fix aspell runtime error in windows if no library (register keys) are present
........
r10394 | peter | 2008-02-26 23:46:42 +0100 (Tue, 26 Feb 2008) | 3 lines

* basic work for checksum on packages to detect if recompile
is needed. Checksum is currently based on the system time
........
r10402 | michael | 2008-02-28 19:22:12 +0100 (Thu, 28 Feb 2008) | 1 line

* Patch from Laurent ([email protected]) to read CMYK files
........
r10427 | peter | 2008-03-02 16:01:08 +0100 (Sun, 02 Mar 2008) | 2 lines

* fixed char constant to formal const
........
r10477 | michael | 2008-03-12 22:08:12 +0100 (Wed, 12 Mar 2008) | 1 line

* Fixed bug in decodesoundexint
........
r10486 | peter | 2008-03-13 22:07:19 +0100 (Thu, 13 Mar 2008) | 3 lines

* simplify compile states
* fix recursive dependency check
........
r10543 | marco | 2008-03-23 19:34:26 +0100 (Sun, 23 Mar 2008) | 2 lines

* fix for 10865
........
r10561 | peter | 2008-03-25 18:14:39 +0100 (Tue, 25 Mar 2008) | 2 lines

* try to compile targets only in neutral state
........
r10562 | peter | 2008-03-25 18:15:26 +0100 (Tue, 25 Mar 2008) | 2 lines

* only parse checksum when available
........
r10563 | peter | 2008-03-25 18:15:41 +0100 (Tue, 25 Mar 2008) | 2 lines

* regenerated
........
r10566 | michael | 2008-03-26 16:33:24 +0100 (Wed, 26 Mar 2008) | 1 line

* Patch for arithmetic overflow from Petr Kristan
........
r10592 | peter | 2008-04-01 23:24:24 +0200 (Tue, 01 Apr 2008) | 2 lines

* avr, armeb added
........
r10593 | peter | 2008-04-01 23:26:20 +0200 (Tue, 01 Apr 2008) | 2 lines

* fixed previous commit
........
r10594 | peter | 2008-04-02 00:32:55 +0200 (Wed, 02 Apr 2008) | 2 lines

* regenerated
........
r10595 | peter | 2008-04-02 00:39:20 +0200 (Wed, 02 Apr 2008) | 10 lines

* detect broken packages, give an error if broken packages are found and the user
needs to run 'fppkg fixbroken' first
* add --broken option to skip the broken package detection at startup
* call fixbroken implicitly after an install command from the commandline has been processed.
This will make sure that all packages depending on the installed package will also be recompiled
and reinstalled.
Warning: Installing a new rtl will recompile everything. Currently this will
give a broken installation because not all packages compile yet.
........
r10596 | peter | 2008-04-02 00:39:52 +0200 (Wed, 02 Apr 2008) | 2 lines

* include fix fixes
........
r10610 | peter | 2008-04-06 23:00:24 +0200 (Sun, 06 Apr 2008) | 4 lines

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

git-svn-id: branches/fixes_2_2@10773 -

michael 17 tahun lalu
induk
melakukan
e8e4e090a5

+ 6 - 5
packages/aspell/src/aspell.pp

@@ -1013,7 +1013,6 @@ uses
 
 var
   LibHandle: TLibHandle = 0;
-  AspellInited_: Boolean;
 
 {$IFDEF WINDOWS}
 function RegistryQueryValue (name,sub:shortstring):shortstring;
@@ -1057,10 +1056,12 @@ begin
   
   {$IFDEF windows}
   bversion := RegistryQueryValue('SOFTWARE\Aspell','AspellVersion');
-  move(bversion[1], version, 4);
-  path := RegistryQueryValue('SOFTWARE\Aspell','Path');
-  // will work if they passed %s, won't bork if they passed absolute
-  libname := path + PathDelim + StringReplace(libn, '%s', IntToStr(Version), [rfReplaceAll]);
+  if Length(bversion) >= 4 then begin
+    move(bversion[1], version, 4);
+    path := RegistryQueryValue('SOFTWARE\Aspell','Path');
+    // will work if they passed %s, won't bork if they passed absolute
+    libname := path + PathDelim + StringReplace(libn, '%s', IntToStr(Version), [rfReplaceAll]);
+  end;
   {$ENDIF}
 
   LibHandle := LoadLibrary(libname);

+ 1 - 0
packages/fcl-base/src/contnrs.pp

@@ -1280,6 +1280,7 @@ begin
       FHashList := nil;
     end;
   SetHashCapacity(1);
+  FHashTable^[0]:=longword(-1); // sethashcapacity does not always call rehash
   if Assigned(FStrs) then
     begin
       FStrCount:=0;

+ 22 - 0
packages/fcl-image/src/fpreadjpeg.pas

@@ -201,6 +201,19 @@ var
     end;
   end;
 
+  function CorrectCMYK(const C: TFPColor): TFPColor;
+  var
+    MinColor: word;
+  begin
+    if C.red<C.green then MinColor:=C.red
+    else MinColor:= C.green;
+    if C.blue<MinColor then MinColor:= C.blue;
+    if MinColor+ C.alpha>$FF then MinColor:=$FF-C.alpha;
+    Result.red:=(C.red-MinColor) shl 8;
+    Result.green:=(C.green-MinColor) shl 8;
+    Result.blue:=(C.blue-MinColor) shl 8;
+    Result.alpha:=alphaOpaque;
+  end;
   procedure ReadPixels;
   var
     Continue: Boolean;
@@ -231,6 +244,15 @@ var
       while (FInfo.output_scanline < FInfo.output_height) do begin
         LinesRead := jpeg_read_scanlines(@FInfo, SampArray, 1);
         if LinesRead<1 then break;
+        if (FInfo.jpeg_color_space = JCS_CMYK) then
+        for x:=0 to FInfo.output_width-1 do begin
+          Color.Red:=SampRow^[x*4+0];
+          Color.Green:=SampRow^[x*4+1];
+          Color.Blue:=SampRow^[x*4+2];
+          Color.alpha:=SampRow^[x*4+3];
+          Img.Colors[x,y]:=CorrectCMYK(Color);
+        end
+        else
         for x:=0 to FInfo.output_width-1 do begin
           Color.Red:=SampRow^[x*3+0] shl 8;
           Color.Green:=SampRow^[x*3+1] shl 8;

+ 8 - 4
packages/fcl-image/src/pscanvas.pp

@@ -218,11 +218,13 @@ Resourcestring
 { TPostScriptCanvas ----------------------------------------------------------}
 
 Procedure TPostScriptCanvas.WritePS(const Cmd : String);
-
+var
+  ss : shortstring;
 begin
   If length(Cmd)>0 then
     FStream.Write(Cmd[1],Length(Cmd));
-  FStream.Write(LineEnding,SizeOf(LineEnding));
+  ss:=LineEnding;
+  FStream.Write(ss[1],Length(ss));
 end;
 
 Procedure TPostScriptCanvas.WritePS(Const Fmt : String; Args : Array of Const);
@@ -586,11 +588,13 @@ begin
 end;
 
 Procedure TPostScript.WritePS(const Cmd : String);
-
+var
+  ss : shortstring;
 begin
   If length(Cmd)>0 then
     FStream.Write(Cmd[1],Length(Cmd));
-  FStream.Write(LineEnding,SizeOf(LineEnding));
+  ss:=LineEnding;
+  FStream.Write(ss[1],Length(ss));
 end;
 
 Procedure TPostScript.WritePS(Const Fmt : String; Args : Array of Const);

+ 178 - 167
packages/fpmkunit/src/fpmkunit.pp

@@ -52,7 +52,7 @@ Type
 
   // Please keep this order, see OSCPUSupported below
   TCpu=(cpuNone,
-    i386,m68k,powerpc,sparc,x86_64,arm,powerpc64
+    i386,m68k,powerpc,sparc,x86_64,arm,powerpc64,avr,armeb
   );
   TCPUS = Set of TCPU;
 
@@ -71,7 +71,7 @@ Type
   TTargetType = (ttProgram,ttUnit,ttImplicitUnit,ttCleanOnlyUnit,ttExampleUnit,ttExampleProgram);
   TTargetTypes = set of TTargetType;
 
-  TTargetState = (tsNeutral,tsNeedCompile,tsNoCompile,tsCompiling,tsCompiled,tsInstalled,tsNotFound);
+  TTargetState = (tsNeutral,tsConsidering,tsNoCompile,tsCompiled,tsInstalled,tsNotFound);
   TTargetStates = Set of TTargetState;
 
   TSourceType = (stDoc,stSrc,stExample,stTest);
@@ -109,35 +109,35 @@ Const
 
   { This table is kept OS,Cpu because it is easier to maintain (PFV) }
   OSCPUSupported : array[TOS,TCpu] of boolean = (
-    { os          none   i386   m68k   ppc    sparc  x86_64 arm    ppc64}
-    { none  }   ( false, false, false, false, false, false, false, false),
-    { linux }   ( false, true,  true,  true,  true,  true,  true,  true ),
-    { go32v2 }  ( false, true,  false, false, false, false, false, false),
-    { win32 }   ( false, true,  false, false, false, false, false, false),
-    { os2 }     ( false, true,  false, false, false, false, false, false),
-    { freebsd } ( false, true,  true,  false, false, true,  false, false),
-    { beos }    ( false, true,  false, false, false, false, false, false),
-    { netbsd }  ( false, false, false, false, false, false, false, false),
-    { amiga }   ( false, false, true,  true,  false, false, false, false),
-    { atari }   ( false, false, false, false, false, false, false, false),
-    { solaris } ( false, true,  false, false, true,  false, false, false),
-    { qnx }     ( false, false, false, false, false, false, false, false),
-    { netware } ( false, true,  false, false, false, false, false, false),
-    { openbsd } ( false, false, false, false, false, false, false, false),
-    { wdosx }   ( false, true,  false, false, false, false, false, false),
-    { palmos }  ( false, false, true,  false, false, false, true,  false),
-    { macos }   ( false, false, false, true,  false, false, false, false),
-    { darwin }  ( false, true,  false, true,  false, true,  false, true ),
-    { emx }     ( false, true,  false, false, false, false, false, false),
-    { watcom }  ( false, true,  false, false, false ,false, false, false),
-    { morphos } ( false, false, false, true,  false ,false, false, false),
-    { netwlibc }( false, true,  false, false, false, false, false, false),
-    { win64   } ( false, false, false, false, false, true,  false, false),
-    { wince    }( false, true,  false, false, false, false, true,  false),
-    { gba    }  ( false, false, false, false, false, false, true,  false),
-    { nds    }  ( false, false, false, false, false, false, true,  false),
-    { embedded }( false, false, false, false, false, false, true,  false),
-    { symbian } ( false, true,  false, false, false, false, true,  false)
+    { os          none   i386    m68k  ppc    sparc  x86_64 arm    ppc64  avr    armeb}
+    { none }    ( false, false, false, false, false, false, false, false, false, false),
+    { linux }   ( false, true,  true,  true,  true,  true,  true,  true,  false, true ),
+    { go32v2 }  ( false, true,  false, false, false, false, false, false, false, false),
+    { win32 }   ( false, true,  false, false, false, false, false, false, false, false),
+    { os2 }     ( false, true,  false, false, false, false, false, false, false, false),
+    { freebsd } ( false, true,  true,  false, false, true,  false, false, false, false),
+    { beos }    ( false, true,  false, false, false, false, false, false, false, false),
+    { netbsd }  ( false, true,  true,  true,  true,  false, false, false, false, false),
+    { amiga }   ( false, false, true,  true,  false, false, false, false, false, false),
+    { atari }   ( false, false, true,  false, false, false, false, false, false, false),
+    { solaris } ( false, true,  false, false, true,  false, false, false, false, false),
+    { qnx }     ( false, true,  false, false, false, false, false, false, false, false),
+    { netware } ( false, true,  false, false, false, false, false, false, false, false),
+    { openbsd } ( false, true,  true,  false, false, false, false, false, false, false),
+    { wdosx }   ( false, true,  false, false, false, false, false, false, false, false),
+    { palmos }  ( false, false, true,  false, false, false, true,  false, false, false),
+    { macos }   ( false, false, false, true,  false, false, false, false, false, false),
+    { darwin }  ( false, true,  false, true,  false, true,  true,  true,  false, false),
+    { emx }     ( false, true,  false, false, false, false, false, false, false, false),
+    { watcom }  ( false, true,  false, false, false ,false, false, false, false, false),
+    { morphos } ( false, false, false, true,  false ,false, false, false, false, false),
+    { netwlibc }( false, true,  false, false, false, false, false, false, false, false),
+    { win64   } ( false, false, false, false, false, true,  false, false, false, false),
+    { wince    }( false, true,  false, false, false, false, true,  false, false, false),
+    { gba    }  ( false, false, false, false, false, false, true,  false, false, false),
+    { nds    }  ( false, false, false, false, false, false, true,  false, false, false),
+    { embedded }( false, true,  true,  true,  true,  true,  true,  true,  true,  true ),
+    { symbian } ( false, true,  false, false, false, false, true,  false, false, false)
   );
 
   // Useful
@@ -308,6 +308,7 @@ Type
     // Package, Unit
     FTarget : TObject;
     FVersion : TFPVersion;
+    FRequireChecksum : Cardinal;
     // Filenames, Includes
     FTargetFileName : String;
     Function GetVersion : string;
@@ -319,6 +320,7 @@ Type
     Property DependencyType : TDependencyType Read FDependencyType;
     Property TargetFileName : String Read FTargetFileName Write FTargetFileName;
     Property Version : String Read GetVersion Write SetVersion;
+    Property RequireChecksum : Cardinal Read FRequireChecksum Write FRequireChecksum;
   end;
 
   TDependencies = Class(TConditionalStrings)
@@ -524,6 +526,7 @@ Type
     FCommands : TCommands;
     FDescriptionFile : String;
     FDescription : String;
+    FInstalledChecksum : Cardinal;
     // Cached directory of installed packages
     FUnitDir : String;
     Function GetDescription : string;
@@ -552,6 +555,7 @@ Type
     Property Directory : String Read FDirectory Write FDirectory;
     Property Description : String Read GetDescription Write FDescription;
     Property DescriptionFile : String Read FDescriptionFile Write FDescriptionFile;
+    Property InstalledChecksum : Cardinal Read FInstalledChecksum Write FInstalledChecksum;
     // Compiler options.
     Property OSes : TOSes Read FOSes Write FOSes;
     Property CPUs : TCPUs Read FCPUs Write FCPUs;
@@ -957,6 +961,7 @@ ResourceString
   SErrInvalidFPCInfo    = 'Compiler returns invalid information, check if fpc -iV works';
   SErrDependencyNotFound = 'Could not find unit directory for dependency package "%s"';
   SErrAlreadyInitialized = 'Installer can only be initialized once';
+  SErrInvalidState      = 'Invalid state for target %s';
 
   SWarnCircularTargetDependency = 'Warning: Circular dependency detected when compiling target %s with target %s';
   SWarnCircularPackageDependency = 'Warning: Circular dependency detected when compiling package %s with package %s';
@@ -1006,6 +1011,7 @@ ResourceString
   SDbgArchivingFile         = 'Archiving "%s"';
   SDbgSearchPath            = 'Using %s path "%s"';
   SDbgEnterDir              = 'Entering directory "%s"';
+  SDbgPackageChecksumChanged = 'Dependent package %s is modified';
 
   // Help messages for usage
   SValue              = 'Value';
@@ -1058,6 +1064,7 @@ Const
   // Keys for unit config
   KeyName     = 'Name';
   KeyVersion  = 'Version';
+  KeyChecksum = 'Checksum';
   KeyNeedLibC = 'NeedLibC';
   KeyDepends  = 'Depends';
 
@@ -1854,6 +1861,7 @@ begin
   FCommands:=TCommands.Create(TCommand);
   FCPUs:=AllCPUs;
   FOSes:=AllOSes;
+  FInstalledChecksum:=$ffffffff;
   // Implicit dependency on RTL
   FDependencies.Add('rtl');
 end;
@@ -2064,7 +2072,10 @@ var
   L,L2 : TStrings;
   VOS : TOS;
   VCPU : TCPU;
-  i : Integer;
+  i,k : Integer;
+  DepChecksum : Cardinal;
+  DepName : String;
+  D : TDependency;
 begin
   L:=TStringList.Create;
   Try
@@ -2072,6 +2083,7 @@ begin
     With L do
       begin
         Version:=Values[KeyVersion];
+        InstalledChecksum:=Cardinal(StrToInt64Def(Values[KeyChecksum],$ffffffff));
         VCPU:=StringToCPU(Values[KeyCPU]);
         VOS:=StringToOS(Values[KeyOS]);
         OSes:=[VOS];
@@ -2079,7 +2091,19 @@ begin
         L2:=TStringList.Create;
         L2.CommaText:=Values[KeyDepends];
         for i:=0 to L2.Count-1 do
-          Dependencies.Add(L2[i],CPUs,OSes);
+          begin
+            DepName:=L2[i];
+            k:=Pos('|',DepName);
+            if k>0 then
+              begin
+                DepChecksum:=StrToInt(Copy(DepName,k+1,Length(DepName)-k));
+                DepName:=Copy(DepName,1,k-1);
+              end
+            else
+              DepChecksum:=$ffffffff;
+            D:=Dependencies.Add(DepName,CPUs,OSes);
+            D.RequireChecksum:=DepChecksum;
+          end;
         FreeAndNil(L2);
         NeedLibC:=Upcase(Values[KeyNeedLibC])='Y';
       end;
@@ -2096,6 +2120,7 @@ Var
   Deps : String;
   i : integer;
   D : TDependency;
+  p : TPackage;
 begin
   F:=TFileStream.Create(AFileName,fmCreate);
   L:=TStringList.Create;
@@ -2104,6 +2129,8 @@ begin
       begin
         Values[KeyName]:=Name;
         Values[KeyVersion]:=Version;
+        // TODO Generate checksum based on PPUs
+        Values[KeyChecksum]:=IntToStr(DateTimeToFileDate(Now));
         Values[KeyCPU]:=CPUToString(ACPU);
         Values[KeyOS]:=OSToString(AOS);
         Deps:='';
@@ -2112,10 +2139,12 @@ begin
             D:=Dependencies[i];
             if (ACPU in D.CPUs) and (AOS in D.OSes) then
               begin
-                if Deps='' then
-                  Deps:=D.Value
-                else
-                  Deps:=Deps+','+D.Value;
+                if Deps<>'' then
+                  Deps:=Deps+',';
+                Deps:=Deps+D.Value;
+                P:=TPackage(D.Target);
+                if assigned(P) and (P.InstalledChecksum<>$ffffffff) then
+                  Deps:=Deps+'|'+IntToStr(P.InstalledChecksum);
               end;
           end;
         Values[KeyDepends]:=Deps;
@@ -3637,17 +3666,6 @@ Var
   OD,OFN : String;
 begin
   Result:=False;
-  case ATarget.State of
-    tsNeedCompile :
-      begin
-        result:=true;
-        exit;
-      end;
-    tsNoCompile,
-    tsCompiling,
-    tsCompiled :
-      exit;
-  end;
 
   // Forced recompile?
   if FForceCompile then
@@ -3693,7 +3711,7 @@ begin
                       Error(SErrDepUnknownTarget,[ATarget.Name,D.Value]);
                     // If a dependent package is compiled we always need to recompile
                     Log(vldebug, SDbgDependencyOnUnit, [ATarget.Name,T.Name]);
-                    Result:=(T.State in [tsNeedCompile,tsCompiling,tsCompiled]) or NeedsCompile(APackage,T);
+                    Result:=(T.State=tsCompiled);
                     if Result then
                       Log(vldebug, SDbgDependencyUnitRecompiled, [T.Name]);
                   end;
@@ -3709,14 +3727,8 @@ begin
         end;
     end;
 
-  // Upate also target state so a second check is faster
   if result then
-    begin
-      ATarget.FTargetState:=tsNeedCompile;
-      Log(vlDebug,SDbgMustCompile,[ATarget.Name]);
-    end
-  else
-    ATarget.FTargetState:=tsNoCompile;
+    Log(vlDebug,SDbgMustCompile,[ATarget.Name]);
 end;
 
 
@@ -3724,24 +3736,17 @@ procedure TBuildEngine.Compile(APackage: TPackage; ATarget: TTarget);
 Var
   S : String;
 begin
-  if ATarget.State in [tsNeutral,tsNeedCompile] then
-    begin
-      Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]);
-      LogIndent;
-      ATarget.FTargetState:=tsCompiling;
-      ExecuteCommands(ATarget.Commands,caBeforeCompile);
-      If Assigned(ATarget.BeforeCompile) then
-        ATarget.BeforeCompile(ATarget);
-      S:=GetCompilerCommand(APackage,ATarget);
-      ExecuteCommand(GetCompiler,S);
-      If Assigned(ATarget.AfterCompile) then
-        ATarget.AfterCompile(ATarget);
-      ExecuteCommands(ATarget.Commands,caAfterCompile);
-      ATarget.FTargetState:=tsCompiled;
-      LogUnIndent;
-    end
-  else if ATarget.State<>tsCompiled then
-    Log(vlWarning, Format(SWarnAttemptingToCompileNonNeutralTarget, [ATarget.Name]));
+  Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]);
+  LogIndent;
+  ExecuteCommands(ATarget.Commands,caBeforeCompile);
+  If Assigned(ATarget.BeforeCompile) then
+    ATarget.BeforeCompile(ATarget);
+  S:=GetCompilerCommand(APackage,ATarget);
+  ExecuteCommand(GetCompiler,S);
+  If Assigned(ATarget.AfterCompile) then
+    ATarget.AfterCompile(ATarget);
+  ExecuteCommands(ATarget.Commands,caAfterCompile);
+  LogUnIndent;
 end;
 
 
@@ -3751,8 +3756,6 @@ Var
   T : TTarget;
   D : TDependency;
 begin
-  if ATarget.State in [tsCompiled,tsCompiling,tsNoCompile] then
-    exit;
   Log(vlDebug, Format(SDbgCompilingDependenciesOfTarget, [ATarget.Name]));
   LogIndent;
   For I:=0 to ATarget.Dependencies.Count-1 do
@@ -3770,9 +3773,12 @@ begin
                   // used for dependency checking
                   if (T.TargetType<>ttImplicitUnit) then
                     begin
-                      if T.State=tsCompiling then
-                        Log(vlWarning,SWarnCircularTargetDependency,[ATarget.Name,T.Name]);
-                      MaybeCompile(APackage,T);
+                      case T.State of
+                        tsNeutral :
+                          MaybeCompile(APackage,T);
+                        tsConsidering :
+                          Log(vlWarning,SWarnCircularTargetDependency,[ATarget.Name,T.Name]);
+                      end;
                     end;
                 end
               else
@@ -3788,14 +3794,20 @@ end;
 
 procedure TBuildEngine.MaybeCompile(APackage: TPackage; ATarget: TTarget);
 begin
-  if not(ATarget.State in [tsNeutral,tsNeedCompile]) then
-    exit;
+  if ATarget.State<>tsNeutral then
+    Error(SErrInvalidState,[ATarget.Name]);
   Log(vlDebug, Format(SDbgConsideringTarget, [ATarget.Name]));
   LogIndent;
+  ATarget.FTargetState:=tsConsidering;
   ResolveDependencies(ATarget.Dependencies,ATarget.Collection as TTargets);
   CompileDependencies(APackage, ATarget);
   if NeedsCompile(APackage, ATarget) then
-    Compile(APackage,ATarget);
+    begin
+      Compile(APackage,ATarget);
+      ATarget.FTargetState:=tsCompiled;
+    end
+  else
+    ATarget.FTargetState:=tsNoCompile;
   LogUnIndent;
 end;
 
@@ -3807,19 +3819,6 @@ Var
   D : TDependency;
 begin
   Result:=False;
-  case APackage.State of
-    tsNeedCompile :
-      begin
-        result:=true;
-        exit;
-      end;
-    tsNoCompile,
-    tsNotFound,
-    tsCompiling,
-    tsCompiled,
-    tsInstalled :
-      exit;
-  end;
 
   // Forced recompile?
   if FForceCompile then
@@ -3836,11 +3835,9 @@ begin
               (Defaults.CPU in D.CPUs) and (Defaults.OS in D.OSes) then
              begin
                P:=TPackage(D.Target);
-               if Assigned(P) and (P<>APackage) then
+               if Assigned(P) then
                  begin
-                   If (P.State in [tsCompiling,tsNeedCompile]) then
-                     Log(vlWarning,SWarnCircularPackageDependency,[APackage.Name,P.Name]);
-                   Result:=(P.State in [tsCompiled,tsCompiling,tsNeedCompile]);
+                   Result:=(P.State=tsCompiled);
                    if Result then
                      break;
                  end;
@@ -3866,70 +3863,8 @@ begin
       end;
     end;
 
-  // Upate also target state so a second check is faster
   if result then
-    begin
-      APackage.FTargetState:=tsNeedCompile;
-      Log(vlDebug,SDbgMustCompile,[APackage.Name]);
-    end
-  else
-    APackage.FTargetState:=tsNoCompile;
-end;
-
-
-procedure TBuildEngine.Compile(APackage: TPackage);
-Var
-  T : TTarget;
-  I : Integer;
-begin
-  Try
-    Log(vlInfo,SInfoCompilingPackage,[APackage.Name]);
-    APackage.FTargetState:=tsCompiling;
-    If (APackage.Directory<>'') then
-      EnterDir(APackage.Directory);
-    CreateOutputDir(APackage);
-    Dictionary.AddVariable('UNITSOUTPUTDIR',APackage.GetUnitsOutputDir(Defaults.CPU,Defaults.OS));
-    Dictionary.AddVariable('BINOUTPUTDIR',APackage.GetBinOutputDir(Defaults.CPU,Defaults.OS));
-    DoBeforeCompile(APackage);
-    For I:=0 to APackage.Targets.Count-1 do
-      begin
-        T:=APackage.Targets.TargetItems[i];
-        if (T.TargetType in [ttUnit,ttProgram]) then
-          begin
-            if TargetOK(T) then
-              MaybeCompile(APackage,T)
-            else
-              begin
-                if not(Defaults.CPU in T.CPUs) then
-                  Log(vldebug, Format(SDbgSkippingTargetWrongCPU, [T.Name, CPUsToString(T.CPUs)]));
-                if not(Defaults.OS in T.OSes) then
-                  Log(vldebug, Format(SDbgSkippingTargetWrongOS, [T.Name, OSesToString(T.OSes)]));
-              end;
-          end
-        else
-          log(vldebug, SDbgTargetIsNotAUnitOrProgram,[T.Name]);
-      end;
-    DoAfterCompile(APackage);
-    APackage.FTargetState:=tsCompiled;
-  Finally
-    If (APackage.Directory<>'') then
-      EnterDir('');
-  end;
-end;
-
-
-procedure TBuildEngine.MaybeCompile(APackage: TPackage);
-begin
-  if not(APackage.State in [tsNeutral,tsNeedCompile]) then
-    exit;
-  Log(vlDebug,SDbgConsideringPackage,[APackage.Name]);
-  LogIndent;
-  ResolveDependencies(APackage.Dependencies,(APackage.Collection as TPackages));
-  CompileDependencies(APackage);
-  ResolveFileNames(APackage,Defaults.CPU,Defaults.OS);
-  If NeedsCompile(APackage) then
-    Compile(APackage);
-  LogUnIndent;
+    Log(vlDebug,SDbgMustCompile,[APackage.Name]);
 end;
 
 
@@ -3982,16 +3917,92 @@ begin
          (Defaults.CPU in D.CPUs) and (Defaults.OS in D.OSes) then
         begin
           P:=TPackage(D.Target);
-          // If it already was compiled, then State<>tsNeutral, and it won't be compiled again.
-          If Assigned(P) and (P<>APackage) then
-            MaybeCompile(P)
+          If Assigned(P) then
+            begin
+              case P.State of
+                tsNeutral :
+                  MaybeCompile(P);
+                tsConsidering :
+                  Log(vlWarning,SWarnCircularPackageDependency,[APackage.Name,P.Name]);
+              end;
+            end
           else
-            D.Target:=CheckExternalPackage(D.Value);
+            begin
+              D.Target:=CheckExternalPackage(D.Value);
+              P:=TPackage(D.Target);
+            end;
+          if (D.RequireChecksum<>$ffffffff) and
+             (P.InstalledChecksum<>$ffffffff) and
+             (P.InstalledChecksum<>D.RequireChecksum) then
+            Log(vlDebug,SDbgPackageChecksumChanged,[P.Name]);
         end;
     end;
 end;
 
 
+procedure TBuildEngine.Compile(APackage: TPackage);
+Var
+  T : TTarget;
+  I : Integer;
+begin
+  Try
+    Log(vlInfo,SInfoCompilingPackage,[APackage.Name]);
+    If (APackage.Directory<>'') then
+      EnterDir(APackage.Directory);
+    CreateOutputDir(APackage);
+    Dictionary.AddVariable('UNITSOUTPUTDIR',APackage.GetUnitsOutputDir(Defaults.CPU,Defaults.OS));
+    Dictionary.AddVariable('BINOUTPUTDIR',APackage.GetBinOutputDir(Defaults.CPU,Defaults.OS));
+    DoBeforeCompile(APackage);
+    For I:=0 to APackage.Targets.Count-1 do
+      begin
+        T:=APackage.Targets.TargetItems[i];
+        if (T.TargetType in [ttUnit,ttProgram]) then
+          begin
+            if TargetOK(T) then
+              begin
+                if T.State=tsNeutral then
+                  MaybeCompile(APackage,T);
+              end
+            else
+              begin
+                if not(Defaults.CPU in T.CPUs) then
+                  Log(vldebug, Format(SDbgSkippingTargetWrongCPU, [T.Name, CPUsToString(T.CPUs)]));
+                if not(Defaults.OS in T.OSes) then
+                  Log(vldebug, Format(SDbgSkippingTargetWrongOS, [T.Name, OSesToString(T.OSes)]));
+              end;
+          end
+        else
+          log(vldebug, SDbgTargetIsNotAUnitOrProgram,[T.Name]);
+      end;
+    DoAfterCompile(APackage);
+  Finally
+    If (APackage.Directory<>'') then
+      EnterDir('');
+  end;
+end;
+
+
+procedure TBuildEngine.MaybeCompile(APackage: TPackage);
+begin
+  if APackage.State<>tsNeutral then
+    Error(SErrInvalidState,[APackage.Name]);
+  Log(vlDebug,SDbgConsideringPackage,[APackage.Name]);
+  LogIndent;
+  APackage.FTargetState:=tsConsidering;
+  ResolveDependencies(APackage.Dependencies,(APackage.Collection as TPackages));
+  CompileDependencies(APackage);
+  ResolveFileNames(APackage,Defaults.CPU,Defaults.OS);
+  If NeedsCompile(APackage) then
+    begin
+      Compile(APackage);
+      APackage.FTargetState:=tsCompiled;
+    end
+  else
+    APackage.FTargetState:=tsNoCompile;
+  LogUnIndent;
+end;
+
+
 Function TBuildEngine.InstallPackageFiles(APAckage : TPackage; tt : TTargetType; Const Dest : String):Boolean;
 Var
   List : TStringList;
@@ -4033,7 +4044,7 @@ Var
   B : Boolean;
 begin
   If (Apackage.State<>tsCompiled) then
-    Compile(APackage);
+    MaybeCompile(APackage);
   try
     Log(vlInfo,SInfoInstallingPackage,[APackage.Name]);
     If (APackage.Directory<>'') then

+ 35 - 24
rtl/fpmake.pp

@@ -28,7 +28,7 @@ begin
     P.SourcePath.Add('objpas');
 
     // Where to find the include files using firstmatch
-    P.IncludePath.Add('$(OS)/$(CPU)',[Linux]+AllBSDOSes);
+    P.IncludePath.Add('$(OS)/$(CPU)',AllUnixOSes);
     P.IncludePath.Add('$(OS)');
     P.IncludePath.Add('$(CPU)');
     P.IncludePath.Add('bsd',AllBSDOSes);
@@ -55,6 +55,7 @@ begin
           AddInclude('varianth.inc');
           AddInclude('sysosh.inc');
           AddInclude('resh.inc');
+          AddInclude('currh.inc');
           // Implementations
           AddInclude('set.inc');
           AddInclude('int64p.inc');
@@ -63,6 +64,7 @@ begin
           AddInclude('sysheap.inc');
           AddInclude('sysdir.inc');
           AddInclude('sysfile.inc');
+          AddInclude('sysres.inc');
           AddInclude('except.inc');
           AddInclude('threadvr.inc');
           AddInclude('filerec.inc');
@@ -70,6 +72,7 @@ begin
           AddInclude('generic.inc');
           AddInclude('genset.inc');
           AddInclude('genmath.inc');
+          AddInclude('gencurr.inc');
           AddInclude('sstrings.inc');
           AddInclude('int64.inc');
           AddInclude('astrings.inc');
@@ -88,7 +91,7 @@ begin
           AddInclude('innr.inc');
           AddInclude('$(CPU).inc');
           AddInclude('fastmove.inc',[i386],AllOSes);
-          AddInclude('strpas.inc');
+          AddInclude('strpas.inc',[i386,powerpc,powerpc64],AllOSes);
           AddInclude('math.inc');
           AddInclude('real2str.inc');
           AddInclude('systhrd.inc',AllWindowsOSes+[Netware,Netwlibc,EMX,OS2]);
@@ -103,12 +106,12 @@ begin
           AddInclude('ctypes.inc',AllUnixOSes);
           AddInclude('stat.inc',[Linux]);
           AddInclude('signal.inc',AllUnixOSes);
-          AddInclude('sighnd.inc',AllUnixOSes);
-          AddInclude('sighndh.inc',AllUnixOSes);
+          AddInclude('sighnd.inc',AllUnixOSes-[Beos]);
+          AddInclude('sighndh.inc',[Linux,Solaris]);
           AddInclude('syscallh.inc',[Linux,Beos,FreeBSD]);
           AddInclude('syscall.inc',[Linux,Beos,FreeBSD]);
           AddInclude('sysnr.inc',[Linux,Beos,FreeBSD]);
-          AddInclude('ossysc.inc',AllUnixOSes);
+          AddInclude('ossysc.inc',AllUnixOSes-[Solaris]);
           AddInclude('osmacro.inc',AllUnixOSes);
           // Windows implementations
           AddInclude('winres.inc',AllWindowsOSes);
@@ -144,7 +147,7 @@ begin
           AddInclude('ostypes.inc');
           AddInclude('stat.inc',[Linux]);
           AddInclude('signal.inc');
-          AddInclude('sighndh.inc');
+          AddInclude('sighndh.inc',[Linux,Solaris]);
           AddInclude('bunxh.inc');
           AddInclude('bunxovlh.inc');
           AddInclude('genfunch.inc');
@@ -153,8 +156,8 @@ begin
           AddInclude('genfdset.inc');
           AddInclude('syscallh.inc',[Linux,Beos,FreeBSD]);
           AddInclude('sysnr.inc',[Linux,Beos,FreeBSD]);
-          AddInclude('bsyscall.inc',[Linux,Beos,FreeBSD]);
-          AddInclude('bunxsysc.inc',[Linux,Beos,FreeBSD]);
+          AddInclude('bsyscall.inc',[Linux,FreeBSD]);
+          AddInclude('bunxsysc.inc',[Linux,FreeBSD]);
           AddInclude('settimeo.inc');
           AddInclude('osmacro.inc');
           AddInclude('bunxovl.inc');
@@ -169,11 +172,11 @@ begin
           AddInclude('aliasptp.inc');
           AddInclude('aliasctp.inc');
           AddInclude('unxconst.inc');
-          AddInclude('unxsysch.inc');
+          AddInclude('unxsysch.inc',[Linux,FreeBSD]);
+          AddInclude('unxsysc.inc',[Linux,FreeBSD]);
           AddInclude('unxovlh.inc');
           AddInclude('unxovl.inc');
           AddInclude('syscallh.inc',[Linux,Beos,FreeBSD]);
-          AddInclude('unxsysc.inc',[Linux,Beos,FreeBSD]);
           AddInclude('textrec.inc');
           AddInclude('filerec.inc');
           AddInclude('unxfunc.inc');
@@ -189,11 +192,17 @@ begin
           AddInclude('termiosproc.inc');
         end;
     T:=P.Targets.AddUnit('unix/errors.pp',AllUnixOSes);
-      T.Dependencies.AddUnit('unixtype');
-      T.Dependencies.AddInclude('errnostr.inc');
-    T:=P.Targets.AddUnit('unix/syscall.pp',AllUnixOSes);
-      T.Dependencies.AddInclude('sysnr.inc');
-      T.Dependencies.AddInclude('syscallh.inc');
+      with T.Dependencies do
+        begin
+          AddUnit('unixtype');
+          AddInclude('errnostr.inc');
+        end;
+    T:=P.Targets.AddUnit('unix/syscall.pp',[Linux,Beos,FreeBSD]);
+      with T.Dependencies do
+        begin
+          AddInclude('sysnr.inc');
+          AddInclude('syscallh.inc');
+        end;
     T:=P.Targets.AddUnit('unix/terminfo.pp',AllUnixOSes);
       T.Dependencies.AddUnit('baseunix',AllUnixOSes);
     T:=P.Targets.AddUnit('unix/dl.pp',AllUnixOSes);
@@ -202,7 +211,7 @@ begin
       With T.Dependencies do
         begin
           AddUnit('baseunix');
-          AddUnit('syscall');
+          AddUnit('syscall',[Linux,Beos,FreeBSD]);
           AddInclude('ipccall.inc',[Linux]);
           AddInclude('ipcbsd.inc',[FreeBSD]);
         end;
@@ -294,11 +303,11 @@ begin
         end;
 
     // Windows units
-    T:=P.Targets.AddUnit('sysinitcyg.pp',AllWindowsOSes);
+    T:=P.Targets.AddUnit('sysinitcyg.pp',AllWindowsOSes-[WinCE]);
       T.Dependencies.AddUnit('system');
-    T:=P.Targets.AddUnit('sysinitgprof.pp',AllWindowsOSes);
+    T:=P.Targets.AddUnit('sysinitgprof.pp',AllWindowsOSes-[WinCE]);
       T.Dependencies.AddUnit('system');
-    T:=P.Targets.AddUnit('sysinitpas.pp',AllWindowsOSes);
+    T:=P.Targets.AddUnit('sysinitpas.pp',AllWindowsOSes-[WinCE]);
       T.Dependencies.AddUnit('system');
     T:=P.Targets.AddUnit('windows.pp',AllWindowsOSes);
       T.IncludePath.Add('win/wininc');
@@ -341,7 +350,7 @@ begin
         begin
           AddUnit('windows');
         end;
-    T:=P.Targets.AddUnit('winsysut.pp',AllWindowsOSes);
+    T:=P.Targets.AddUnit('winsysut.pp',AllWindowsOSes-[WinCE]);
       with T.Dependencies do
         begin
           AddUnit('windows');
@@ -352,7 +361,7 @@ begin
         begin
           AddUnit('system');
         end;
-    T:=P.Targets.AddUnit('signals.pp',AllWindowsOSes);
+    T:=P.Targets.AddUnit('signals.pp',[Win32]);
       with T.Dependencies do
         begin
           AddUnit('system');
@@ -475,6 +484,8 @@ begin
           AddUnit('windows',AllWindowsOSes);
           AddInclude('classesh.inc');
           AddInclude('classes.inc');
+          AddInclude('resref.inc');
+          AddInclude('sllist.inc');
           AddInclude('util.inc');
           AddInclude('bits.inc');
           AddInclude('streams.inc');
@@ -554,7 +565,7 @@ begin
           AddUnit('unixtype',AllUnixOSes);
           AddInclude('aliasctp.inc',AllUnixOSes);
         end;
-    T:=P.Targets.AddUnit('initc.pp');
+    T:=P.Targets.AddUnit('initc.pp',AllOSes-[WinCE]);
       T.Dependencies.AddUnit('ctypes');
     T:=P.Targets.AddUnit('cmem.pp');
       T.Dependencies.AddUnit('system');
@@ -660,7 +671,7 @@ begin
            AddInclude('keyscan.inc');
            AddUnit('mouse');
          end;
-    T:=P.Targets.AddUnit('sockets.pp');
+    T:=P.Targets.AddUnit('sockets.pp',AllUnixOSes+AllWindowsOSes+[OS2,MorphOS,Netware,Netwlibc]);
       with T.Dependencies do
         begin
           AddUnit('baseunix',AllUnixOSes);
@@ -672,7 +683,7 @@ begin
           AddInclude('sockovl.inc');
           AddInclude('sockets.inc');
           AddInclude('unxsockh.inc',AllUnixOSes);
-          AddInclude('unixsock.inc',AllUnixOSes);
+          AddInclude('unixsock.inc',AllUnixOSes-[Solaris,Darwin]);
           AddInclude('fpwinsockh.inc',AllWindowsOSes);
         end;
     T:=P.Targets.AddUnit('serial.pp',AllUnixOSes);

+ 5 - 3
rtl/objpas/strutils.pp

@@ -836,9 +836,11 @@ begin
     Result:=Chr(Ord0+(AValue mod 7))+Result;
     AValue:=AValue div 7;
     end;
-  if Len>2 then
-    Result:=IntToStr(AValue mod 26)+Result;
-  AValue:=AValue div 26;
+  if Len>1 then
+    begin
+    Result:=Chr(Ord0+(AValue mod 26))+Result;
+    AValue:=AValue div 26;
+    end;
   Result:=Chr(OrdA+AValue)+Result;
 end;
 

+ 1 - 1
rtl/objpas/sysutils/dati.inc

@@ -75,7 +75,7 @@ end;
 function MSecsToTimeStamp(MSecs: comp): TTimeStamp;
 begin
   result.Date := Trunc(msecs / msecsperday);
-  msecs:= comp(msecs-result.date*msecsperday);
+  msecs:= msecs-comp(result.date)*msecsperday;
   result.Time := Round(MSecs);
 end ;
 

File diff ditekan karena terlalu besar
+ 293 - 287
utils/fppkg/fpmkunitsrc.inc


+ 27 - 19
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;
@@ -245,6 +242,8 @@ begin
         GlobalOptions.InstallGlobal:=true
       else if CheckOption(I,'r','recovery') then
         GlobalOptions.RecoveryMode:=true
+      else if CheckOption(I,'b','broken') then
+        GlobalOptions.AllowBroken:=true
       else if CheckOption(I,'h','help') then
         begin
           ShowUsage;
@@ -273,8 +272,8 @@ procedure TMakeTool.DoRun;
 var
   ActionPackage : TFPPackage;
   OldCurrDir : String;
-  Res    : Boolean;
   i      : Integer;
+  SL     : TStringList;
 begin
   OldCurrDir:=GetCurrentDir;
   Try
@@ -289,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
@@ -304,10 +303,20 @@ begin
     if GlobalOptions.CompilerConfig<>GlobalOptions.FPMakeCompilerConfig then
       FindInstalledPackages(CompilerOptions,true);
 
+    // Check for broken dependencies
+    if not GlobalOptions.AllowBroken and
+       not((ParaPackages.Count=0) and (ParaAction='fixbroken')) then
+      begin
+        SL:=TStringList.Create;
+        if FindBrokenPackages(SL) then
+          Error(SErrBrokenPackagesFound);
+        FreeAndNil(SL);
+      end;
+
     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
@@ -316,23 +325,22 @@ 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 (ParaAction='install') then
+      pkghandler.ExecuteAction('','fixbroken');
+
     Terminate;
 
   except

+ 12 - 96
utils/fppkg/fprepos.pp

@@ -79,6 +79,7 @@ type
     FCPUs : TCPUS;
     FMinVersion: TFPVersion;
     FPackageName: String;
+    FRequireChecksum : cardinal;
     procedure SetMinVersion(const AValue: TFPVersion);
   Public
     Constructor Create(ACollection : TCollection); override;
@@ -91,6 +92,7 @@ type
     Property MinVersion : TFPVersion Read FMinVersion Write SetMinVersion;
     Property OSes : TOSes Read FOSes Write FOses;
     Property CPUs : TCPUs Read FCPUs Write FCPUs;
+    Property RequireChecksum : Cardinal Read FRequireChecksum Write FRequireChecksum;
   end;
 
   { TFPDepencencies }
@@ -116,11 +118,12 @@ type
     FExternalURL: String;
     FFileName: String;
     FVersion: TFPVersion;
-    FInstalledVersion: TFPVersion;
     FDependencies : TFPDependencies;
     FOSes : TOSES;
     FCPUs : TCPUS;
-    FIsLocalPackage : Boolean;
+    // Installation info
+    FChecksum : cardinal;
+    FLocalFileName : String;
     function GetFileName: String;
     procedure SetName(const AValue: String);
     procedure SetVersion(const AValue: TFPVersion);
@@ -130,13 +133,12 @@ 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;
     Property Author : String Read FAuthor Write FAuthor;
     Property Version : TFPVersion Read FVersion Write SetVersion;
-    Property InstalledVersion : TFPVersion Read FInstalledVersion Write FInstalledVersion;
     Property License : String Read FLicense Write FLicense;
     Property Description : String Read FDescription Write FDescription;
     Property ExternalURL : String Read FExternalURL Write FExternalURL;
@@ -144,8 +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 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 }
@@ -189,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;
@@ -479,7 +474,7 @@ constructor TFPPackage.Create(ACollection: TCollection);
 begin
   inherited Create(ACollection);
   FVersion:=TFPVersion.Create;
-  FInstalledVersion:=TFPVersion.Create;
+  FChecksum:=$ffffffff;
   FOSes:=AllOSes;
   FCPUs:=AllCPUs;
   FDependencies:=TFPDependencies.Create(TFPDependency);
@@ -490,7 +485,6 @@ destructor TFPPackage.Destroy;
 begin
   FreeAndNil(FDependencies);
   FreeAndNil(FVersion);
-  FreeAndNil(FInstalledVersion);
   inherited Destroy;
 end;
 
@@ -615,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
@@ -624,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;
@@ -802,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);
@@ -987,6 +902,7 @@ begin
   FMinVersion:=TFPVersion.Create;
   FOSes:=AllOSes;
   FCPUs:=AllCPUs;
+  FRequireChecksum:=$ffffffff;
 end;
 
 

+ 152 - 95
utils/fppkg/pkgcommands.pp

@@ -23,169 +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 }
 
-function TCommandAddConfig.Execute(const Args:TActionArgs):boolean;
+  TCommandFixBroken = Class(TPackagehandler)
+  Public
+    Procedure Execute;override;
+  end;
+
+
+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);
@@ -195,121 +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
+  UFN,S : String;
+  P   : TFPPackage;
 begin
-  if assigned(CurrentPackage) then
-    ExecuteAction(CurrentPackage,'build',Args);
-  ExecuteAction(CurrentPackage,'fpmakeinstall',Args);
-  // Update local status file
-  if assigned(CurrentPackage) then
-    CurrentPackage.InstalledVersion.Assign(CurrentPackage.Version);
-  Result:=true;
+  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
+        UFN:=CompilerOptions.GlobalUnitDir
+      else
+        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;
@@ -317,13 +346,22 @@ begin
               else
                 begin
                   status:='Updating';
-                  L.Add(DepPackage.Name);
+                  L.Add(D.PackageName);
                 end;
             end
           else
-            status:='OK';
+            begin
+              if PackageIsBroken(InstalledP) then
+                begin
+                  status:='Broken, recompiling';
+                  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)]);
@@ -333,12 +371,30 @@ 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;
+
+
+procedure TCommandFixBroken.Execute;
+var
+  i : integer;
+  SL : TStringList;
+begin
+  SL:=TStringList.Create;
+  repeat
+    FindBrokenPackages(SL);
+    if SL.Count=0 then
+      break;
+    for i:=0 to SL.Count-1 do
+      begin
+        ExecuteAction(SL[i],'build');
+        ExecuteAction(SL[i],'install');
+      end;
+  until false;
+  FreeAndNil(SL);
 end;
 
 
@@ -355,4 +411,5 @@ initialization
   RegisterPkgHandler('clean',TCommandClean);
   RegisterPkgHandler('archive',TCommandArchive);
   RegisterPkgHandler('installdependencies',TCommandInstallDependencies);
+  RegisterPkgHandler('fixbroken',TCommandFixBroken);
 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;

+ 42 - 42
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';
@@ -222,7 +223,12 @@ begin
         CreateFPMKUnitSource(TempBuildDir+PathDelim+'fpmkunit.pp');
       // Call compiler
       If ExecuteProcess(FPMakeCompilerOptions.Compiler,OOptions+' '+FPmakeSrc)<>0 then
-        Error(SErrFailedToCompileFPCMake);
+        begin
+          if not GlobalOptions.RecoveryMode then
+            Error(SErrCompileFailureFPMakeTryRecovery)
+          else
+            Error(SErrCompileFailureFPMake);
+        end;
       // Cleanup units
       DeleteDir(TempBuildDir);
     end
@@ -231,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;
 
@@ -256,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
@@ -281,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;
 
 

+ 8 - 2
utils/fppkg/pkgmessages.pp

@@ -26,7 +26,8 @@ Resourcestring
   SErrException              = 'The FPC Package tool encountered the following error:';
   SErrActionAlreadyRegistered= 'Action "%s" is already registered';
   SErrActionNotFound         = 'Action "%s" is not supported';
-  SErrFailedToCompileFPCMake = 'Could not compile fpmake driver program';
+  SErrCompileFailureFPMake   = 'Could not compile fpmake driver program';
+  SErrCompileFailureFPMakeTryRecovery = 'Could not compile fpmake driver program, try adding "--recovery"';
   SErrNoFTPDownload          = 'This binary has no support for FTP downloads.';
   SErrNoHTTPDownload         = 'This binary has no support for HTTP downloads.';
   SErrBackupFailed           = 'Backup of file "%s" to file "%s" failed.';
@@ -47,11 +48,13 @@ Resourcestring
   SErrLoginFailed            = 'FTP LOGIN command failed.';
   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"';
@@ -73,6 +76,7 @@ Resourcestring
   SLogSelectedMirror         = 'Selected mirror "%s"';
   SLogUpgradingConfig        = 'Configuration file "%s" is updated with new configuration settings';
   SLogPackageDependency      = 'Dependency on package %s %s, installed %s, available %s  (%s)';
+  SLogPackageChecksumChanged = 'Package %s needs to be rebuild, dependency %s is modified';
 
   SDbgFound                  = 'Found';
   SDbgNotFound               = 'Not Found';
@@ -81,6 +85,8 @@ Resourcestring
   SDbgBackupFile             = 'Creating Backup File "%s"';
   SDbgPackageMultipleLocations = 'Multiple installations found for package %s, using installation "%s"';
   SDbgPackageDependencyOtherTarget  = 'Dependency on package %s is not for %s';
+  SDbgObsoleteDependency     = 'Obsolete dependency found on package %s';
+
 
 implementation
 

+ 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

+ 3 - 0
utils/fppkg/pkgoptions.pp

@@ -45,6 +45,7 @@ Type
     FFPMakeCompilerConfig : String;
     // Parameter options
     FCompilerConfig : String;
+    FAllowBroken,
     FInstallGlobal,
     FRecoveryMode   : Boolean;
     function  GetOptString(Index: integer): String;
@@ -74,6 +75,7 @@ Type
     Property CompilerConfig : String Read FCompilerConfig Write FCompilerConfig;
     Property InstallGlobal : Boolean Read FInstallGlobal Write FInstallGlobal;
     Property RecoveryMode : Boolean Read FRecoveryMode Write FRecoveryMode;
+    Property AllowBroken : Boolean Read FAllowBroken Write FAllowBroken;
   end;
 
 
@@ -261,6 +263,7 @@ begin
   FCompilerConfig:=FDefaultCompilerConfig;
   FInstallGlobal:=False;
   FRecoveryMode:=False;
+  FAllowBroken:=False;
 end;
 
 

+ 314 - 129
utils/fppkg/pkgrepos.pp

@@ -10,21 +10,27 @@ uses
 
 function GetRemoteRepositoryURL(const AFileName:string):string;
 
-procedure LoadLocalMirrors;
-procedure LoadLocalRepository;
-function  LoadOrCreatePackage(const AName:string):TFPPackage;
-function  LoadPackageManifest(const AManifestFN:string):TFPPackage;
+procedure LoadLocalAvailableMirrors;
+procedure LoadLocalAvailableRepository;
+procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
+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
@@ -42,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;
@@ -60,7 +66,7 @@ begin
     X:=TFPXMLMirrorHandler.Create;
     With X do
       try
-        LoadFromXml(CurrentMirrors,S);
+        LoadFromXml(AvailableMirrors,S);
       finally
         Free;
       end;
@@ -83,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);
@@ -160,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);
@@ -216,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;
@@ -244,29 +198,74 @@ begin
 end;
 
 
+procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
+Var
+  L,DepSL : TStrings;
+  DepName,
+  V : String;
+  DepChecksum : Cardinal;
+  i,j,k : integer;
+  D : TFPDependency;
+begin
+  L:=TStringList.Create;
+  Try
+    ReadIniFile(AFileName,L);
+{$warning TODO Maybe check also CPU-OS}
+    // Read fpunits.conf
+    V:=L.Values['version'];
+    APackage.Version.AsString:=V;
+    V:=L.Values['checksum'];
+    if V<>'' then
+      APackage.Checksum:=StrToInt(V)
+    else
+      APackage.Checksum:=$ffffffff;
+    // Load dependencies
+    V:=L.Values['depends'];
+    DepSL:=TStringList.Create;
+    DepSL.CommaText:=V;
+    for i:=0 to DepSL.Count-1 do
+      begin
+        DepName:=DepSL[i];
+        k:=Pos('|',DepName);
+        if k>0 then
+          begin
+            DepChecksum:=StrToInt(Copy(DepName,k+1,Length(DepName)-k));
+            DepName:=Copy(DepName,1,k-1);
+          end
+        else
+          DepChecksum:=$ffffffff;
+        D:=nil;
+        for j:=0 to APackage.Dependencies.Count-1 do
+          begin
+            D:=APackage.Dependencies[j];
+            if D.PackageName=DepName then
+              break;
+            D:=nil;
+          end;
+        if not assigned(D) then
+          D:=APackage.AddDependency(DepName,'');
+        D.RequireChecksum:=DepChecksum;
+      end;
+    DepSL.Free;
+  Finally
+    L.Free;
+  end;
+end;
+
+
 procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boolean=true);
 
-  procedure LoadUnitConfigFromFile(APackage:TFPPackage;const AFileName: String);
-  Var
-    L : TStrings;
-    V : String;
+  function AddInstalledPackage(const AName,AFileName: String):TFPPackage;
   begin
-    L:=TStringList.Create;
-    Try
-      ReadIniFile(AFileName,L);
-{$warning TODO Maybe check also CPU-OS}
-{$warning TODO Add date to check recompile}
-      V:=L.Values['version'];
-      APackage.InstalledVersion.AsString:=V;
-      // Log packages found in multiple locations (local and global) ?
-      if not APackage.InstalledVersion.Empty then
-        begin
-          if showdups then
-            Log(vlDebug,SDbgPackageMultipleLocations,[APackage.Name,ExtractFilePath(AFileName)]);
-        end;
-    Finally
-      L.Free;
-    end;
+    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,[result.Name,ExtractFilePath(AFileName)]);
+      end;
   end;
 
   procedure LoadPackagefpcFromFile(APackage:TFPPackage;const AFileName: String);
@@ -278,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;
@@ -302,7 +301,7 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
               UF:=UD+UnitConfigFileName;
               if FileExistsLog(UF) then
                 begin
-                  P:=LoadOrCreatePackage(SR.Name);
+                  P:=AddInstalledPackage(SR.Name,UF);
                   LoadUnitConfigFromFile(P,UF)
                 end
               else
@@ -311,7 +310,7 @@ procedure FindInstalledPackages(ACompilerOptions:TCompilerOptions;showdups:boole
                   UF:=UD+'Package.fpc';
                   if FileExistsLog(UF) then
                     begin
-                      P:=LoadOrCreatePackage(SR.Name);
+                      P:=AddInstalledPackage(SR.Name,UF);
                       LoadPackagefpcFromFile(P,UF);
                     end;
                 end;
@@ -321,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
@@ -331,10 +332,58 @@ begin
 end;
 
 
+function PackageIsBroken(APackage:TFPPackage):boolean;
+var
+  j : integer;
+  D : TFPDependency;
+  DepPackage : TFPPackage;
+begin
+  result:=false;
+  for j:=0 to APackage.Dependencies.Count-1 do
+    begin
+      D:=APackage.Dependencies[j];
+      if (CompilerOptions.CompilerOS in D.OSes) and
+         (CompilerOptions.CompilerCPU in D.CPUs) then
+        begin
+          DepPackage:=InstalledRepository.FindPackage(D.PackageName);
+          // Don't stop on missing dependencies
+          if assigned(DepPackage) then
+            begin
+              if (DepPackage.Checksum<>D.RequireChecksum) then
+                begin
+                  Log(vlInfo,SLogPackageChecksumChanged,[APackage.Name,D.PackageName]);
+                  result:=true;
+                  exit;
+                end;
+            end
+          else
+            Log(vlDebug,SDbgObsoleteDependency,[D.PackageName]);
+        end;
+    end;
+end;
+
+
+function FindBrokenPackages(SL:TStrings):Boolean;
+var
+  i : integer;
+  P : TFPPackage;
+begin
+  SL.Clear;
+  for i:=0 to InstalledRepository.PackageCount-1 do
+    begin
+      P:=InstalledRepository.Packages[i];
+      if PackageIsBroken(P) then
+        SL.Add(P.Name);
+    end;
+  Result:=(SL.Count>0);
+end;
+
+
 procedure CheckFPMakeDependencies;
 var
   i : Integer;
-  P : TFPPackage;
+  P,AvailP : TFPPackage;
+  AvailVerStr : string;
   ReqVer : TFPVersion;
 begin
   // Reset availability
@@ -347,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]);
@@ -364,20 +418,107 @@ 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 AvailableRepository.PackageCount-1 do
+    begin
+      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 CurrentRepository.PackageCount-1 do
+  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:=CurrentRepository.Packages[i];
-      if all or (P.Version.CompareVersion(P.InstalledVersion)>0) then
-        begin
-          Writeln(Format('%-20s %-12s %-12s',[P.Name,P.InstalledVersion.AsString,P.Version.AsString]));
-        end;
+      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
+    Writeln(SL[i]);
+  FreeAndNil(SL);
 end;
 
 
@@ -385,30 +526,77 @@ end;
                            Remote Repository
 *****************************************************************************}
 
+
 procedure ListRemoteRepository;
 var
   P : TFPPackage;
   i : integer;
+  SL : TStringList;
 begin
-  Writeln(Format('%-20s %-12s %-20s',['Name','Available','FileName']));
-  for i:=0 to CurrentRepository.PackageCount-1 do
+  SL:=TStringList.Create;
+  SL.Sorted:=true;
+  for i:=0 to InstalledRepository.PackageCount-1 do
     begin
-      P:=CurrentRepository.Packages[i];
-      Writeln(Format('%-20s %-12s %-20s',[P.Name,P.Version.AsString,P.FileName]));
+      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']));
+  for i:=0 to SL.Count-1 do
+    Writeln(SL[i]);
+  FreeAndNil(SL);
 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);
@@ -456,13 +644,10 @@ begin
   X:=TFPXMLRepositoryHandler.Create;
   With X do
     try
-      SaveToXml(CurrentRepository,'packages.xml');
+      SaveToXml(InstalledRepository,'packages.xml');
     finally
       Free;
     end;
 end;
 
-
-
-initialization
 end.

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini