Explorar o código

* verbosity cleanup so it is constistent with fpmkunit
* lnet http failures now raise an error
* mirrors.xml support
* config file upgrading added
* weighted random mirror selection

git-svn-id: trunk@10013 -

peter %!s(int64=17) %!d(string=hai) anos
pai
achega
35c6e49575

+ 56 - 106
utils/fppkg/fppkg.lpi

@@ -12,7 +12,7 @@
       <MainUnit Value="0"/>
       <IconPath Value=".\"/>
       <TargetFileExt Value=""/>
-      <ActiveEditorIndexAtStart Value="4"/>
+      <ActiveEditorIndexAtStart Value="7"/>
     </General>
     <VersionInfo>
       <ProjectVersion Value=""/>
@@ -37,9 +37,9 @@
         <Filename Value="fppkg.pp"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="fppkg"/>
-        <CursorPos X="49" Y="280"/>
-        <TopLine Value="270"/>
-        <EditorIndex Value="6"/>
+        <CursorPos X="1" Y="246"/>
+        <TopLine Value="228"/>
+        <EditorIndex Value="7"/>
         <UsageCount Value="86"/>
         <Loaded Value="True"/>
       </Unit0>
@@ -77,7 +77,7 @@
         <UnitName Value="fprepos"/>
         <CursorPos X="1" Y="187"/>
         <TopLine Value="163"/>
-        <EditorIndex Value="7"/>
+        <EditorIndex Value="8"/>
         <UsageCount Value="86"/>
         <Loaded Value="True"/>
       </Unit5>
@@ -93,9 +93,11 @@
         <Filename Value="pkghandler.pp"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="pkghandler"/>
-        <CursorPos X="56" Y="170"/>
-        <TopLine Value="156"/>
+        <CursorPos X="46" Y="219"/>
+        <TopLine Value="200"/>
+        <EditorIndex Value="6"/>
         <UsageCount Value="86"/>
+        <Loaded Value="True"/>
       </Unit7>
       <Unit8>
         <Filename Value="pkgmkconv.pp"/>
@@ -117,8 +119,8 @@
         <Filename Value="pkgmessages.pp"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="pkgmessages"/>
-        <CursorPos X="96" Y="73"/>
-        <TopLine Value="43"/>
+        <CursorPos X="23" Y="36"/>
+        <TopLine Value="8"/>
         <EditorIndex Value="2"/>
         <UsageCount Value="86"/>
         <Loaded Value="True"/>
@@ -166,8 +168,8 @@
       <Unit17>
         <Filename Value="pkgcommands.pp"/>
         <UnitName Value="pkgcommands"/>
-        <CursorPos X="39" Y="265"/>
-        <TopLine Value="242"/>
+        <CursorPos X="13" Y="110"/>
+        <TopLine Value="110"/>
         <EditorIndex Value="1"/>
         <UsageCount Value="41"/>
         <Loaded Value="True"/>
@@ -203,8 +205,8 @@
       <Unit22>
         <Filename Value="pkgrepos.pp"/>
         <UnitName Value="pkgrepos"/>
-        <CursorPos X="104" Y="109"/>
-        <TopLine Value="82"/>
+        <CursorPos X="17" Y="108"/>
+        <TopLine Value="108"/>
         <EditorIndex Value="4"/>
         <UsageCount Value="32"/>
         <Loaded Value="True"/>
@@ -265,8 +267,8 @@
       <Unit31>
         <Filename Value="pkgfpmake.pp"/>
         <UnitName Value="pkgfpmake"/>
-        <CursorPos X="35" Y="218"/>
-        <TopLine Value="188"/>
+        <CursorPos X="25" Y="236"/>
+        <TopLine Value="217"/>
         <EditorIndex Value="0"/>
         <UsageCount Value="20"/>
         <Loaded Value="True"/>
@@ -276,15 +278,15 @@
         <UnitName Value="pkglnet"/>
         <CursorPos X="45" Y="32"/>
         <TopLine Value="1"/>
-        <EditorIndex Value="8"/>
+        <EditorIndex Value="9"/>
         <UsageCount Value="17"/>
         <Loaded Value="True"/>
       </Unit32>
       <Unit33>
         <Filename Value="pkgoptions.pp"/>
         <UnitName Value="pkgoptions"/>
-        <CursorPos X="49" Y="230"/>
-        <TopLine Value="210"/>
+        <CursorPos X="24" Y="476"/>
+        <TopLine Value="439"/>
         <EditorIndex Value="3"/>
         <UsageCount Value="19"/>
         <Loaded Value="True"/>
@@ -292,8 +294,8 @@
       <Unit34>
         <Filename Value="pkgglobals.pp"/>
         <UnitName Value="pkgglobals"/>
-        <CursorPos X="1" Y="51"/>
-        <TopLine Value="19"/>
+        <CursorPos X="1" Y="20"/>
+        <TopLine Value="20"/>
         <EditorIndex Value="5"/>
         <UsageCount Value="17"/>
         <Loaded Value="True"/>
@@ -320,127 +322,75 @@
         <UsageCount Value="10"/>
       </Unit37>
     </Units>
-    <JumpHistory Count="30" HistoryIndex="29">
+    <JumpHistory Count="17" HistoryIndex="16">
       <Position1>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="706" Column="21" TopLine="688"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="128" Column="17" TopLine="111"/>
       </Position1>
       <Position2>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="751" Column="28" TopLine="733"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="47" Column="32" TopLine="28"/>
       </Position2>
       <Position3>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="768" Column="25" TopLine="748"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="213" Column="18" TopLine="188"/>
       </Position3>
       <Position4>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="842" Column="25" TopLine="824"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="51" Column="54" TopLine="32"/>
       </Position4>
       <Position5>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="883" Column="17" TopLine="850"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="76" Column="25" TopLine="57"/>
       </Position5>
       <Position6>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="894" Column="32" TopLine="876"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="110" Column="56" TopLine="91"/>
       </Position6>
       <Position7>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="907" Column="59" TopLine="889"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="60" Column="31" TopLine="49"/>
       </Position7>
       <Position8>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="909" Column="18" TopLine="891"/>
+        <Filename Value="pkghandler.pp"/>
+        <Caret Line="160" Column="16" TopLine="134"/>
       </Position8>
       <Position9>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="914" Column="23" TopLine="896"/>
+        <Filename Value="pkghandler.pp"/>
+        <Caret Line="44" Column="36" TopLine="24"/>
       </Position9>
       <Position10>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="99" Column="1" TopLine="80"/>
+        <Filename Value="pkghandler.pp"/>
+        <Caret Line="213" Column="46" TopLine="194"/>
       </Position10>
       <Position11>
-        <Filename Value="fppkg.pp"/>
-        <Caret Line="55" Column="1" TopLine="37"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="236" Column="12" TopLine="199"/>
       </Position11>
       <Position12>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="69" Column="26" TopLine="55"/>
+        <Filename Value="pkgfpmake.pp"/>
+        <Caret Line="200" Column="20" TopLine="181"/>
       </Position12>
       <Position13>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="79" Column="21" TopLine="57"/>
+        <Filename Value="fppkg.pp"/>
+        <Caret Line="317" Column="24" TopLine="280"/>
       </Position13>
       <Position14>
-        <Filename Value="fprepos.pp"/>
-        <Caret Line="992" Column="39" TopLine="967"/>
+        <Filename Value="pkgglobals.pp"/>
+        <Caret Line="159" Column="52" TopLine="147"/>
       </Position14>
       <Position15>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="75" Column="21" TopLine="57"/>
+        <Filename Value="fppkg.pp"/>
+        <Caret Line="74" Column="30" TopLine="55"/>
       </Position15>
       <Position16>
         <Filename Value="fppkg.pp"/>
-        <Caret Line="280" Column="5" TopLine="253"/>
+        <Caret Line="78" Column="32" TopLine="59"/>
       </Position16>
       <Position17>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="91" Column="1" TopLine="57"/>
-      </Position17>
-      <Position18>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="16" Column="17" TopLine="1"/>
-      </Position18>
-      <Position19>
-        <Filename Value="pkgfpmake.pp"/>
-        <Caret Line="266" Column="30" TopLine="252"/>
-      </Position19>
-      <Position20>
-        <Filename Value="pkgcommands.pp"/>
-        <Caret Line="223" Column="1" TopLine="205"/>
-      </Position20>
-      <Position21>
         <Filename Value="fppkg.pp"/>
-        <Caret Line="278" Column="26" TopLine="260"/>
-      </Position21>
-      <Position22>
-        <Filename Value="pkgmessages.pp"/>
-        <Caret Line="65" Column="29" TopLine="41"/>
-      </Position22>
-      <Position23>
-        <Filename Value="pkgglobals.pp"/>
-        <Caret Line="36" Column="22" TopLine="29"/>
-      </Position23>
-      <Position24>
-        <Filename Value="pkgmessages.pp"/>
-        <Caret Line="65" Column="87" TopLine="43"/>
-      </Position24>
-      <Position25>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="110" Column="29" TopLine="84"/>
-      </Position25>
-      <Position26>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="96" Column="23" TopLine="85"/>
-      </Position26>
-      <Position27>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="104" Column="32" TopLine="87"/>
-      </Position27>
-      <Position28>
-        <Filename Value="pkgfpmake.pp"/>
-        <Caret Line="220" Column="1" TopLine="204"/>
-      </Position28>
-      <Position29>
-        <Filename Value="pkgrepos.pp"/>
-        <Caret Line="98" Column="19" TopLine="82"/>
-      </Position29>
-      <Position30>
-        <Filename Value="pkgfpmake.pp"/>
-        <Caret Line="169" Column="51" TopLine="151"/>
-      </Position30>
+        <Caret Line="245" Column="9" TopLine="224"/>
+      </Position17>
     </JumpHistory>
   </ProjectOptions>
   <CompilerOptions>

+ 31 - 19
utils/fppkg/fppkg.pp

@@ -66,34 +66,39 @@ end;
 
 procedure TMakeTool.LoadGlobalDefaults;
 var
-  SL : TStringList;
   i : integer;
   cfgfile : String;
   GeneratedConfig : boolean;
 begin
+  // Default verbosity
+  LogLevels:=DefaultLogLevels;
+  for i:=1 to ParamCount do
+    if (ParamStr(i)='-d') or (ParamStr(i)='--debug') then
+      begin
+        LogLevels:=AllLogLevels+[vlDebug];
+        break;
+      end;
+  // Load file or create new default configuration
   cfgfile:=GetConfigFileName;
   GeneratedConfig:=false;
-  // Load file or create new default configuration
   if FileExists(cfgfile) then
-    GlobalOptions.LoadGlobalFromFile(cfgfile)
+    begin
+      GlobalOptions.LoadGlobalFromFile(cfgfile);
+      if GlobalOptions.Dirty then
+        GlobalOptions.SaveGlobalToFile(cfgfile);
+    end
   else
     begin
       ForceDirectories(ExtractFilePath(cfgfile));
       GlobalOptions.SaveGlobalToFile(cfgfile);
       GeneratedConfig:=true;
     end;
-  // Load default verbosity from config
-  SL:=TStringList.Create;
-  SL.CommaText:=GlobalOptions.DefaultVerbosity;
-  for i:=0 to SL.Count-1 do
-    Include(Verbosity,StringToVerbosity(SL[i]));
-  SL.Free;
   GlobalOptions.CompilerConfig:=GlobalOptions.DefaultCompilerConfig;
   // Tracing of what we've done above, need to be done after the verbosity is set
   if GeneratedConfig then
-    Log(vDebug,SLogGeneratingGlobalConfig,[cfgfile])
+    Log(vlDebug,SLogGeneratingGlobalConfig,[cfgfile])
   else
-    Log(vDebug,SLogLoadingGlobalConfig,[cfgfile])
+    Log(vlDebug,SLogLoadingGlobalConfig,[cfgfile])
 end;
 
 
@@ -113,7 +118,7 @@ begin
   S:=GlobalOptions.CompilerConfigDir+GlobalOptions.CompilerConfig;
   if FileExists(S) then
     begin
-      Log(vDebug,SLogLoadingCompilerConfig,[S]);
+      Log(vlDebug,SLogLoadingCompilerConfig,[S]);
       CompilerOptions.LoadCompilerFromFile(S)
     end
   else
@@ -121,9 +126,11 @@ begin
       // Generate a default configuration if it doesn't exists
       if GlobalOptions.CompilerConfig='default' then
         begin
-          Log(vDebug,SLogGeneratingCompilerConfig,[S]);
+          Log(vlDebug,SLogGeneratingCompilerConfig,[S]);
           CompilerOptions.InitCompilerDefaults;
           CompilerOptions.SaveCompilerToFile(S);
+          if CompilerOptions.Dirty then
+            CompilerOptions.SaveCompilerToFile(S);
         end
       else
         Error(SErrMissingCompilerConfig,[S]);
@@ -132,8 +139,10 @@ begin
   S:=GlobalOptions.CompilerConfigDir+GlobalOptions.FPMakeCompilerConfig;
   if FileExists(S) then
     begin
-      Log(vDebug,SLogLoadingFPMakeCompilerConfig,[S]);
-      FPMakeCompilerOptions.LoadCompilerFromFile(S)
+      Log(vlDebug,SLogLoadingFPMakeCompilerConfig,[S]);
+      FPMakeCompilerOptions.LoadCompilerFromFile(S);
+      if FPMakeCompilerOptions.Dirty then
+        FPMakeCompilerOptions.SaveCompilerToFile(S);
     end
   else
     Error(SErrMissingCompilerConfig,[S]);
@@ -146,7 +155,8 @@ begin
   Writeln('Options:');
   Writeln('  -c --config        Set compiler configuration to use');
   Writeln('  -h --help          This help');
-  Writeln('  -v --verbose       Set verbosity');
+  Writeln('  -v --verbose       Show more information');
+  Writeln('  -d --debug         Show debugging information');
   Writeln('  -g --global        Force installation to global (system-wide) directory');
   Writeln('  -f --force         Force installation also if the package is already installed');
   Writeln('Actions:');
@@ -230,7 +240,9 @@ begin
       if CheckOption(I,'c','config') then
         GlobalOptions.CompilerConfig:=OptionArg(I)
       else if CheckOption(I,'v','verbose') then
-        Include(Verbosity,StringToVerbosity(OptionArg(I)))
+        LogLevels:=AllLogLevels
+      else if CheckOption(I,'d','debug') then
+        LogLevels:=AllLogLevels+[vlDebug]
       else if CheckOption(I,'g','global') then
         GlobalOptions.InstallGlobal:=true
       else if CheckOption(I,'h','help') then
@@ -283,7 +295,7 @@ begin
 
     if ParaPackages.Count=0 then
       begin
-        Log(vDebug,SLogCommandLineAction,['[<currentdir>]',ParaAction]);
+        Log(vlDebug,SLogCommandLineAction,['[<currentdir>]',ParaAction]);
         res:=pkghandler.ExecuteAction(nil,ParaAction);
       end
     else
@@ -300,7 +312,7 @@ begin
               end
             else
               ActionPackage:=CurrentRepository.PackageByName(ParaPackages[i]);
-            Log(vDebug,SLogCommandLineAction,['['+ActionPackage.Name+']',ParaAction]);
+            Log(vlDebug,SLogCommandLineAction,['['+ActionPackage.Name+']',ParaAction]);
             res:=pkghandler.ExecuteAction(ActionPackage,ParaAction);
             if ActionPackage.IsLocalPackage then;
               FreeAndNil(ActionPackage);

+ 143 - 0
utils/fppkg/fprepos.pp

@@ -209,7 +209,48 @@ Type
     Property PackageCollection : TFPPackages Read FPackages;
   end;
 
+
+  { TFPMirror }
+
+  TFPMirror = Class(TStreamCollectionItem)
+  private
+    FContact: String;
+    FName: String;
+    FURL: String;
+    FWeight: Integer;
+  Public
+    Constructor Create(ACollection : TCollection); override;
+    Destructor Destroy; override;
+    Procedure LoadFromStream(Stream : TStream; Streamversion : Integer); override;
+    Procedure SaveToStream(Stream : TStream); override;
+    Procedure Assign(Source : TPersistent); override;
+  Published
+    Property Name : String Read FName Write FName;
+    Property URL : String Read FURL Write FURL;
+    Property Contact : String Read FContact Write FContact;
+    Property Weight : Integer Read FWeight Write FWeight;
+  end;
+
+  { TFPMirrors }
+
+  TFPMirrors = Class(TStreamCollection)
+  private
+    FVersion : Integer;
+    function GetMirror(Index : Integer): TFPMirror;
+    procedure SetMirror(Index : Integer; const AValue: TFPMirror);
+  Protected
+    Function CurrentStreamVersion : Integer; override;
+  Public
+    Function IndexOfMirror(const AMirrorName : String) : Integer;
+    Function FindMirror(const AMirrorName : String) : TFPMirror;
+    Function MirrorByName(const AMirrorName : String) : TFPMirror;
+    Function AddMirror(const AMirrorName : string) : TFPMirror;
+    Property StreamVersion : Integer Read FVersion Write FVersion;
+    Property Mirrors [Index : Integer] : TFPMirror Read GetMirror Write SetMirror; default;
+  end;
+
   EPackage = Class(Exception);
+  EMirror = Class(Exception);
 
 Const
   // Max level of dependency searching before we decide it's a circular dependency.
@@ -244,6 +285,7 @@ ResourceString
   SErrNoFileName           = 'No filename for repository specified.';
   SErrDuplicatePackageName = 'Duplicate package name : "%s"';
   SErrMaxLevelExceeded     = 'Maximum number of dependency levels exceeded (%d) at package "%s".';
+  SErrMirrorNotFound       = 'Mirror "%s" not found.';
 
 
 Function OSToString(OS: TOS) : String;
@@ -1021,4 +1063,105 @@ begin
     Result.MinVersion.AsString:=AMinVersion;
 end;
 
+{ TFPMirror }
+
+constructor TFPMirror.Create(ACollection: TCollection);
+begin
+  inherited Create(ACollection);
+  Weight:=100;
+end;
+
+
+destructor TFPMirror.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TFPMirror.LoadFromStream(Stream: TStream; Streamversion : Integer);
+begin
+  Name:=ReadString(Stream);
+  URL:=ReadString(Stream);
+  Contact:=ReadString(Stream);
+  Weight:=ReadInteger(Stream);
+end;
+
+procedure TFPMirror.SaveToStream(Stream: TStream);
+begin
+  WriteString(Stream,Name);
+  WriteString(Stream,URL);
+  WriteString(Stream,Contact);
+  WriteInteger(Stream,Weight);
+end;
+
+procedure TFPMirror.Assign(Source: TPersistent);
+Var
+  P : TFPMirror;
+begin
+  if Source is TFPMirror then
+    begin
+    P:=Source as TFPMirror;
+    // This creates trouble if P has the same owning collection !!
+    If P.Collection<>Collection then
+      Name:=P.Name;
+    URL:=P.URL;
+    Contact:=P.Contact;
+    Weight:=P.Weight;
+    end
+  else
+    inherited Assign(Source);
+end;
+
+{ TFPMirrors }
+
+function TFPMirrors.GetMirror(Index : Integer): TFPMirror;
+begin
+  Result:=TFPMirror(Items[Index])
+end;
+
+procedure TFPMirrors.SetMirror(Index : Integer; const AValue: TFPMirror);
+begin
+   Items[Index]:=AValue;
+end;
+
+function TFPMirrors.CurrentStreamVersion: Integer;
+begin
+  Result:=FVersion;
+end;
+
+function TFPMirrors.IndexOfMirror(const AMirrorName: String): Integer;
+begin
+  Result:=Count-1;
+  While (Result>=0) and (CompareText(GetMirror(Result).Name,AMirrorName)<>0) do
+    Dec(Result);
+end;
+
+function TFPMirrors.FindMirror(const AMirrorName: String): TFPMirror;
+Var
+  I : Integer;
+begin
+  I:=IndexOfMirror(AMirrorName);
+  If (I=-1) then
+    Result:=Nil
+  else
+    Result:=GetMirror(I);
+end;
+
+function TFPMirrors.MirrorByName(const AMirrorName: String): TFPMirror;
+begin
+  Result:=FindMirror(AMirrorName);
+  If Result=Nil then
+    Raise EMirror.CreateFmt(SErrMirrorNotFound,[AMirrorName]);
+end;
+
+function TFPMirrors.AddMirror(const AMirrorName: string): TFPMirror;
+begin
+  Result:=Add as TFPMirror;
+  Try
+    Result.Name:=AMirrorName;
+  Except
+    Result.Free;
+    Raise;
+  end;
+end;
+
 end.

+ 192 - 76
utils/fppkg/fpxmlrep.pp

@@ -21,9 +21,9 @@ uses
 
 Type
 
-  { TFPXMLRepositoryHandler }
+  { TFPXMLHandler }
 
-  TFPXMLRepositoryHandler = Class(TObject)
+  TFPXMLHandler = Class(TObject)
   private
     FIgnoreUnknownNodes: Boolean;
   Protected
@@ -32,6 +32,14 @@ Type
     Function FindNextElement(Start : TDomNode; NodeName : String) : TDomElement;
     Function NodeText(E : TDomElement) : String;
     procedure CheckNodeType(E : TDomElement; NodeName : String);
+  public
+    property IgnoreUnknownNodes : Boolean Read FIgnoreUnknownNodes Write FIgnoreUnknownNodes;
+  end;
+
+  { TFPXMLRepositoryHandler }
+
+  TFPXMLRepositoryHandler = Class(TFPXMLHandler)
+  private
     // The DO versions do not check the node type. They do the actual work
     // for the public XMLtoXYZ versions..
     Function  DoXMLToCPUs(N : TDomElement) : TCPUs; virtual;
@@ -55,11 +63,11 @@ Type
     Procedure SaveToXml(P : TFPPackage; Stream : TStream);
     Procedure SaveToXml(PS : TFPPackages; Stream : TStream);
     Procedure SaveToXml(R : TFPRepository; Stream : TStream);
-    Procedure SaveToXml(D : TFPDependency; FileName : String);
-    Procedure SaveToXml(DS : TFPDependencies; FileName : String);
-    Procedure SaveToXml(P : TFPPackage; FileName : String);
-    Procedure SaveToXml(PS : TFPPackages; FileName : String);
-    Procedure SaveToXml(R : TFPRepository; FileName : String);
+    Procedure SaveToXml(D : TFPDependency; const FileName: String);
+    Procedure SaveToXml(DS : TFPDependencies; const FileName: String);
+    Procedure SaveToXml(P : TFPPackage; const FileName: String);
+    Procedure SaveToXml(PS : TFPPackages; const FileName: String);
+    Procedure SaveToXml(R : TFPRepository; const FileName: String);
     // Loading
     Procedure XMLToVersion(E : TDomElement; V : TFPVersion);
     Procedure XMLToDependency(E : TDomElement; D : TFPDependency);
@@ -72,12 +80,24 @@ Type
     Procedure LoadFromXml(P : TFPPackage; Stream : TStream);
     Procedure LoadFromXml(PS : TFPPackages; Stream : TStream);
     Procedure LoadFromXml(R : TFPRepository; Stream : TStream);
-    Procedure LoadFromXml(D : TFPDependency; FileName : String);
-    Procedure LoadFromXml(DS : TFPDependencies; FileName : String);
-    Procedure LoadFromXml(P : TFPPackage; FileName : String);
-    Procedure LoadFromXml(PS : TFPPackages; FileName : String);
-    Procedure LoadFromXml(R : TFPRepository; FileName : String);
-    property IgnoreUnknownNodes : Boolean Read FIgnoreUnknownNodes Write FIgnoreUnknownNodes;
+    Procedure LoadFromXml(D : TFPDependency; const FileName: String);
+    Procedure LoadFromXml(DS : TFPDependencies; const FileName: String);
+    Procedure LoadFromXml(P : TFPPackage; const FileName: String);
+    Procedure LoadFromXml(PS : TFPPackages; const FileName: String);
+    Procedure LoadFromXml(R : TFPRepository; const FileName: String);
+  end;
+
+  { TFPXMLMirrorHandler }
+
+  TFPXMLMirrorHandler = Class(TFPXMLHandler)
+  private
+    procedure DoXMLToMirror(E: TDomElement; P: TFPMirror);
+    procedure DoXMLToMirrors(E: TDomElement; PS: TFPMirrors);
+  Public
+    // Loading
+    Procedure XMLToMirrors(E : TDomElement; PS: TFPMirrors);
+    Procedure LoadFromXml(PS : TFPMirrors; Stream : TStream);
+    Procedure LoadFromXml(PS : TFPMirrors; const FileName : String);
   end;
 
   EXMLPackage = Class(EPackage);
@@ -104,6 +124,13 @@ Const
   SNodeOS           = 'os';
   SNodeCPU          = 'cpu';
 
+  // Mirrors
+  SNodeURL          = 'url';
+  SNodeContact      = 'contact';
+  SNodeWeight       = 'weight';
+  SNodeMirror       = 'mirror';
+  SNodeMirrors      = 'mirrors';
+
   SAttrName         = 'name';
   SAttrPackageName  = 'packagename';
   SAttrMinVersion   = 'minversion';
@@ -116,8 +143,69 @@ ResourceString
   SErrInvalidXMLDocument = 'Wrong root tag in XML document. Expected "%s", got "%s".';
   SErrUnknownPackageNode = 'Unknown XML tag ("%s") encountered while reading package "%s".';
   SErrInvalidDependencyXML = 'Invalid XMl encountered when reading dependency.';
+  SErrUnknownMirrorNode = 'Unknown XML tag ("%s") encountered while reading mirror "%s".';
+
+
+{****************************************************************************
+                             TFPXMLHandler
+****************************************************************************}
+
+function TFPXMLHandler.AddTextNode(Const NodeName,NodeContent : String; XML : TXMLDocument; Parent : TDomNode_WithChildren) : TDomElement;
+
+begin
+  Result:=XML.CreateElement(NodeName);
+  Try
+    Result.AppendChild(XML.CreateTextNode(NodeContent));
+    If Assigned(Parent) then
+      Parent.AppendChild(Result);
+  Except
+    Parent.RemoveChild(Result);
+    Result.Free;
+    Raise;
+  end;
+end;
+
+function TFPXMLHandler.GetNextElement(Start: TDomNode): TDomElement;
+
+begin
+  Result:=Nil;
+  While (Start<>Nil) and (Start.NodeType<>ELEMENT_NODE) do
+    Start:=Start.NextSibling;
+  If (Start<>Nil) then
+    Result:=Start as TDomElement;
+end;
+
+function TFPXMLHandler.FindNextElement(Start: TDomNode; NodeName: String): TDomElement;
+begin
+  Result:=GetNextElement(Start);
+  While (Result<>Nil) and (Result.NodeName<>NodeName) do
+    Result:=GetNextElement(Result);
+end;
+
+procedure TFPXMLHandler.CheckNodeType(E : TDomElement; NodeName : String);
+
+begin
+  If (E.NodeName<>NodeName) then
+    Raise EXMLPackage.CreateFmt(SErrInvalidXMLDocument,[NodeName,E.NodeName]);
+end;
+
+Function TFPXMLHandler.NodeText(E : TDomElement) : String;
+
+Var
+  N : TDomNode;
+
+begin
+  N:=E.FirstChild;
+  While (N<>Nil) and (N.NodeType<>TEXT_NODE) do
+    N:=N.NextSibling;
+  If (N<>Nil) then
+    Result:=N.NodeValue;
+end;
+
 
-{ TFPXMLRepositoryHandler }
+{****************************************************************************
+                        TFPXMLRepositoryHandler
+****************************************************************************}
 
 function TFPXMLRepositoryHandler.VersionToXML(V : TFPVersion;
   XML: TXMLDocument; Parent : TDomNode_WithChildren): TDomElement;
@@ -186,58 +274,6 @@ begin
     end;
 end;
 
-function TFPXMLRepositoryHandler.AddTextNode(Const NodeName,NodeContent : String; XML : TXMLDocument; Parent : TDomNode_WithChildren) : TDomElement;
-
-begin
-  Result:=XML.CreateElement(NodeName);
-  Try
-    Result.AppendChild(XML.CreateTextNode(NodeContent));
-    If Assigned(Parent) then
-      Parent.AppendChild(Result);
-  Except
-    Parent.RemoveChild(Result);
-    Result.Free;
-    Raise;
-  end;
-end;
-
-function TFPXMLRepositoryHandler.GetNextElement(Start: TDomNode): TDomElement;
-
-begin
-  Result:=Nil;
-  While (Start<>Nil) and (Start.NodeType<>ELEMENT_NODE) do
-    Start:=Start.NextSibling;
-  If (Start<>Nil) then
-    Result:=Start as TDomElement;
-end;
-
-function TFPXMLRepositoryHandler.FindNextElement(Start: TDomNode; NodeName: String): TDomElement;
-begin
-  Result:=GetNextElement(Start);
-  While (Result<>Nil) and (Result.NodeName<>NodeName) do
-    Result:=GetNextElement(Result);
-end;
-
-procedure TFPXMLRepositoryHandler.CheckNodeType(E : TDomElement; NodeName : String);
-
-begin
-  If (E.NodeName<>NodeName) then
-    Raise EXMLPackage.CreateFmt(SErrInvalidXMLDocument,[NodeName,E.NodeName]);
-end;
-
-Function TFPXMLRepositoryHandler.NodeText(E : TDomElement) : String;
-
-Var
-  N : TDomNode;
-
-begin
-  N:=E.FirstChild;
-  While (N<>Nil) and (N.NodeType<>TEXT_NODE) do
-    N:=N.NextSibling;
-  If (N<>Nil) then
-    Result:=N.NodeValue;
-end;
-
 function TFPXMLRepositoryHandler.PackageToXML(P: TFPPackage;
   XML: TXMLDocument; Parent : TDomNode_WithChildren): TDomElement;
 
@@ -420,7 +456,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.SaveToXml(D: TFPDependency; FileName: String);
+procedure TFPXMLRepositoryHandler.SaveToXml(D: TFPDependency; const FileName: String);
 
 Var
   F : TFileStream;
@@ -434,7 +470,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.SaveToXml(DS: TFPDependencies; FileName: String);
+procedure TFPXMLRepositoryHandler.SaveToXml(DS: TFPDependencies; const FileName: String);
 
 Var
   F : TFileStream;
@@ -448,7 +484,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.SaveToXml(P: TFPPackage; FileName: String);
+procedure TFPXMLRepositoryHandler.SaveToXml(P: TFPPackage; const FileName: String);
 
 Var
   F : TFileStream;
@@ -462,7 +498,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.SaveToXml(PS: TFPPackages; FileName: String);
+procedure TFPXMLRepositoryHandler.SaveToXml(PS: TFPPackages; const FileName: String);
 
 Var
   F : TFileStream;
@@ -476,7 +512,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.SaveToXml(R: TFPRepository; FileName: String);
+procedure TFPXMLRepositoryHandler.SaveToXml(R: TFPRepository; const FileName: String);
 
 Var
   F : TFileStream;
@@ -763,7 +799,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.LoadFromXml(D: TFPDependency; FileName: String);
+procedure TFPXMLRepositoryHandler.LoadFromXml(D: TFPDependency; const FileName: String);
 
 Var
   F : TFileStream;
@@ -777,7 +813,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.LoadFromXml(DS: TFPDependencies; FileName: String);
+procedure TFPXMLRepositoryHandler.LoadFromXml(DS: TFPDependencies; const FileName: String);
 
 Var
   F : TFileStream;
@@ -791,7 +827,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.LoadFromXml(P: TFPPackage; FileName: String);
+procedure TFPXMLRepositoryHandler.LoadFromXml(P: TFPPackage; const FileName: String);
 
 Var
   F : TFileStream;
@@ -805,7 +841,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.LoadFromXml(PS: TFPPackages; FileName: String);
+procedure TFPXMLRepositoryHandler.LoadFromXml(PS: TFPPackages; const FileName: String);
 
 Var
   F : TFileStream;
@@ -819,7 +855,7 @@ begin
   end;
 end;
 
-procedure TFPXMLRepositoryHandler.LoadFromXml(R: TFPRepository; FileName: String);
+procedure TFPXMLRepositoryHandler.LoadFromXml(R: TFPRepository; const FileName: String);
 
 Var
   F : TFileStream;
@@ -833,5 +869,85 @@ begin
   end;
 end;
 
+
+{****************************************************************************
+                           TFPXMLMirrorHandler
+****************************************************************************}
+
+procedure TFPXMLMirrorHandler.DoXMLToMirror(E: TDomElement; P: TFPMirror);
+Var
+  N : TDomElement;
+begin
+  P.Name:=E[sAttrName];
+  N:=GetNextElement(E.FirstChild);
+  While (N<>Nil) do
+    begin
+      if (N.NodeName=sNodeURL) then
+        P.URL:=NodeText(N)
+      else if (N.NodeName=sNodeContact) then
+        P.Contact:=NodeText(N)
+      else if (N.NodeName=sNodeWeight) then
+        P.Weight:=StrToInt(NodeText(N))
+      else if Not IgnoreUnknownNodes then
+        Raise EXMLPackage.CreateFmt(SErrUnknownMirrorNode,[N.NodeName,P.Name]);
+      N:=GetNextElement(N.NextSibling);
+    end;
+end;
+
+
+procedure TFPXMLMirrorHandler.DoXMLToMirrors(E: TDomElement; PS: TFPMirrors);
+Var
+  PN : TDomElement;
+  P : TFPMirror;
+begin
+  PN:=FindNextElement(E.FirstChild,SNodeMirror);
+  While (PN<>Nil) do
+    begin
+    P:=PS.AddMirror('');
+    try
+      DoXMLToMirror(PN,P);
+    except
+      P.Free;
+      Raise;
+    end;
+    PN:=FindNextElement(PN.NextSibling,SNodeMirror);
+    end;
+end;
+
+
+procedure TFPXMLMirrorHandler.XMLToMirrors(E: TDomElement; PS: TFPMirrors);
+begin
+  CheckNodeType(E,SNodeMirrors);
+  DoXMLToMirrors(E,PS);
+end;
+
+
+procedure TFPXMLMirrorHandler.LoadFromXml(PS: TFPMirrors; Stream: TStream);
+Var
+  XML : TXMLDocument;
+begin
+  XML:=TXMLDocument.Create;
+  try
+    xmlread.ReadXMLFile(XML,Stream);
+    XmlToMirrors(XML.DocumentElement,PS);
+  finally
+    XML.Free;
+  end;
+end;
+
+
+procedure TFPXMLMirrorHandler.LoadFromXml(PS: TFPMirrors; const FileName: String);
+Var
+  F : TFileStream;
+begin
+  F:=TFileStream.Create(FileName,fmOpenRead);
+  try
+    LoadFromXMl(PS,F);
+  finally
+    F.Free;
+  end;
+end;
+
+
 end.
 

+ 13 - 5
utils/fppkg/pkgcommands.pp

@@ -107,7 +107,7 @@ type
 function TCommandAddConfig.Execute(const Args:TActionArgs):boolean;
 begin
 {
-  Log(vInfo,SLogGeneratingCompilerConfig,[S]);
+  Log(vlInfo,SLogGeneratingCompilerConfig,[S]);
   Options.InitCompilerDefaults(Args[2]);
   Options.SaveCompilerToFile(S);
 }
@@ -116,9 +116,17 @@ end;
 
 
 function TCommandUpdate.Execute(const Args:TActionArgs):boolean;
+var
+  PackagesURL :  String;
 begin
-  Log(vCommands,SLogDownloading,[GlobalOptions.RemotePackagesFile,GlobalOptions.LocalPackagesFile]);
-  DownloadFile(GlobalOptions.RemotePackagesFile,GlobalOptions.LocalPackagesFile);
+  // Download mirrors.xml
+  Log(vlCommands,SLogDownloading,[GlobalOptions.RemoteMirrorsURL,GlobalOptions.LocalMirrorsFile]);
+  DownloadFile(GlobalOptions.RemoteMirrorsURL,GlobalOptions.LocalMirrorsFile);
+  LoadLocalMirrors;
+  // Download packages.xml
+  PackagesURL:=GetRemoteRepositoryURL(PackagesFileName);
+  Log(vlCommands,SLogDownloading,[PackagesURL,GlobalOptions.LocalPackagesFile]);
+  DownloadFile(PackagesURL,GlobalOptions.LocalPackagesFile);
   // Read the repository again
   LoadLocalRepository;
   LoadLocalStatus;
@@ -178,7 +186,7 @@ begin
   { Unzip Archive }
   With TUnZipper.Create do
     try
-      Log(vCommands,SLogUnzippping,[ArchiveFile]);
+      Log(vlCommands,SLogUnzippping,[ArchiveFile]);
       OutputPath:=PackageBuildPath;
       UnZipAllFiles(ArchiveFile);
     Finally
@@ -262,7 +270,7 @@ begin
         end
       else
         status:='OK';
-      Log(vDebug,SDbgPackageDependency,
+      Log(vlDebug,SDbgPackageDependency,
           [D.PackageName,D.MinVersion.AsString,DepPackage.InstalledVersion.AsString,DepPackage.Version.AsString,status]);
     end;
   // Install needed updates

+ 1 - 1
utils/fppkg/pkgdownload.pp

@@ -164,7 +164,7 @@ begin
   DownloaderClass:=GetDownloader(GlobalOptions.Downloader);
   with DownloaderClass.Create(nil) do
     try
-      Log(vCommands,SLogDownloading,[PackageRemoteArchive,PackageLocalArchive]);
+      Log(vlCommands,SLogDownloading,[PackageRemoteArchive,PackageLocalArchive]);
       Download(PackageRemoteArchive,PackageLocalArchive);
     finally
       Free;

+ 3 - 3
utils/fppkg/pkgfpmake.pp

@@ -197,7 +197,7 @@ begin
       // Compile options
       //   -- default is to optimize, smartlink and strip to reduce
       //      the executable size (there can be 100's of fpmake's on a system)
-      if vInfo in Verbosity then
+      if vlInfo in LogLevels then
         OOptions:=OOptions+' -vi';
       OOptions:=OOptions+' -O2 -XXs';
       // Create fpmkunit.pp if needed
@@ -210,7 +210,7 @@ begin
       DeleteDir(TempBuildDir);
     end
   else
-    Log(vCommands,SLogNotCompilingFPMake);
+    Log(vlCommands,SLogNotCompilingFPMake);
 end;
 
 
@@ -233,7 +233,7 @@ begin
   ExecuteAction(CurrentPackage,'compilefpmake');
   { Create options }
   OOptions:=' --nofpccfg';
-  if vInfo in Verbosity then
+  if vlInfo in LogLevels then
     OOptions:=OOptions+' --verbose';
   OOptions:=OOptions+' --compiler='+CompilerOptions.Compiler;
   OOptions:=OOptions+' --cpu='+CPUToString(CompilerOptions.CompilerCPU);

+ 35 - 27
utils/fppkg/pkgglobals.pp

@@ -43,16 +43,21 @@ Const
   );
 
 Type
-  TVerbosity = (vError,vWarning,vInfo,vCommands,vDebug);
-  TVerbosities = Set of TVerbosity;
+  TLogLevel = (vlError,vlWarning,vlInfo,vlCommands,vlDebug);
+  TLogLevels = Set of TLogLevel;
 
+const
+  DefaultLogLevels = [vlError,vlWarning];
+  AllLogLevels = [vlError,vlWarning,vlCommands,vlInfo];
+
+type
   EPackagerError = class(Exception);
 
 // Logging
-Function StringToVerbosity (S : String) : TVerbosity;
-Function VerbosityToString (V : TVerbosity): String;
-Procedure Log(Level: TVerbosity;Msg : String);
-Procedure Log(Level: TVerbosity;Fmt : String; const Args : array of const);
+Function StringToLogLevels (S : String) : TLogLevels;
+Function LogLevelsToString (V : TLogLevels): String;
+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);
 
@@ -68,7 +73,7 @@ Function GetCompilerInfo(const ACompiler,AOptions:string):string;
 function IsSuperUser:boolean;
 
 var
-  Verbosity : TVerbosities;
+  LogLevels : TLogLevels;
   FPMKUnitDepAvailable : array[1..FPMKUnitDepCount] of boolean;
 
 
@@ -94,49 +99,52 @@ uses
   pkgmessages;
 
 
-function StringToVerbosity(S: String): TVerbosity;
+function StringToLogLevels(S: String): TLogLevels;
 Var
   I : integer;
 begin
-  I:=GetEnumValue(TypeInfo(TVerbosity),'v'+S);
+  I:=GetEnumValue(TypeInfo(TLogLevels),'v'+S);
   If (I<>-1) then
-    Result:=TVerbosity(I)
+    Result:=TLogLevels(I)
   else
-    Raise EPackagerError.CreateFmt(SErrInvalidVerbosity,[S]);
+    Raise EPackagerError.CreateFmt(SErrInvalidLogLevels,[S]);
 end;
 
 
-Function VerbosityToString (V : TVerbosity): String;
+Function LogLevelsToString (V : TLogLevels): String;
 begin
-  Result:=GetEnumName(TypeInfo(TVerbosity),Integer(V));
+  Result:=GetEnumName(TypeInfo(TLogLevels),Integer(V));
   Delete(Result,1,1);// Delete 'v'
 end;
 
 
-procedure Log(Level:TVerbosity;Msg: String);
+procedure Log(Level:TLogLevel;Msg: String);
 var
   Prefix : string;
 begin
-  if not(Level in Verbosity) then
+  if not(Level in LogLevels) then
     exit;
   Prefix:='';
   case Level of
-    vWarning :
+    vlWarning :
       Prefix:=SWarning;
-    vError :
+    vlError :
       Prefix:=SError;
-{    vInfo :
+{    vlInfo :
       Prefix:='I: ';
-    vCommands :
+    vlCommands :
       Prefix:='C: ';
-    vDebug :
+    vlDebug :
       Prefix:='D: '; }
   end;
-  Writeln(stdErr,Prefix,Msg);
+  if Level in [vlError,vlWarning] then
+    Writeln(stdErr,Prefix,Msg)
+  else
+    Writeln(stdOut,Prefix,Msg);
 end;
 
 
-Procedure Log(Level:TVerbosity; Fmt:String; const Args:array of const);
+Procedure Log(Level:TLogLevel; Fmt:String; const Args:array of const);
 begin
   Log(Level,Format(Fmt,Args));
 end;
@@ -211,9 +219,9 @@ Function DirectoryExistsLog(const ADir:string):Boolean;
 begin
   result:=SysUtils.DirectoryExists(ADir);
   if result then
-    Log(vDebug,SDbgDirectoryExists,[ADir,SDbgFound])
+    Log(vlDebug,SDbgDirectoryExists,[ADir,SDbgFound])
   else
-    Log(vDebug,SDbgDirectoryExists,[ADir,SDbgNotFound]);
+    Log(vlDebug,SDbgDirectoryExists,[ADir,SDbgNotFound]);
 end;
 
 
@@ -221,9 +229,9 @@ Function FileExistsLog(const AFileName:string):Boolean;
 begin
   result:=SysUtils.FileExists(AFileName);
   if result then
-    Log(vDebug,SDbgFileExists,[AFileName,SDbgFound])
+    Log(vlDebug,SDbgFileExists,[AFileName,SDbgFound])
   else
-    Log(vDebug,SDbgFileExists,[AFileName,SDbgNotFound]);
+    Log(vlDebug,SDbgFileExists,[AFileName,SDbgNotFound]);
 end;
 
 
@@ -232,7 +240,7 @@ Var
   BFN : String;
 begin
   BFN:=AFileName+'.bak';
-  Log(vDebug,SDbgBackupFile,[BFN]);
+  Log(vlDebug,SDbgBackupFile,[BFN]);
   If not RenameFile(AFileName,BFN) then
     Error(SErrBackupFailed,[AFileName,BFN]);
 end;

+ 12 - 11
utils/fppkg/pkghandler.pp

@@ -40,8 +40,8 @@ type
   private
     FCurrentPackage : TFPPackage;
   Protected
-    Procedure Log(Level: TVerbosity;Msg : String);
-    Procedure Log(Level: TVerbosity;Fmt : String; const Args : array of const);
+    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);
@@ -73,6 +73,7 @@ uses
   typinfo,
   contnrs,
   uriparser,
+  pkgrepos,
   pkgmessages;
 
 var
@@ -113,7 +114,7 @@ begin
     FullActionName:=AAction;
   if ExecutedActions.Find(FullActionName)<>nil then
     begin
-      Log(vDebug,'Already executed or executing action '+FullActionName);
+      Log(vlDebug,'Already executed or executing action '+FullActionName);
       result:=true;
       exit;
     end;
@@ -130,9 +131,9 @@ begin
           else
             logargs:=logargs+','+Args[i];
         end;
-      Log(vDebug,SLogRunAction+' start',[AAction,logargs]);
+      Log(vlDebug,SLogRunAction+' start',[AAction,logargs]);
       result:=Execute(Args);
-      Log(vDebug,SLogRunAction+' end',[AAction,logargs]);
+      Log(vlDebug,SLogRunAction+' end',[AAction,logargs]);
     finally
       Free;
     end;
@@ -149,14 +150,14 @@ end;
 
 Function TPackageHandler.ExecuteProcess(Const Prog,Args:String):Integer;
 begin
-  Log(vCommands,SLogExecute,[Prog,Args]);
+  Log(vlCommands,SLogExecute,[Prog,Args]);
   Result:=SysUtils.ExecuteProcess(Prog,Args);
 end;
 
 
 Procedure TPackageHandler.SetCurrentDir(Const ADir:String);
 begin
-  Log(vCommands,SLogChangeDir,[ADir]);
+  Log(vlCommands,SLogChangeDir,[ADir]);
   if not SysUtils.SetCurrentDir(ADir) then
     Error(SErrChangeDirFailed,[ADir]);
 end;
@@ -179,7 +180,7 @@ begin
   if CurrentPackage.ExternalURL<>'' then
     Result:=CurrentPackage.ExternalURL
   else
-    Result:=GlobalOptions.RemoteRepository+CurrentPackage.FileName;
+    Result:=GetRemoteRepositoryURL(CurrentPackage.FileName);
 end;
 
 function TPackageHandler.PackageLocalArchive: String;
@@ -195,7 +196,7 @@ end;
 
 function TPackageHandler.PackageManifestFile: String;
 begin
-  Result:=DefaultManifestFile;
+  Result:=ManifestFileName;
 end;
 
 
@@ -209,13 +210,13 @@ begin
 end;
 
 
-Procedure TPackageHandler.Log(Level:TVerbosity; Msg:String);
+Procedure TPackageHandler.Log(Level:TLogLevel; Msg:String);
 begin
   pkgglobals.Log(Level,PackageLogPrefix+Msg);
 end;
 
 
-Procedure TPackageHandler.Log(Level:TVerbosity; Fmt:String; const Args:array of const);
+Procedure TPackageHandler.Log(Level:TLogLevel; Fmt:String; const Args:array of const);
 begin
   pkgglobals.Log(Level,PackageLogPrefix+Fmt,Args);
 end;

+ 3 - 1
utils/fppkg/pkglnet.pp

@@ -95,7 +95,7 @@ procedure TLNetDownloader.OnFTPFailure(aSocket: TLSocket;
   const aStatus: TLFTPStatus);
 begin
   FFTP.Disconnect;
-  Error('Retrieve failed');
+  Error(SErrDownloadFailed,['FTP','']);
   FQuit:=True;
 end;
 
@@ -148,6 +148,8 @@ begin
     FQuit:=False;
     while not FQuit do
       FHTTP.CallAction;
+    if FHTTP.Response.Status<>HSOK then
+      Error(SErrDownloadFailed,['HTTP',FHTTP.Response.Reason]);
   Finally
     FOutStream:=nil; // to be sure
   end;

+ 8 - 4
utils/fppkg/pkgmessages.pp

@@ -32,14 +32,16 @@ Resourcestring
   SErrBackupFailed           = 'Backup of file "%s" to file "%s" failed.';
   SErrUnknownProtocol        = 'Unknown download protocol: "%s"';
   SErrNoSuchFile             = 'File "%s" does not exist.';
-  SErrWGetDownloadFailed     = 'Download failed: wget reported exit status %d.';
-  SErrDownloadFailed         = 'Download failed: %s';
-  SErrInvalidVerbosity       = 'Invalid verbosity string: "%s"';
+  SErrDownloadFailed         = '%s Download failed: %s';
+  SErrInvalidLogLevels       = 'Invalid verbosity string: "%s"';
   SErrInvalidCommand         = 'Invalid command: %s';
   SErrChangeDirFailed        = 'Could not change directory to "%s"';
   SErrCorruptPackagesFile    = 'Packages file "%s" is corrupt, delete file manual and retry';
+  SErrCorruptMirrorsFile     = 'Mirrors file "%s" is corrupt, delete file manual and retry';
   SErrPackageIsLocal         = 'Operation not supported for local packages';
   SErrConvertFPMakeExists    = 'Found existing fpmake.pp, aborting conversion';
+  SErrFailedToSelectMirror   = 'Could not select a mirror, run update and retry';
+  SErrUnsupportedConfigVersion = 'Configuration file "%s" is too old, delete file manual and retry';
 
   SErrHTTPGetFailed          = 'HTTP Download failed.';
   SErrLoginFailed            = 'FTP LOGIN command failed.';
@@ -63,10 +65,13 @@ Resourcestring
   SLogDetectedFPCDIR         = 'Detected %s FPCDIR "%s"';
   SLogGeneratingCompilerConfig  = 'Generating default compiler configuration in "%s"';
   SLogLoadingPackagesFile    = 'Loading available packages from "%s"';
+  SLogLoadingMirrorsFile     = 'Loading available mirrors from "%s"';
   SLogLoadingStatusFile      = 'Loading local status from "%s"';
   SLogSavingStatusFile       = 'Saving local status to "%s"';
   SLogFPMKUnitDepVersion     = 'Checking for %s %s, installed %s, available %s';
   SLogFPMKUnitDepTooOld      = 'Minimum version of %s is not installed, using internal fpmkunit with limited functionality';
+  SLogSelectedMirror         = 'Selected mirror "%s"';
+  SLogUpgradingConfig        = 'Configuration file "%s" is updated with new configuration settings';
 
   SDbgFound                  = 'Found';
   SDbgNotFound               = 'Not Found';
@@ -75,7 +80,6 @@ Resourcestring
   SDbgBackupFile             = 'Creating Backup File "%s"';
   SDbgPackageDependency      = 'Dependency on package %s %s, installed %s, available %s  (%s)';
 
-
 implementation
 
 end.

+ 7 - 7
utils/fppkg/pkgmkconv.pp

@@ -80,7 +80,7 @@ begin
   Result:=Pos(lowercase(S)+',','i386,powerpc,arm,alpha,sparc,x86_64,powerpc64,')<>0
 end;
 
-Function GetOSCPU(L : String; var OS,CPU : String) : String;
+Procedure GetOSCPU(L : String; var OS,CPU : String);
 
   Procedure Add(Var A : String; ad : String);
 
@@ -543,8 +543,8 @@ end;
 procedure TMakeFileConverter.DoInstalls(Src,IFL : TStrings);
 
 Var
-  I,J,P : Integer;
-  Pre,N,V,D,DOS,OS,CPU : String;
+  I : Integer;
+  N,V,OS,CPU : String;
 
 begin
   If Assigned(IFL) then
@@ -560,8 +560,8 @@ end;
 procedure TMakeFileConverter.DoCleans(Src,CFL : TStrings);
 
 Var
-  I,J,P : Integer;
-  N,V,DOS,OS,CPU : String;
+  I : Integer;
+  N,V,OS,CPU : String;
 
 
 begin
@@ -598,7 +598,7 @@ Var
   B : Boolean;
 
 begin
-  Log(vDebug,'Converting '+AFileName);
+  Log(vlDebug,'Converting '+AFileName);
   T:=Nil;
   D:=Nil;
   S:=Nil;
@@ -684,7 +684,7 @@ Var
   L : TStrings;
 
 begin
-  Log(vInfo,SLogGeneratingFPMake);
+  Log(vlInfo,SLogGeneratingFPMake);
   L:=TStringList.Create;
   Try
     StartInstaller(L);

+ 99 - 125
utils/fppkg/pkgoptions.pp

@@ -19,8 +19,11 @@ interface
 uses Classes, Sysutils, Inifiles, fprepos;
 
 Const
-  DefaultManifestFile      = 'manifest.xml';
-  CurrentConfigVersion     = '0.1';
+  ManifestFileName     = 'manifest.xml';
+  MirrorsFileName      = 'mirrors.xml';
+  PackagesFileName     = 'packages.xml';
+  VersionsFileName     = 'versions-%s.dat';
+  CurrentConfigVersion = 2;
 
 Type
 
@@ -29,15 +32,13 @@ Type
   TGlobalOptions = Class(TPersistent)
   private
     FDirty : Boolean;
-    FConfigVersion,
-    FRemoteMirrorsLocation,
-    FLocalMirrorsLocation,
+    FConfigVersion : Integer;
+    FRemoteMirrorsURL,
     FRemoteRepository,
     FLocalRepository,
     FCompilerConfigDir,
     FPackagesDir,
     FBuildDir,
-    FDefaultVerbosity,
     FDownloader,
     FDefaultCompilerConfig,
     FFPMakeCompilerConfig : String;
@@ -49,24 +50,21 @@ Type
   Public
     Constructor Create;
     Procedure InitGlobalDefaults;
-    Procedure LoadGlobalFromIni(Ini : TCustomIniFile); virtual;
-    Procedure SaveGlobalToIni(Ini : TCustomIniFile); virtual;
     Procedure LoadGlobalFromFile(const AFileName : String);
     Procedure SaveGlobalToFile(const AFileName : String);
     Property Dirty : Boolean Read FDirty;
-    Property ConfigVersion : String read FConfigVersion;
-    function RemotePackagesFile:string;
+    Property ConfigVersion : Integer read FConfigVersion;
     function LocalPackagesFile:string;
+    function LocalMirrorsFile:string;
     function LocalVersionsFile(const ACompilerConfig:String):string;
   Published
-    Property RemoteMirrorsLocation : String Index 0 Read GetOptString Write SetOptString;
-    Property LocalMirrorsLocation : String Index 1 Read GetOptString Write SetOptString;
+    Property RemoteMirrorsURL : String Index 0 Read GetOptString Write SetOptString;
+    // 1 is unused
     Property RemoteRepository : String Index 2 Read GetOptString Write SetOptString;
     Property LocalRepository : String Index 3 Read GetOptString Write SetOptString;
     Property BuildDir : String Index 4 Read GetOptString Write SetOptString;
     Property PackagesDir : String Index 5 Read GetOptString Write SetOptString;
     Property CompilerConfigDir : String Index 6 Read GetOptString Write SetOptString;
-    Property DefaultVerbosity : String Index 7 Read GetOptString Write SetOptString;
     Property DefaultCompilerConfig : String Index 8 Read GetOptString Write SetOptString;
     Property FPMakeCompilerConfig : String Index 9 Read GetOptString Write SetOptString;
     Property Downloader: String Index 10 Read GetOptString Write SetOptString;
@@ -81,7 +79,7 @@ Type
   TCompilerOptions = Class(TPersistent)
   private
     FDirty: Boolean;
-    FConfigVersion,
+    FConfigVersion : Integer;
     FCompiler,
     FCompilerVersion,
     FLocalInstallDir,
@@ -95,12 +93,10 @@ Type
   Public
     Constructor Create;
     Procedure InitCompilerDefaults;
-    Procedure LoadCompilerFromIni(Ini : TCustomIniFile); virtual;
-    Procedure SaveCompilerToIni(Ini : TCustomIniFile); virtual;
     Procedure LoadCompilerFromFile(const AFileName : String);
     Procedure SaveCompilerToFile(const AFileName : String);
     Property Dirty : Boolean Read FDirty;
-    Property ConfigVersion : String read FConfigVersion;
+    Property ConfigVersion : Integer read FConfigVersion;
     Function LocalUnitDir:string;
     Function GlobalUnitDir:string;
   Published
@@ -126,15 +122,11 @@ uses
   pkgmessages;
 
 Const
-  DefaultMirrorFile       = 'mirrors.xml';
-  DefaultPackagesFile     = 'packages.xml';
-  DefaultVersionsFile     = 'versions-%s.dat';
-  DefaultMirrorsLocation  = 'http://www.freepascal.org/repository/'+DefaultMirrorFile;
-{$warning TODO use real repository}
+  DefaultMirrorsURL  = 'http://www.freepascal.org/repository/'+MirrorsFileName;
 {$ifdef localrepository}
   DefaultRemoteRepository = 'file://'+{$I %HOME%}+'/repository/';
 {$else}
-  DefaultRemoteRepository = 'http://www.freepascal.org/~peter/repository/';
+  DefaultRemoteRepository = 'auto';
 {$endif}
 
   // ini file keys
@@ -144,14 +136,12 @@ Const
   KeyConfigVersion         = 'ConfigVersion';
 
   // Global config
-  KeyLocalMirrorsLocation  = 'LocalMirrors';
-  KeyRemoteMirrorsLocation = 'RemoteMirrors';
+  KeyRemoteMirrorsURL = 'RemoteMirrors';
   KeyRemoteRepository      = 'RemoteRepository';
   KeyLocalRepository       = 'LocalRepository';
   KeyPackagesDir           = 'PackagesDir';
   KeyBuildDir              = 'BuildDir';
   KeyCompilerConfigDir     = 'CompilerConfigDir';
-  KeyVerbosity             = 'Verbosity';
   KeyCompilerConfig        = 'CompilerConfig';
   KeyFPMakeCompilerConfig  = 'FPMakeCompilerConfig';
   KeyDownloader            = 'Downloader';
@@ -178,14 +168,12 @@ end;
 function TGlobalOptions.GetOptString(Index: integer): String;
 begin
   Case Index of
-    0 : Result:=FRemoteMirrorsLocation;
-    1 : Result:=FLocalMirrorsLocation;
+    0 : Result:=FRemoteMirrorsURL;
     2 : Result:=FRemoteRepository;
     3 : Result:=FLocalRepository;
     4 : Result:=FBuildDir;
     5 : Result:=FPackagesDir;
     6 : Result:=FCompilerConfigDir;
-    7 : Result:=FDefaultVerbosity;
     8 : Result:=FDefaultCompilerConfig;
     9 : Result:=FFPMakeCompilerConfig;
    10 : Result:=FDownloader;
@@ -199,14 +187,12 @@ begin
   If AValue=GetOptString(Index) then
     Exit;
   Case Index of
-    0 : FLocalMirrorsLocation:=AValue;
-    1 : FRemoteMirrorsLocation:=AValue;
+    1 : FRemoteMirrorsURL:=AValue;
     2 : FRemoteRepository:=AValue;
     3 : FLocalRepository:=AValue;
     4 : FBuildDir:=FixPath(AValue);
     5 : FPackagesDir:=FixPath(AValue);
     6 : FCompilerConfigDir:=FixPath(AValue);
-    7 : FDefaultVerbosity:=AValue;
     8 : FDefaultCompilerConfig:=AValue;
     9 : FFPMakeCompilerConfig:=AValue;
    10 : FDownloader:=AValue;
@@ -217,21 +203,21 @@ begin
 end;
 
 
-function TGlobalOptions.RemotePackagesFile:string;
+function TGlobalOptions.LocalPackagesFile:string;
 begin
-  Result:=FRemoteRepository+DefaultPackagesFile;
+  Result:=FLocalRepository+PackagesFileName;
 end;
 
 
-function TGlobalOptions.LocalPackagesFile:string;
+function TGlobalOptions.LocalMirrorsFile:string;
 begin
-  Result:=FLocalRepository+DefaultPackagesFile;
+  Result:=FLocalRepository+MirrorsFileName;
 end;
 
 
 function TGlobalOptions.LocalVersionsFile(const ACompilerConfig:String):string;
 begin
-  Result:=FLocalRepository+Format(DefaultVersionsFile,[ACompilerConfig]);
+  Result:=FLocalRepository+Format(VersionsFileName,[ACompilerConfig]);
 end;
 
 
@@ -259,13 +245,11 @@ begin
   FBuildDir:=LocalDir+'build'+PathDelim;
   FPackagesDir:=LocalDir+'packages'+PathDelim;
   FCompilerConfigDir:=LocalDir+'config'+PathDelim;
-  FLocalMirrorsLocation:=LocalDir+DefaultMirrorFile;
   FLocalRepository:=LocalDir;
   // Remote
-  FRemoteMirrorsLocation:=DefaultMirrorsLocation;
+  FRemoteMirrorsURL:=DefaultMirrorsURL;
   FRemoteRepository:=DefaultRemoteRepository;
   // Other config
-  FDefaultVerbosity:='error,warning,info,debug,commands';
   FDefaultCompilerConfig:='default';
   FFPMakeCompilerConfig:='default';
   // Downloader
@@ -280,55 +264,38 @@ begin
 end;
 
 
-procedure TGlobalOptions.LoadGlobalFromIni(Ini: TCustomIniFile);
-begin
- With Ini do
-   begin
-     FConfigVersion:=ReadString(SDefaults,KeyConfigVersion,'');
-     if FConfigVersion<>CurrentConfigVersion then
-       Error('Old configuration found, please delete manual');
-     FLocalMirrorsLocation:=ReadString(SDefaults,KeyLocalMirrorsLocation,FLocalMirrorsLocation);
-     FRemoteMirrorsLocation:=ReadString(SDefaults,KeyRemoteMirrorsLocation,FRemoteMirrorsLocation);
-     FRemoteRepository:=ReadString(SDefaults,KeyRemoteRepository,FRemoteRepository);
-     FLocalRepository:=ReadString(SDefaults,KeyLocalRepository,FLocalRepository);
-     FBuildDir:=FixPath(ReadString(SDefaults,KeyBuildDir,FBuildDir));
-     FPackagesDir:=FixPath(ReadString(SDefaults,KeyPackagesDir,FPackagesDir));
-     FCompilerConfigDir:=FixPath(ReadString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir));
-     FDefaultVerbosity:=ReadString(SDefaults,KeyVerbosity,FDefaultVerbosity);
-     FDefaultCompilerConfig:=ReadString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
-     FFPMakeCompilerConfig:=ReadString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
-     FDownloader:=ReadString(SDefaults,KeyDownloader,FDownloader);
-   end;
-end;
-
-
-procedure TGlobalOptions.SaveGlobalToIni(Ini: TCustomIniFile);
-begin
- With Ini do
-   begin
-     WriteString(SDefaults,KeyConfigVersion,FConfigVersion);
-     WriteString(SDefaults,KeyBuildDir,FBuildDir);
-     WriteString(SDefaults,KeyPackagesDir,FPackagesDir);
-     WriteString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir);
-     WriteString(SDefaults,KeyLocalRepository,FLocalRepository);
-     WriteString(SDefaults,KeyLocalMirrorsLocation,FLocalMirrorsLocation);
-     WriteString(SDefaults,KeyRemoteMirrorsLocation,FRemoteMirrorsLocation);
-     WriteString(SDefaults,KeyRemoteRepository,FRemoteRepository);
-     WriteString(SDefaults,KeyVerbosity,FDefaultVerbosity);
-     WriteString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
-     WriteString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
-     WriteString(SDefaults,KeyDownloader,FDownloader);
-   end;
-end;
-
-
 procedure TGlobalOptions.LoadGlobalFromFile(const AFileName: String);
 Var
   Ini : TMemIniFile;
 begin
-  Ini:=TMemIniFile.Create(AFileName);
   try
-    LoadGlobalFromIni(Ini);
+    Ini:=TMemIniFile.Create(AFileName);
+    With Ini do
+      begin
+        FConfigVersion:=ReadInteger(SDefaults,KeyConfigVersion,0);
+        if (FConfigVersion<>CurrentConfigVersion) then
+          begin
+            Log(vlDebug,SLogUpgradingConfig,[AFileName]);
+            FDirty:=true;
+            if FConfigVersion<1 then
+              begin
+                FRemoteRepository:='auto';
+              end;
+            if (FConfigVersion>CurrentConfigVersion) then
+              Error(SErrUnsupportedConfigVersion,[AFileName]);
+          end;
+        FRemoteMirrorsURL:=ReadString(SDefaults,KeyRemoteMirrorsURL,FRemoteMirrorsURL);
+{$warning Temporary Config check, can be removed in March-2008}
+        if FConfigVersion>=1 then
+          FRemoteRepository:=ReadString(SDefaults,KeyRemoteRepository,FRemoteRepository);
+        FLocalRepository:=ReadString(SDefaults,KeyLocalRepository,FLocalRepository);
+        FBuildDir:=FixPath(ReadString(SDefaults,KeyBuildDir,FBuildDir));
+        FPackagesDir:=FixPath(ReadString(SDefaults,KeyPackagesDir,FPackagesDir));
+        FCompilerConfigDir:=FixPath(ReadString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir));
+        FDefaultCompilerConfig:=ReadString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
+        FFPMakeCompilerConfig:=ReadString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
+        FDownloader:=ReadString(SDefaults,KeyDownloader,FDownloader);
+      end;
   finally
     Ini.Free;
   end;
@@ -341,9 +308,22 @@ Var
 begin
   if FileExists(AFileName) then
     BackupFile(AFileName);
-  Ini:=TIniFile.Create(AFileName);
   try
-    SaveGlobalToIni(Ini);
+    Ini:=TIniFile.Create(AFileName);
+    With Ini do
+      begin
+        WriteInteger(SDefaults,KeyConfigVersion,CurrentConfigVersion);
+        WriteString(SDefaults,KeyBuildDir,FBuildDir);
+        WriteString(SDefaults,KeyPackagesDir,FPackagesDir);
+        WriteString(SDefaults,KeyCompilerConfigDir,FCompilerConfigDir);
+        WriteString(SDefaults,KeyLocalRepository,FLocalRepository);
+        WriteString(SDefaults,KeyRemoteMirrorsURL,FRemoteMirrorsURL);
+        WriteString(SDefaults,KeyRemoteRepository,FRemoteRepository);
+        WriteString(SDefaults,KeyCompilerConfig,FDefaultCompilerConfig);
+        WriteString(SDefaults,KeyFPMakeCompilerConfig,FFPMakeCompilerConfig);
+        WriteString(SDefaults,KeyDownloader,FDownloader);
+        FDirty:=False;
+      end;
     Ini.UpdateFile;
   finally
     Ini.Free;
@@ -443,7 +423,7 @@ begin
   FCompilerVersion:=infosl[0];
   FCompilerCPU:=StringToCPU(infosl[1]);
   FCompilerOS:=StringToOS(infosl[2]);
-  Log(vDebug,SLogDetectedCompiler,[FCompiler,FCompilerVersion,MakeTargetString(FCompilerCPU,FCompilerOS)]);
+  Log(vlDebug,SLogDetectedCompiler,[FCompiler,FCompilerVersion,MakeTargetString(FCompilerCPU,FCompilerOS)]);
   // Use the same algorithm as the compiler, see options.pas
 {$ifdef Unix}
   FGlobalInstallDir:=FixPath(GetEnvironmentVariable('FPCDIR'));
@@ -465,45 +445,13 @@ begin
     end;
   FGlobalInstallDir:=ExpandFileName(FGlobalInstallDir);
 {$endif unix}
-  Log(vDebug,SLogDetectedFPCDIR,['global',FGlobalInstallDir]);
+  Log(vlDebug,SLogDetectedFPCDIR,['global',FGlobalInstallDir]);
   // User writable install directory
   if not IsSuperUser then
     begin
       FLocalInstallDir:=GlobalOptions.LocalRepository+'lib'+PathDelim+FCompilerVersion+PathDelim;
-      Log(vDebug,SLogDetectedFPCDIR,['local',FLocalInstallDir]);
+      Log(vlDebug,SLogDetectedFPCDIR,['local',FLocalInstallDir]);
     end;
- end;
-
-
-procedure TCompilerOptions.LoadCompilerFromIni(Ini: TCustomIniFile);
-begin
- With Ini do
-   begin
-     FConfigVersion:=ReadString(SDefaults,KeyConfigVersion,'');
-     if FConfigVersion<>CurrentConfigVersion then
-       Error('Old configuration found, please delete manual');
-     FGlobalInstallDir:=FixPath(ReadString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir));
-     FLocalInstallDir:=FixPath(ReadString(SDefaults,KeyLocalInstallDir,FLocalInstallDir));
-     FCompiler:=ReadString(SDefaults,KeyCompiler,FCompiler);
-     FCompilerOS:=StringToOS(ReadString(SDefaults,KeyCompilerOS,OSToString(CompilerOS)));
-     FCompilerCPU:=StringToCPU(ReadString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU)));
-     FCompilerVersion:=ReadString(SDefaults,KeyCompilerVersion,FCompilerVersion);
-   end;
-end;
-
-
-procedure TCompilerOptions.SaveCompilerToIni(Ini: TCustomIniFile);
-begin
- With Ini do
-   begin
-     WriteString(SDefaults,KeyConfigVersion,FConfigVersion);
-     WriteString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir);
-     WriteString(SDefaults,KeyLocalInstallDir,FLocalInstallDir);
-     WriteString(SDefaults,KeyCompiler,FCompiler);
-     WriteString(SDefaults,KeyCompilerOS,OSToString(CompilerOS));
-     WriteString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU));
-     WriteString(SDefaults,KeyCompilerVersion,FCompilerVersion);
-   end;
 end;
 
 
@@ -511,9 +459,25 @@ procedure TCompilerOptions.LoadCompilerFromFile(const AFileName: String);
 Var
   Ini : TMemIniFile;
 begin
-  Ini:=TMemIniFile.Create(AFileName);
   try
-    LoadCompilerFromIni(Ini);
+    Ini:=TMemIniFile.Create(AFileName);
+    With Ini do
+      begin
+        FConfigVersion:=ReadInteger(SDefaults,KeyConfigVersion,0);
+        if (FConfigVersion<>CurrentConfigVersion) then
+          begin
+            Log(vlDebug,SLogUpgradingConfig,[AFileName]);
+            FDirty:=true;
+            if (FConfigVersion>CurrentConfigVersion) then
+              Error(SErrUnsupportedConfigVersion,[AFileName]);
+          end;
+        FGlobalInstallDir:=FixPath(ReadString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir));
+        FLocalInstallDir:=FixPath(ReadString(SDefaults,KeyLocalInstallDir,FLocalInstallDir));
+        FCompiler:=ReadString(SDefaults,KeyCompiler,FCompiler);
+        FCompilerOS:=StringToOS(ReadString(SDefaults,KeyCompilerOS,OSToString(CompilerOS)));
+        FCompilerCPU:=StringToCPU(ReadString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU)));
+        FCompilerVersion:=ReadString(SDefaults,KeyCompilerVersion,FCompilerVersion);
+      end;
   finally
     Ini.Free;
   end;
@@ -526,9 +490,19 @@ Var
 begin
   if FileExists(AFileName) then
     BackupFile(AFileName);
-  Ini:=TIniFile.Create(AFileName);
   try
-    SaveCompilerToIni(Ini);
+    Ini:=TIniFile.Create(AFileName);
+    With Ini do
+      begin
+        WriteInteger(SDefaults,KeyConfigVersion,CurrentConfigVersion);
+        WriteString(SDefaults,KeyGlobalInstallDir,FGlobalInstallDir);
+        WriteString(SDefaults,KeyLocalInstallDir,FLocalInstallDir);
+        WriteString(SDefaults,KeyCompiler,FCompiler);
+        WriteString(SDefaults,KeyCompilerOS,OSToString(CompilerOS));
+        WriteString(SDefaults,KeyCompilerCPU,CPUtoString(CompilerCPU));
+        WriteString(SDefaults,KeyCompilerVersion,FCompilerVersion);
+        FDirty:=False;
+      end;
     Ini.UpdateFile;
   finally
     Ini.Free;

+ 110 - 13
utils/fppkg/pkgrepos.pp

@@ -8,6 +8,9 @@ uses
   Classes,SysUtils,
   fprepos;
 
+function GetRemoteRepositoryURL(const AFileName:string):string;
+
+procedure LoadLocalMirrors;
 procedure LoadLocalRepository;
 procedure LoadLocalStatus;
 procedure SaveLocalStatus;
@@ -19,6 +22,7 @@ procedure RebuildRemoteRepository;
 procedure SaveRemoteRepository;
 
 var
+  CurrentMirrors    : TFPMirrors;
   CurrentRepository : TFPRepository;
 
 
@@ -31,6 +35,99 @@ uses
   pkgoptions,
   pkgmessages;
 
+{*****************************************************************************
+                           Mirror Selection
+*****************************************************************************}
+
+var
+  CurrentRemoteRepositoryURL : String;
+
+procedure LoadLocalMirrors;
+var
+  S : String;
+  X : TFPXMLMirrorHandler;
+begin
+  if assigned(CurrentMirrors) then
+    CurrentMirrors.Free;
+  CurrentMirrors:=TFPMirrors.Create(TFPMirror);
+
+  // Repository
+  S:=GlobalOptions.LocalMirrorsFile;
+  Log(vlDebug,SLogLoadingMirrorsFile,[S]);
+  if not FileExists(S) then
+    exit;
+  try
+    X:=TFPXMLMirrorHandler.Create;
+    With X do
+      try
+        LoadFromXml(CurrentMirrors,S);
+      finally
+        Free;
+      end;
+  except
+    on E : Exception do
+      begin
+        Log(vlError,E.Message);
+        Error(SErrCorruptMirrorsFile,[S]);
+      end;
+  end;
+end;
+
+
+function SelectRemoteMirror:string;
+var
+  i,j : Integer;
+  Bucket,
+  BucketCnt : Integer;
+  M : TFPMirror;
+begin
+  Result:='';
+  // Create array for selection
+  BucketCnt:=0;
+  for i:=0 to CurrentMirrors.Count-1 do
+    inc(BucketCnt,CurrentMirrors[i].Weight);
+  // Select random entry
+  Bucket:=Random(BucketCnt);
+  M:=nil;
+  for i:=0 to CurrentMirrors.Count-1 do
+    begin
+      for j:=0 to CurrentMirrors[i].Weight-1 do
+        begin
+          if Bucket=0 then
+            begin
+              M:=CurrentMirrors[i];
+              break;
+            end;
+          Dec(Bucket);
+        end;
+      if assigned(M) then
+        break;
+    end;
+  if assigned(M) then
+    begin
+      Log(vlInfo,SLogSelectedMirror,[M.Name]);
+      Result:=M.URL;
+    end
+  else
+    Error(SErrFailedToSelectMirror);
+end;
+
+
+function GetRemoteRepositoryURL(const AFileName:string):string;
+var
+  i : integer;
+begin
+  if CurrentRemoteRepositoryURL='' then
+    begin
+      if GlobalOptions.RemoteRepository='auto' then
+        CurrentRemoteRepositoryURL:=SelectRemoteMirror
+      else
+        CurrentRemoteRepositoryURL:=GlobalOptions.RemoteRepository;
+    end;
+  Result:=CurrentRemoteRepositoryURL+AFileName;
+end;
+
+
 {*****************************************************************************
                            Local Repository
 *****************************************************************************}
@@ -45,7 +142,7 @@ begin
   CurrentRepository:=TFPRepository.Create(Nil);
   // Repository
   S:=GlobalOptions.LocalPackagesFile;
-  Log(vDebug,SLogLoadingPackagesFile,[S]);
+  Log(vlDebug,SLogLoadingPackagesFile,[S]);
   if not FileExists(S) then
     exit;
   try
@@ -59,7 +156,7 @@ begin
   except
     on E : Exception do
       begin
-        Log(vError,E.Message);
+        Log(vlError,E.Message);
         Error(SErrCorruptPackagesFile,[S]);
       end;
   end;
@@ -71,7 +168,7 @@ var
   S : String;
 begin
   S:=GlobalOptions.LocalVersionsFile(GlobalOptions.CompilerConfig);
-  Log(vDebug,SLogLoadingStatusFile,[S]);
+  Log(vlDebug,SLogLoadingStatusFile,[S]);
   CurrentRepository.ClearStatus;
   if FileExists(S) then
     CurrentRepository.LoadStatusFromFile(S);
@@ -83,7 +180,7 @@ var
   S : String;
 begin
   S:=GlobalOptions.LocalVersionsFile(GlobalOptions.CompilerConfig);
-  Log(vDebug,SLogSavingStatusFile,[S]);
+  Log(vlDebug,SLogSavingStatusFile,[S]);
   CurrentRepository.SaveStatusToFile(S);
 end;
 
@@ -96,7 +193,7 @@ var
   ReqVer : TFPVersion;
 begin
   S:=GlobalOptions.LocalVersionsFile(GlobalOptions.FPMakeCompilerConfig);
-  Log(vDebug,SLogLoadingStatusFile,[S]);
+  Log(vlDebug,SLogLoadingStatusFile,[S]);
   CurrentRepository.ClearStatus;
   if FileExists(S) then
     CurrentRepository.LoadStatusFromFile(S);
@@ -109,14 +206,14 @@ begin
         begin
           ReqVer:=TFPVersion.Create;
           ReqVer.AsString:=FPMKUnitDeps[i].ReqVer;
-          Log(vDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.InstalledVersion.AsString,P.Version.AsString]);
+          Log(vlDebug,SLogFPMKUnitDepVersion,[P.Name,ReqVer.AsString,P.InstalledVersion.AsString,P.Version.AsString]);
           if ReqVer.CompareVersion(P.InstalledVersion)<=0 then
             FPMKUnitDepAvailable[i]:=true
           else
-            Log(vDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
+            Log(vlDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
         end
       else
-        Log(vDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
+        Log(vlDebug,SLogFPMKUnitDepTooOld,[FPMKUnitDeps[i].package]);
     end;
 end;
 
@@ -168,7 +265,7 @@ begin
   CurrentRepository:=TFPRepository.Create(Nil);
   try
     ManifestSL:=TStringList.Create;
-    ManifestSL.Add(DefaultManifestFile);
+    ManifestSL.Add(ManifestFileName);
     { Find all archives }
     ArchiveSL:=TStringList.Create;
     SearchFiles(ArchiveSL,'*.zip');
@@ -181,23 +278,23 @@ begin
         { Unzip manifest.xml }
         With TUnZipper.Create do
           try
-            Log(vCommands,SLogUnzippping,[ArchiveSL[i]]);
+            Log(vlCommands,SLogUnzippping,[ArchiveSL[i]]);
             OutputPath:='.';
             UnZipFiles(ArchiveSL[i],ManifestSL);
           Finally
             Free;
           end;
         { Load manifest.xml }
-        if FileExists(DefaultManifestFile) then
+        if FileExists(ManifestFileName) then
           begin
             X:=TFPXMLRepositoryHandler.Create;
             With X do
               try
-                LoadFromXml(CurrentRepository.PackageCollection,DefaultManifestFile);
+                LoadFromXml(CurrentRepository.PackageCollection,ManifestFileName);
               finally
                 Free;
               end;
-            DeleteFile(DefaultManifestFile);
+            DeleteFile(ManifestFileName);
           end
         else
           Writeln('No manifest found in archive ',ArchiveSL[i]);

+ 2 - 2
utils/fppkg/pkgwget.pp

@@ -22,7 +22,7 @@ Type
 implementation
 
 uses
-  process,
+  sysutils,process,
   pkgglobals,
   pkgmessages;
 
@@ -53,7 +53,7 @@ begin
           Dest.WriteBuffer(Buffer,Count);
         end;
       If (ExitStatus<>0) then
-        Error(SErrWGetDownloadFailed,[ExitStatus]);
+        Error(SErrDownloadFailed,['WGET',Format('exit status %d',[ExitStatus])]);
     finally
       Free;
     end;