initial commit from lost SVN repo

This commit is contained in:
fatalerrors
2023-10-06 15:59:41 +02:00
parent 8186c7b10e
commit f600f5706a
1496 changed files with 666909 additions and 73 deletions

685
common/ucommon.pas Normal file
View File

@@ -0,0 +1,685 @@
{
********************************************************************************
SPackGui (common files)
Copyright (C) 2013 Geoffray Levasseur <geoffray.levasseurbrandin@numericable.fr>.
Copyright (C) <date> <add your name and mail address here>
http://www.geoffray-levasseur.org/
http://0.tuxfamilly.org/
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
********************************************************************************
Description:
some common vars and functions
********************************************************************************
}
unit uCommon;
{$include defines.inc}
interface
uses
Classes, IniFiles, Forms;
type
TCharSet = set of Char;
const
//for test we don't touch to real system files
{$IFDEF TEST}
//you need to change everything before the ELSE compiler directive
//accordingly to your own test path
sDefaultLogFileName = '/share/src/pascal/0linux/log/spackgui.log';
sLockFile = '/share/src/pascal/0linux/log/spackgui.lock';
sIconBaseDir = '/share/src/pascal/0linux/icons';
sRootUserName = 'fatalerrors'; //when testing we want to make change even if non root
sDefaultSpackPkgDir = '/share/src/pascal/0linux/testpack';
sDefaultConfDir = '/share/src/pascal/0linux/testconf';
sDefaultRepoIndexDir = sDefaultConfDir;
sDefaultDwlDir = '/share/src/pascal/0linux/packages';
sRepoConfFile = 'depots.conf';
sMainConfFile = 'spackgui.conf';
{$ELSE}
sDefaultLogFileName = {$LOCALSTATEDIR}'/log/spackgui.log';
sLockFile = {$LOCALSTATEDIR}'/lock/spackgui.lock';
sIconBaseDir = {$PREFIX}'/share/spackgui/icons';
sRootUserName = 'root';
sDefaultSpackPkgDir = {$LOCALSTATEDIR}'/lib/spack';
sDefaultConfDir = {$SYSCONFDIR}'/spackgui';
sDefaultRepoIndexDir = sDefaultConfDir;
sDefaultDwlDir = {$LOCALSTATEDIR}'/cache/spack';
sRepoConfFile = 'depots.conf';
sMainConfFile = 'spackgui.conf';
{$ENDIF}
sDefaultInstallPackage = 'spackadd %s';
sDefaultReinstallPackage = 'spackadd -f %s';
sDefaultRemovePackage = 'spackrm %s';
sDefaultUpdatePackage = 'spackadd %s';
AnsiLineFeed = AnsiChar(#10);
AnsiCarriageReturn = AnsiChar(#13);
AnsiCrLf = AnsiString(#13#10);
iDefaultProxyPort = 3128;
RegExprOperator: TCharSet = ['&', '|', '#'];
var
sConfDir: string; //place where configuration files will be stored
sSpackPkgDir: string; //installed packages repository
sRepoIndexDir: string; //place where repositories metadata are stored
sDwlDir: string; //place where packages are downloaded before install
sDefaultRepo: string; //default repo used for upgrades
bChangeAllowed: Boolean; //global saying if change are allowed or not
bUnitsAreDecimal: Boolean; //user may want decimal
cThousandSep: Char; //thousand separator (#0 means none)
cDecimalSep: Char; //decimal separator
bNoColors: Boolean; //colorize listview or not
bShowGrig: Boolean; //show a grid in listview or not
sInstallPackage: string; //command to install a package
sReinstallPackage: string; //command to reinstall an installed package
sRemovePackage: string; //command to remove an installed package
sUpdatePackage: string; //command to update an installed package
tLockFile: Text; //pointer to lockfile
iniMain: TIniFile; //main configuration file object
iniRepo: TIniFile; //repositories configuration file object
bReadOnly: Boolean; //when non-root we are read-only
slRepoList: TStringList; //list of non installed packages repository
slDeprecated: TStringList; //list of deprecated packages
sArch: string; //used architecture
//proxy settings
sHttpProxyAddress: string;
iHttpProxyPort: Integer;
sHttpProxyUser: string;
sHttpProxyPass: string;
sFtpProxyAddress: string;
iFtpProxyPort: Integer;
sFtpProxyUser: string;
sFtpProxyPass: string;
//write a string list in an ini file, the TInifile must be initialized
procedure IniWriteStrings(IniFile: TIniFile; const Section, Ident: string;
Str: TStrings);
//read a string list in an ini file, the TInifile must be initialized
procedure IniReadStrings(IniFile: TIniFile; const Section, Ident: string;
Str: TStrings);
// SPack use that format: pkgname-version-arch-build{,.spack}
procedure DecomposePackageName(const S: ansistring;
out Name, Version: ansistring; out Build: Byte; out Arch: ansistring);
// Extract package name a full spack format string
function ExtractPackageName(const S: ansistring): ansistring;
// Format numbers for file size display (with units)
// the base unit is Byte but spack have KB as base unit
function DispSize(const Size: integer): string;
//convert strings generated by the previous function to LongInt
function SizeStrToInt(const SzStr: string): LongInt;
// Get Major, minor and release number (sometimes there's letters so we keep that
// string)... Exotic version numbering gets remainings information in rem var
procedure DecomposeVersion(const V: string; out Maj, Min, Rel, Rem: string);
// If V1 > V2 result is 1, 0 if equal and -1 if V1 < V2
function CompareVersion(const V1, V2: string): ShortInt;
// Load/save window geometry in main ini file
procedure LoadWindowGeometry(Form: TForm);
procedure SaveWindowGeometry(Form: TForm);
// Load/save repository configuration informations
procedure LoadRepoSettings;
procedure SaveRepoSettings;
// Initialize config dir and inifiles
procedure InitConf;
// Get address of a repository from it's name
function GetRepoAddress(const RepoName: string): string;
implementation
uses
SysUtils, uStrings, uUtils, uDebug, Controls;
procedure IniWriteStrings(IniFile: TIniFile; const Section, Ident: string;
Str: TStrings);
var
I: integer;
OldCount: Integer;
begin
//old number of line as needed
OldCount := IniFile.ReadInteger(Section, Ident + rsConfNameCount, 0);
if OldCount > Str.Count then //more lines in old config ?
for I := Str.Count to OldCount do
IniFile.DeleteKey(Section, Ident + IntToStr(I)); //erase old keys
IniFile.WriteInteger(Section, Ident + rsConfNameCount, Str.Count); //new count
for I := 0 to Str.Count - 1 do
IniFile.WriteString(Section, Ident + IntToStr(I), Str[I]); //write each line
end;
procedure IniReadStrings(IniFile: TIniFile; const Section, Ident: string;
Str: TStrings);
var
I, N: Integer;
begin
Str.Clear;
N := IniFile.ReadInteger(Section, Ident + rsConfNameCount, 0);
for I := 0 to N - 1 do
Str.Add(IniFile.ReadString(Section, Ident + IntToStr(I), ''));
end;
procedure DecomposePackageName(const S: ansistring;
out Name, Version: ansistring; out Build: Byte; out Arch: ansistring);
var
I, J: integer;
Tmp: string;
begin
I := Length(S);
while S[I] <> '-' do
Dec(I);
Tmp := Copy(S, I + 1, Length(S) - I + 1);
if Trim(Tmp) <> '' then
Build := StrToInt(Tmp)
else
Build := 0;
Dec(I);
J := I;
while S[I] <> '-' do
Dec(I);
Arch := Copy(S, I + 1, J - I);
Dec(I);
J := I;
while S[I] <> '-' do
Dec(I);
Version := Copy(S, I + 1, J - I);
Name := Copy(S, 1, I - 1);
//the following is unneeded as we shouldn't have '-' in versions
//--------------------------------------------------------------
//I := Length(Name);
//while (I > 1) and (Name[I] <> '-') do //still some '-' in the name ?
// Dec(I);
//if I > 1 then //name or version contains '-': try to analyse this correctly...
// if (Name[I + 1] in ['0'..'9']) and (Name[Length(Name)] in ['0'..'9']) then
// begin
// Tmp := Copy(Name, I + 1, Length(Name) - I + 1);
// Version := Tmp + '-' + Version;
// Name := Copy(S, 1, I - 1);
// end;
end;
function ExtractPackageName(const S: ansistring): ansistring;
var
I, P: integer;
Tmp: string;
begin
if UpperCase(ExtractFileExt(S)) = rsSpackExt then
Tmp := RemoveFileExt(S)
else
Tmp := S;
P := Pos(' ', S);
if P <> 0 then
begin
Tmp := Copy(Tmp, P + 1, Length(Tmp) - P);
P := Pos(' ', Tmp);
Tmp := Copy(Tmp, 1, P - 1);
end;
I := Length(Tmp);
//skip build
while Tmp[I] <> '-' do
Dec(I);
Dec(I);
//skip arch
while Tmp[I] <> '-' do
Dec(I);
Dec(I);
//skip version
while Tmp[I] <> '-' do
Dec(I);
Result := Copy(S, 1, I - 1);
end;
function DispSize(const Size: LongInt): string;
var
Diviser, I, N: Integer;
Unt: string;
begin
if bUnitsAreDecimal then
Diviser := 1000
else
Diviser := 1024;
// we go up to GB as bigger is probably not needed for now in that kind of app
if Size > (Diviser * 10) then //if true at least 10KB
if (Size div Diviser) > (Diviser * 10) then //10MB
if ((Size div Diviser) div Diviser) > (Diviser * 10) then //10GB
begin
Result := IntToStr(((Size div Diviser) div Diviser) div Diviser);
if ((Size div Diviser) div Diviser) mod Diviser <> 0 then
Result := Result + cDecimalSep +
Copy(IntToStr(((Size div Diviser) div Diviser) mod Diviser), 1, 2);
if bUnitsAreDecimal then
Unt := rsGB
else
Unt := rsGiB;
end else
begin
Result := IntToStr((Size div Diviser) div Diviser);
if (Size div Diviser) mod Diviser <> 0 then
Result := Result + cDecimalSep +
Copy(IntToStr((Size div Diviser) mod Diviser), 1, 2);
if bUnitsAreDecimal then
Unt := rsMB
else
Unt := rsMiB;
end
else
begin
Result := IntToStr(Size div Diviser);
if Size mod Diviser <> 0 then
Result := Result + cDecimalSep + Copy(IntToStr(Size mod Diviser), 1, 2);
if bUnitsAreDecimal then
Unt := rsKB
else
Unt := rsKiB;
end else
begin
Unt := rsByte;
Result := IntToStr(Size);
end;
if (((Length(Result) > 3) and (Pos(cDecimalSep, Result) = 0)) or
((Pos(cDecimalSep, Result) <> 0) and (Length(Result) > 5))) and
(cThousandSep <> #0) then
begin
N := Pos(cDecimalSep, Result) - 1;
if N <= 0 then
N := Length(Result);
I := 0;
while N >= 1 do
begin
if (I <> 0) and (I mod 3 = 0) then
Insert(cThousandSep, Result, N + 1);
Inc(I);
Dec(N);
end;
end;
Result := Result + ' ' + Unt;
end;
function SizeStrToInt(const SzStr: string): LongInt;
var
Mul: Integer;
Val: Single;
S: string;
begin
S := Trim(SzStr);
if S = '' then
begin
Result := 0;
Exit;
end;
Mul := 1;
if Pos(rsKiB, S) > 1 then
begin
Mul := 1024;
S := Copy(S, 1, Length(S) - 4);
end else
if Pos(rsKB, S) > 1 then
begin
Mul := 1000;
S := Copy(S, 1, Length(S) - 3);
end else
if Pos(rsMiB, S) > 1 then
begin
Mul := 1024 * 1024;
S := Copy(S, 1, Length(S) - 4);
end else
if Pos(rsMB, S) > 1 then
begin
Mul := 1000 * 1000;
S := Copy(S, 1, Length(S) - 3);
end else
if Pos(rsGiB, S) > 1 then
begin
Mul := 1024 * 1024 * 1024;
S := Copy(S, 1, Length(S) - 4);
end else
if Pos(rsGB, S) > 1 then
begin
Mul := 1000 * 1000 * 1000;
S := Copy(S, 1, Length(S) - 3);
end else
if Pos(rsByte, S) > 1 then
S := Copy(S, 1, Length(S) - 2);
while Pos(cThousandSep, S) <> 0 do
Delete(S, Pos(cThousandSep, S), 1);
if Pos(cDecimalSep, S) <> 0 then
S[Pos(cDecimalSep, S)] := '.';
try
Val := StrToFloat(S);
except
PrintLnDbg(Format('E Error while converting %s with intermediate %s to float',
[SzStr, S]));
Result := 0;
Exit;
end;
try
Result := Round(Val * Mul);
except
PrintLnDbg(Format('E Error while converting %s: float is to big',
[SzStr, S]));
Result := 0;
end;
end;
procedure DecomposeVersion(const V: string; out Maj, Min, Rel, Rem: string);
var
I: integer;
Tmp: string;
begin
Rem := '';
Tmp := '';
I := Pos('.', V);
if (I = 0) then
I := Pos('_', V);
if I > 0 then
begin
Maj := Copy(V, 1, I - 1);
Tmp := Copy(V, I + 1, Length(V) - I);
if Length(V) = 0 then
begin
Min := '';
Rel := '';
Rem := '';
Exit;
end;
I := Pos('.', Tmp);
if (I = 0) then
I := Pos('_', Tmp);
if I > 0 then
begin
Min := Copy(Tmp, 1, I - 1);
Tmp := Copy(Tmp, I + 1, Length(Tmp) - I);
if Length(Tmp) = 0 then
begin
Rel := '';
Rem := '';
Exit;
end;
I := Pos('.', Tmp);
if (I = 0) then
I := Pos('_', Tmp);
if I > 0 then
begin
Rel := Copy(Tmp, 1, I - 1);
Tmp := Copy(Tmp, I + 1, Length(Tmp) - I);
if Length(Tmp) = 0 then
Exit;
Rem := Tmp;
end else
Rel := Tmp;
end else
Min := Tmp;
end else
Maj := V;
end;
function CompareVersion(const V1, V2: string): ShortInt;
var
Maj1, Maj2: string;
Min1, Min2: string;
Rel1, Rel2: string;
Rem1, Rem2: string;
begin
DecomposeVersion(V1, Maj1, Min1, Rel1, Rem1);
DecomposeVersion(V2, Maj2, Min2, Rel2, Rem2);
Result := 0;
//test remainning informations
if Rem1 > Rem2 then
Result := 1
else
if Rem1 < Rem2 then
Result := -1;
//test release (overide previous test)
if Rel1 > Rel2 then
Result := 1
else
if Rel1 < Rel2 then
Result := -1;
//test minor
if Min1 > Min2 then
Result := 1
else
if Min1 < Min2 then
Result := -1;
//test major
if Maj1 > Maj2 then
Result := 1
else
if Maj1 < Maj2 then
Result := -1;
end;
procedure LoadWindowGeometry(Form: TForm);
begin
Form.Left := iniMain.ReadInteger(Form.Name, rsConfNameLeft, Form.Left);
Form.Top := iniMain.ReadInteger(Form.Name, rsConfNameTop, Form.Top);
if Form.BorderStyle <> bsDialog then
begin
Form.Width := iniMain.ReadInteger(Form.Name, rsConfNameWidth, Form.Width);
Form.Height := iniMain.ReadInteger(Form.Name, rsConfNameHeight, Form.Height);
if iniMain.ReadBool(Form.Name, rsConfNameMaximized, False) then
Form.WindowState := wsMaximized;
end;
end;
procedure SaveWindowGeometry(Form: TForm);
var
Maxi: Boolean;
begin
iniMain.WriteInteger(Form.Name, rsConfNameLeft, Form.Left);
iniMain.WriteInteger(Form.Name, rsConfNameTop, Form.Top);
if Form.BorderStyle <> bsDialog then
begin
iniMain.WriteInteger(Form.Name, rsConfNameWidth, Form.Width);
iniMain.WriteInteger(Form.Name, rsConfNameHeight, Form.Height);
Maxi := Form.WindowState = wsMaximized;
iniMain.WriteBool(Form.Name, rsConfNameMaximized, Maxi);
end;
end;
procedure InitConf;
var
UseHome: Boolean;
ProxyTmp, Port: string;
begin
bReadOnly := False;
sConfDir := sDefaultConfDir;
if not DirectoryExists(sConfDir) then
if DirectoryIsReadOnly(ExtractFileDir(sConfDir)) then
UseHome := True
else
MkDir(sConfDir)
else
if DirectoryIsReadOnly(sConfDir) then
UseHome := True;
if UseHome then
if not DirectoryIsReadOnly(GetHomePath) then
begin
sConfDir := GetHomePath + rsFreeDesktopConfig + '/' + rsHomeConfDir; //freedestop compliant
if not DirectoryExists(sConfDir) then
begin
if not DirectoryExists(GetHomePath + rsFreeDesktopConfig) then
MkDir(GetHomePath + rsFreeDesktopConfig);
MkDir(sConfDir);
end
end else
bReadOnly := True;
iniMain := TIniFile.Create(sConfDir + '/' + sMainConfFile);
PrintLnDbg(Format(rsInfoInitConfFile, [iniMain.FileName]), vlLow);
iniRepo := TIniFile.Create(sConfDir + '/' + sRepoConfFile);
PrintLnDbg(Format(rsInfoInitConfFile, [iniRepo.FileName]), vlLow);
case GetUsedCPU of
cpu386: sArch := 'i686';
cpuX86_64: sArch := 'x86_64';
cpuArm: sArch := 'arm';
end;
//environment settings
sInstallPackage := iniMain.ReadString(rsConfSectionCommand,
rsConfNameInstallCommand, sDefaultInstallPackage);
sReinstallPackage := iniMain.ReadString(rsConfSectionCommand,
rsConfNameReinstallCommand, sDefaultReinstallPackage);
sRemovePackage := iniMain.ReadString(rsConfSectionCommand,
rsConfNameRemoveCommand, sDefaultRemovePackage);
sUpdatePackage := iniMain.ReadString(rsConfSectionCommand,
rsConfNameUpdateCommand, sDefaultUpdatePackage);
sSpackPkgDir := iniMain.ReadString(rsConfSectionPaths, rsConfNameInstPkgPath,
sDefaultSpackPkgDir);
sDwlDir := iniMain.ReadString(rsConfSectionPaths, rsConfNamePkgDownloadPath,
sDefaultDwlDir);
sRepoIndexDir := iniMain.ReadString(rsConfSectionPaths,
rsConfNameRepoDownloadPath, sDefaultRepoIndexDir);
ProxyTmp := iniMain.ReadString(rsConfSectionProxy, rsConfNameHttpProxy, '');
GetProxyInfo(ProxyTmp, sHttpProxyUser, sHttpProxyPass, sHttpProxyAddress, Port);
try
if Trim(Port) <> '' then
iHttpProxyPort := StrToInt(Port);
finally
//do nothing
end;
ProxyTmp := iniMain.ReadString(rsConfSectionProxy, rsConfNameFtpProxy, '');
GetProxyInfo(ProxyTmp, sFtpProxyUser, sFtpProxyPass, sFtpProxyAddress, Port);
try
if Trim(Port) <> '' then
iFtpProxyPort := StrToInt(Port);
finally
//do nothing
end;
//display settings
try
cThousandSep := Chr(iniMain.ReadInteger(rsConfSectionDisplay,
rsConfNameThousandsSep, Ord(' ')));
except
cThousandSep := ' ';
end;
try
cDecimalSep := Chr(iniMain.ReadInteger(rsConfSectionDisplay,
rsConfNameDecimalSep, Ord(',')));
except
cDecimalSep := ',';
end;
bUnitsAreDecimal := iniMain.ReadBool(rsConfSectionDisplay,
rsConfNameDecimalUnits, False);
bShowGrig := iniMain.ReadBool(rsConfSectionDisplay, rsConfNameShowGrid, False);
bNoColors := iniMain.ReadBool(rsConfSectionDisplay, rsConfNameNoColors, False);
end;
procedure LoadRepoSettings;
var
I: Integer;
begin
PrintLnDbg(rsInfoLoadingRepoSettings, vlLow);
if iniRepo = nil then
Exit; //exception goes here
if slRepoList = nil then
slRepoList := TStringList.Create
else
slRepoList.Clear;
iniRepo.ReadSections(slRepoList);
for I := 0 to slRepoList.Count - 1 do
begin
if iniRepo.ReadBool(slRepoList[I], rsConfNameDefault, False) then
sDefaultRepo := slRepoList[I];
slRepoList[I] := slRepoList[I] + '=' +
iniRepo.ReadString(slRepoList[I], rsConfNameAddress, '');
end;
PrintLnDbg(Format(rsInfoDefaultRepo, [sDefaultRepo]), vlLow);
end;
procedure SaveRepoSettings;
var
I, N: Integer;
Name, Address: string;
begin
if bReadOnly then
Exit; //this should not happen: trigger an exception when conception is over
if (slRepoList = nil) or (iniRepo = nil) then
Exit; //should not happen: an exception goes here
for I := 0 to slRepoList.Count - 1 do
begin
N := Pos('=', slRepoList[I]);
if N = 0 then
Continue; //show an error message
Name := Trim(Copy(slRepoList[I], 1, N - 1));
Address := Trim(Copy(slRepoList[I], N + 1, Length(slRepoList[I]) - N));
iniRepo.WriteString(Name, rsConfNameAddress, Address);
iniRepo.WriteBool(Name, rsConfNameDefault, Name = sDefaultRepo);
end;
iniRepo.UpdateFile;
end;
function GetRepoAddress(const RepoName: string): string;
var
I: Integer;
begin
for I := 0 to slRepoList.Count - 1 do
if Pos(RepoName, slRepoList[I]) = 1 then
Result := Copy(slRepoList[I], Pos('=', slRepoList[I]) + 1,
Length(slRepoList[I]) - Pos('=', slRepoList[I]) + 1);
end;
end.