fpc/utils/fppkg/fppkg.pp
joost fd191a9d57 --- Merging r44193 into '.':
U    utils/fppkg/fppkg.pp
--- Recording mergeinfo for merge of r44193 into '.':
 U   .

git-svn-id: branches/fixes_3_2@44214 -
2020-02-18 22:30:10 +00:00

482 lines
15 KiB
ObjectPascal

program fppkg;
{$mode objfpc}{$H+}{$macro on}
{$if defined(VER2_2) and (FPC_PATCH<1)}
{$fatal At least FPC 2.2.1 is required to compile fppkg}
{$endif}
{$ifndef package_version_major}
{$define package_version_major:=0}
{$endif}
{$ifndef package_version_minor}
{$define package_version_minor:=0}
{$endif}
{$ifndef package_version_micro}
{$define package_version_micro:=0}
{$endif}
{$ifndef package_version_build}
{$define package_version_build:=0}
{$endif}
uses
// General
{$ifdef unix}
baseunix, cthreads,
{$endif}
Classes, SysUtils, TypInfo, custapp,
// Repository handler objects
fprepos, fpxmlrep,
pkgmessages, pkgglobals, pkgoptions, pkgrepos,
// Package Handler components
pkghandler,pkgmkconv, pkgdownload,
pkgfpmake, pkgcommands,
pkgPackagesStructure,
fpmkunit
// Downloaders
{$if (defined(unix) and not defined(android)) or defined(windows)}
,pkgwget
,pkglnet
,pkgfphttp
,opensslsockets
{$endif}
;
const
version_major = package_version_major;
version_minor = package_version_minor;
version_micro = package_version_micro;
version_build = package_version_build;
Type
{ TMakeTool }
TMakeTool = Class(TCustomApplication)
Private
ParaAction : string;
ParaPackages : TStringList;
procedure MaybeCreateLocalDirs;
procedure ShowUsage;
procedure ShowVersion;
Public
Constructor Create;
Destructor Destroy;override;
Procedure LoadGlobalDefaults;
Procedure ProcessCommandLine(FirstPass: boolean);
Procedure DoRun; Override;
end;
EMakeToolError = Class(Exception);
{ TMakeTool }
procedure TMakeTool.LoadGlobalDefaults;
var
i : integer;
cfgfile : String;
begin
// Default verbosity
LogLevels:=DefaultLogLevels;
for i:=1 to ParamCount do
begin
if (ParamStr(i)='-d') or (ParamStr(i)='--debug') then
begin
LogLevels:=AllLogLevels+[llDebug];
break;
end;
if (ParamStr(i)='-v') or (ParamStr(i)='--verbose') then
begin
LogLevels:=AllLogLevels+[llDebug];
break;
end;
end;
// First try config file from command line
if HasOption('C','config-file') then
cfgfile:=GetOptionValue('C','config-file')
else
cfgfile:='';
GFPpkg.InitializeGlobalOptions(CfgFile);
end;
procedure TMakeTool.MaybeCreateLocalDirs;
begin
ForceDirectories(GFPpkg.Options.GlobalSection.BuildDir);
ForceDirectories(GFPpkg.Options.GlobalSection.ArchivesDir);
ForceDirectories(GFPpkg.Options.GlobalSection.CompilerConfigDir);
end;
procedure TMakeTool.ShowUsage;
begin
Writeln('Usage: ',Paramstr(0),' [options] <action> <package>');
Writeln('Options:');
Writeln(' -C --config-file Specify the configuration file to use');
Writeln(' -c --config Set compiler configuration to use');
Writeln(' -h --help This help');
Writeln(' -V --version Show version and exit');
Writeln(' -v --verbose Show more information');
Writeln(' -d --debug Show debugging information');
Writeln(' -f --force Force installation also if the package is already installed');
Writeln(' -r --recovery Recovery mode, use always internal fpmkunit');
Writeln(' -b --broken Do not stop on broken packages');
Writeln(' -l --showlocation Show in which repository the the packages are installed');
Writeln(' -o --options=value Pass extra options to the compiler');
Writeln(' -n Do not read the default configuration files');
Writeln(' -p --prefix=value Specify the prefix');
Writeln(' -s --skipbroken Skip the rebuild of depending packages after installation');
Writeln(' -i --installlocation Specify the repository to install packages into');
Writeln(' --compiler=value Specify the compiler-executable');
Writeln(' --cpu=value Specify the target cpu to compile for');
Writeln(' --os=value Specify the target operating system to compile for');
Writeln('Actions:');
Writeln(' update Update packages list');
Writeln(' list List available and installed packages');
Writeln(' build Build package');
Writeln(' compile Compile package');
Writeln(' install Install package');
Writeln(' uninstall Uninstall package');
Writeln(' clean Clean package');
Writeln(' archive Create archive of package');
Writeln(' download Download package');
Writeln(' convertmk Convert Makefile.fpc to fpmake.pp');
Writeln(' info Show more information about a package');
Writeln(' fixbroken Recompile all (broken) packages with changed dependencies');
Writeln(' listsettings Show the values for all fppkg settings');
// Writeln(' addconfig Add a compiler configuration for the supplied compiler');
Halt(0);
end;
Constructor TMakeTool.Create;
begin
inherited Create(nil);
ParaPackages:=TStringList.Create;
end;
Destructor TMakeTool.Destroy;
begin
FreeAndNil(ParaPackages);
inherited Destroy;
end;
procedure TMakeTool.ProcessCommandLine(FirstPass: boolean);
Function CheckOption(Index : Integer;Short,Long : String): Boolean;
var
O : String;
begin
O:=Paramstr(Index);
Result:=(O='-'+short) or (O='--'+long) or (copy(O,1,Length(Long)+3)=('--'+long+'='));
end;
Function OptionArg(Var Index : Integer) : String;
Var
P : Integer;
begin
if (Length(ParamStr(Index))>1) and (Paramstr(Index)[2]<>'-') then
begin
If Index<ParamCount then
begin
Inc(Index);
Result:=Paramstr(Index);
end
else
Error(SErrNeedArgument,[Index,ParamStr(Index)]);
end
else If length(ParamStr(Index))>2 then
begin
P:=Pos('=',Paramstr(Index));
If (P=0) then
Error(SErrNeedArgument,[Index,ParamStr(Index)])
else
begin
Result:=Paramstr(Index);
Delete(Result,1,P);
end;
end;
end;
function SplitSpaces(var SplitString: string) : string;
var i : integer;
begin
i := pos(' ',SplitString);
if i > 0 then
begin
result := copy(SplitString,1,i-1);
delete(SplitString,1,i);
end
else
begin
result := SplitString;
SplitString:='';
end;
end;
Var
I : Integer;
HasAction : Boolean;
OptString : String;
begin
I:=0;
HasAction:=false;
// We can't use the TCustomApplication option handling,
// because they cannot handle [general opts] [command] [cmd-opts] [args]
While (I<ParamCount) do
begin
Inc(I);
// Check options.
if CheckOption(I,'C','config-file') then
begin
// Do nothing, the config-file has already been read.
OptionArg(I);
end
else if CheckOption(I,'c','config') then
GFPpkg.Options.CommandLineSection.CompilerConfig:=OptionArg(I)
else if CheckOption(I,'v','verbose') then
LogLevels:=AllLogLevels
else if CheckOption(I,'d','debug') then
LogLevels:=AllLogLevels+[llDebug]
else if CheckOption(I,'i','installrepository') then
GFPpkg.Options.CommandLineSection.InstallRepository:=OptionArg(I)
else if CheckOption(I,'r','recovery') then
GFPpkg.Options.CommandLineSection.RecoveryMode:=true
else if CheckOption(I,'n','') then
GFPpkg.Options.CommandLineSection.SkipConfigurationFiles:=true
else if CheckOption(I,'b','broken') then
GFPpkg.Options.CommandLineSection.AllowBroken:=true
else if CheckOption(I,'l','showlocation') then
GFPpkg.Options.CommandLineSection.ShowLocation:=true
else if CheckOption(I,'s','skipbroken') then
GFPpkg.Options.CommandLineSection.SkipFixBrokenAfterInstall:=true
else if CheckOption(I,'o','options') and FirstPass then
begin
OptString := OptionArg(I);
while OptString <> '' do
GFPpkg.CompilerOptions.Options.Add(SplitSpaces(OptString));
end
else if CheckOption(I,'p','prefix') then
begin
GFPpkg.CompilerOptions.GlobalPrefix := OptionArg(I);
GFPpkg.CompilerOptions.LocalPrefix := OptionArg(I);
GFPpkg.FPMakeCompilerOptions.GlobalPrefix := OptionArg(I);
GFPpkg.FPMakeCompilerOptions.LocalPrefix := OptionArg(I);
end
else if CheckOption(I,'','compiler') then
begin
GFPpkg.CompilerOptions.Compiler := OptionArg(I);
GFPpkg.FPMakeCompilerOptions.Compiler := OptionArg(I);
end
else if CheckOption(I,'','os') then
GFPpkg.CompilerOptions.CompilerOS := StringToOS(OptionArg(I))
else if CheckOption(I,'','cpu') then
GFPpkg.CompilerOptions.CompilerCPU := StringToCPU(OptionArg(I))
else if CheckOption(I,'h','help') then
begin
ShowUsage;
halt(0);
end
else if CheckOption(I,'V','version') then
begin
ShowVersion;
halt(0);
end
else if (Length(Paramstr(i))>0) and (Paramstr(I)[1]='-') then
begin
if FirstPass then
Raise EMakeToolError.CreateFmt(SErrInvalidArgument,[I,ParamStr(i)])
end
else
// It's a command or target.
begin
if HasAction then
begin
if FirstPass then
ParaPackages.Add(Paramstr(i))
end
else
begin
ParaAction:=Paramstr(i);
HasAction:=true;
end;
end;
end;
if not HasAction then
ShowUsage;
end;
procedure TMakeTool.DoRun;
var
OldCurrDir : String;
i : Integer;
SL : TStringList;
Repo: TFPRepository;
InstPackages: TFPCurrentDirectoryPackagesStructure;
ArchivePackages: TFPArchiveFilenamePackagesStructure;
begin
OldCurrDir:=GetCurrentDir;
Try
InitializeFppkg;
LoadGlobalDefaults;
ProcessCommandLine(true);
SetLength(FPMKUnitDeps,FPMKUnitDepDefaultCount);
for i := 0 to FPMKUnitDepDefaultCount-1 do
FPMKUnitDeps[i]:=FPMKUnitDepsDefaults[i];
MaybeCreateLocalDirs;
if not GFPpkg.Options.CommandLineSection.SkipConfigurationFiles then
begin
GFPpkg.InitializeCompilerOptions;
if GFPpkg.Options.GlobalSection.ConfigVersion = 4 then
begin
// This version did not have any repository configured, but used a
// 'local' and 'global' compiler-setting.
GFPpkg.Options.AddRepositoriesForCompilerSettings(GFPpkg.CompilerOptions);
end;
end
else
begin
GFPpkg.FPMakeCompilerOptions.InitCompilerDefaults;
GFPpkg.CompilerOptions.InitCompilerDefaults;
end;
// The command-line is parsed for the second time, to make it possible
// to override the values in the compiler-configuration file. (like prefix)
ProcessCommandLine(false);
// If CompilerVersion, CompilerOS or CompilerCPU is still empty, use the
// compiler-executable to get them
GFPpkg.FPMakeCompilerOptions.CheckCompilerValues;
GFPpkg.CompilerOptions.CheckCompilerValues;
LoadLocalAvailableMirrors;
// Load local repository, update first if this is a new installation
// errors will only be reported as warning. The user can be bootstrapping
// and do an update later
if not FileExists(GFPpkg.Options.GlobalSection.LocalPackagesFile) then
begin
try
pkghandler.ExecuteAction('','update', GFPpkg);
except
on E: Exception do
pkgglobals.Log(llWarning,E.Message);
end;
end;
FindInstalledPackages(GFPpkg.FPMakeCompilerOptions,true);
// Check for broken dependencies
if not GFPpkg.Options.CommandLineSection.AllowBroken and
(((ParaAction='fixbroken') and (ParaPackages.Count>0)) or
(ParaAction='compile') or
(ParaAction='build') or
(ParaAction='install') or
(ParaAction='archive')) then
begin
pkgglobals.Log(llDebug,SLogCheckBrokenDependenvies);
SL:=TStringList.Create;
if FindBrokenPackages(SL) then
Error(SErrBrokenPackagesFound);
FreeAndNil(SL);
end;
if (ParaAction='install') or (ParaAction='uninstall') or
(ParaAction='fixbroken') then
GFPpkg.ScanInstalledPackagesForAvailablePackages;
if ParaPackages.Count=0 then
begin
// Do not add the fake-repository with the contents of the current directory
// when a list of packages is shown. (The fake repository should not be shown)
if ParaAction<>'list' then
begin
Repo := TFPRepository.Create(GFPpkg);
GFPpkg.RepositoryList.Add(Repo);
Repo.RepositoryType := fprtAvailable;
Repo.RepositoryName := 'CurrentDirectory';
Repo.Description := 'Package in current directory';
InstPackages := TFPCurrentDirectoryPackagesStructure.Create(GFPpkg);
InstPackages.InitializeWithOptions(nil, GFPpkg.Options, GFPpkg.CompilerOptions);
InstPackages.Path := OldCurrDir;
InstPackages.AddPackagesToRepository(Repo);
Repo.DefaultPackagesStructure := InstPackages;
end;
pkghandler.ExecuteAction(CurrentDirPackageName,ParaAction,GFPpkg);
end
else
begin
// Process packages
for i:=0 to ParaPackages.Count-1 do
begin
if sametext(ExtractFileExt(ParaPackages[i]),'.zip') and FileExists(ParaPackages[i]) then
begin
Repo := TFPRepository.Create(GFPpkg);
GFPpkg.RepositoryList.Add(Repo);
Repo.RepositoryType := fprtAvailable;
Repo.RepositoryName := 'ArchiveFile';
Repo.Description := 'Package in archive-file';
ArchivePackages := TFPArchiveFilenamePackagesStructure.Create(GFPpkg);
ArchivePackages.InitializeWithOptions(nil, GFPpkg.Options, GFPpkg.CompilerOptions);
ArchivePackages.ArchiveFileName := ParaPackages[i];
ArchivePackages.AddPackagesToRepository(Repo);
Repo.DefaultPackagesStructure := ArchivePackages;
pkgglobals.Log(llDebug,SLogCommandLineAction,['['+CmdLinePackageName+']',ParaAction]);
pkghandler.ExecuteAction(CmdLinePackageName,ParaAction,GFPpkg);
end
else
begin
pkgglobals.Log(llDebug,SLogCommandLineAction,['['+ParaPackages[i]+']',ParaAction]);
pkghandler.ExecuteAction(ParaPackages[i],ParaAction,GFPpkg);
end;
end;
end;
// Recompile all packages dependent on this package
if (ParaAction='install') and not GFPpkg.Options.CommandLineSection.SkipFixBrokenAfterInstall then
pkghandler.ExecuteAction('','fixbroken',GFPpkg);
Terminate;
except
On E : Exception do
begin
Writeln(StdErr,SErrException);
Writeln(StdErr,E.Message);
Halt(1);
end;
end;
SetCurrentDir(OldCurrDir);
end;
procedure TMakeTool.ShowVersion;
var
Version: TFPVersion;
begin
Version := TFPVersion.Create;
try
Version.Major := version_major;
Version.Minor := version_minor;
Version.Micro := version_micro;
Version.Build := version_build;
Writeln('Version: ', Version.AsString);
finally
Version.Free;
end;
end;
begin
With TMakeTool.Create do
try
run;
finally
Free;
end;
end.