From 6b965a42eb236e4bb2942717e8b42e5c0c260c96 Mon Sep 17 00:00:00 2001 From: Rafael de Figueiredo Alves Date: Thu, 22 Jun 2023 22:21:11 -0300 Subject: [PATCH] Update June 22, 2023 - Removed a variable that isn't been used (thanks to @MatheusM) - Added some more methods to direct access some variables (related to development) - Organized the file to keep things as neat as possible --- Demo/uDemo.pas | 2 +- src/DotEnv4Delphi.pas | 594 ++++++++++++++++++++++++++++-------------- 2 files changed, 403 insertions(+), 193 deletions(-) diff --git a/Demo/uDemo.pas b/Demo/uDemo.pas index bc188e7..6ffb106 100644 --- a/Demo/uDemo.pas +++ b/Demo/uDemo.pas @@ -74,7 +74,7 @@ procedure TForm2.Button3Click(Sender: TObject); procedure TForm2.Button4Click(Sender: TObject); begin - //Exemplo de nova forma de obter alguns tipos de variáveis diretamente, sem precisatr do comando env + //Exemplo de nova forma de obter alguns tipos de variáveis diretamente, sem precisar do comando env Memo1.Lines.Add('Porta: ' + DotEnv.Port.ToString); end; diff --git a/src/DotEnv4Delphi.pas b/src/DotEnv4Delphi.pas index fdcf2fe..1f2ed47 100644 --- a/src/DotEnv4Delphi.pas +++ b/src/DotEnv4Delphi.pas @@ -12,66 +12,115 @@ interface WINDIR, DB_USERNAME, DBUSERNAME, DBPORT, DB_PORT, PORT, HOSTNAME, DB_HOST, DB_USER, DBHOST, DBUSER, DBPASS, DB_PASS, PASSWORD, DBPASSWORD, BASE_URL, TOKEN, API_TOKEN, CONNECTIONSTRING, DEVELOPMENT, DATABASE_URL, SECRET_KEY); {$EndRegion} - +//-------------------------------------------------------------------------------------------------------------------------- {$Region 'DotEnv4Delphi´s interface'} iDotEnv4Delphi = interface ['{3BF1532F-91B1-4C1F-A40A-CD81F8754451}'] + //Main methods function Config(const OnlyFromEnvFile: Boolean = False): iDotEnv4Delphi; overload; function Config(const path: string = ''; OnlyFromEnvFile: Boolean = False): iDotEnv4Delphi; overload; function Env(const name: string): string; overload; function Env(const EnvVar: TEnvVar): string; overload; + function GetVersion: string; + + //Specific methods to access specific variables + + //To access WebAPI specific variables + function BaseUrl: string; + function SecretKey: string; function Port: integer; function Token: string; - function Password: string; - function BaseUrl: string; + + //To access Database Connection specific variables function Hostname: string; function DBHost: string; + function DBPort: integer; function DBPassword: string; function ConnectionString: string; - function isDevelopment: Boolean; + function Password: string; function DatabaseURL: string; - function SecretKey: string; - function GetVersion: string; + + //To access Development specific variables + function isDevelopment: Boolean; + function ComputerName: string; + function ProcessorArchitecture: string; + function TEMP_Dir: string; + function WindowsDir: string; + function AppData: string; + function ClientName: string; + function CommonProgramFiles: string; + function ProgramFiles: String; + function OS: string; + function AppPath: string; end; {$EndRegion} - +//-------------------------------------------------------------------------------------------------------------------------- {$Region 'DotEnv4Delphi´s class declaration'} TDotEnv4Delphi = class(TInterfacedObject, iDotEnv4Delphi) private class var FInstance: iDotEnv4Delphi; + + //Variables to manage the class fromDotEnvFile: Boolean; EnvPath: string; EnvDict: TDictionary; + + //Methods to make the class work procedure ReadEnvFile; function ReadValueFromEnvFile(const key: string): string; public + //Constructors and Destructors constructor Create; Destructor Destroy; override; class function New: iDotEnv4Delphi; + + //Main methods function Config(const OnlyFromEnvFile: Boolean = False): iDotEnv4Delphi; overload; function Config(const path: string = ''; OnlyFromEnvFile: Boolean = False): iDotEnv4Delphi; overload; function Env(const name: string): string; overload; function Env(const EnvVar: TEnvVar): string; overload; + function GetVersion: string; + + //Specific methods to access specific variables + + //To access WebAPI specific variables + function BaseUrl: string; + function SecretKey: string; function Port: integer; function Token: string; - function Password: string; - function BaseUrl: string; + + //To access Database Connection specific variables function Hostname: string; function DBHost: string; + function DBPort: integer; function DBPassword: string; function ConnectionString: string; - function isDevelopment: Boolean; function DatabaseURL: string; - function SecretKey: string; - function GetVersion: string; + function Password: string; + + //To access Development specific variables + function isDevelopment: Boolean; + function ComputerName: string; + function ProcessorArchitecture: string; + function TEMP_Dir: string; + function WindowsDir: string; + function AppData: string; + function ClientName: string; + function CommonProgramFiles: string; + function ProgramFiles: String; + function OS: string; + function AppPath: string; end; {$EndRegion} +//-------------------------------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------------------------- var DotEnv: iDotEnv4Delphi; - + const - fVersion = '1.2.0'; + fVersion = '1.3.0'; //Const to manage versioning +//-------------------------------------------------------------------------------------------------------------------------- implementation @@ -82,34 +131,141 @@ implementation { TDotEnv4Delphi } +{$REGION 'Constructor and Destructor'} +constructor TDotEnv4Delphi.Create; +begin + EnvDict := TDictionary.create; + EnvPath := ExtractFilePath(ParamStr(0)) + '.env'; + fromDotEnvFile := False; + ReadEnvFile; +end; + +//Method to instantiate the class in a Singleton pattern way +class function TDotEnv4Delphi.New: iDotEnv4Delphi; +begin + if not Assigned(FInstance) then + FInstance := Self.Create; + + Result := FInstance; +end; + +destructor TDotEnv4Delphi.Destroy; +begin + FreeAndNil(EnvDict); + inherited; +end; +{$ENDREGION} +//-------------------------------------------------------------------------------------------------------------------------- +{$REGION 'Internal Methods to make the class work'} function TDotEnv4Delphi.ReadValueFromEnvFile(const key: string): string; begin EnvDict.TryGetValue(key.ToUpper, Result); end; -function TDotEnv4Delphi.SecretKey: string; -var - fSecret: string; -begin - fSecret := Env('SECRET_KEY'); +procedure TDotEnv4Delphi.ReadEnvFile; - if fSecret = EmptyStr then - fSecret := Env('Secret_Key'); + function PegarValor(const valor: string): string; - if fSecret = EmptyStr then - fSecret := Env('SecretKey'); + function RemoverComentario(const valor: string): string; + var + positionOfLastQuote: integer; + begin + if (valor.StartsWith('"')) or (valor.StartsWith(#39)) then + begin + positionOfLastQuote := Pos('"', Copy(valor, 2, length(valor) - 1)); + if positionOfLastQuote = 0 then + positionOfLastQuote := Pos(#39, Copy(valor, 2, length(valor) - 1)); - if fSecret = EmptyStr then - fSecret := Env('SECRETKEY'); + if positionOfLastQuote > 0 then + begin + if Pos('#', valor) > positionOfLastQuote then + Result := Copy(valor, 1, Pos('#', valor) - 1); + end; + end + else + begin + if Pos('#', valor) > 0 then + Result := Copy(valor, 1, Pos('#', valor) - 1) + else + Result := valor; + end; + end; - Result := fSecret; -end; + function Interpolar(const valor: string): string; + var + PosIni, PosFim : integer; + chave, ValorChave: string; + begin + Result := valor; + if (not valor.StartsWith('"')) and (not valor.StartsWith(#39)) then + begin + while Pos('${', Result) > 0 do + begin + PosIni := Pos('${', Result); + PosFim := Pos('}', Result); + chave := Copy(Result, PosIni + 2, PosFim - (PosIni + 2)); + ValorChave := Env(chave); + Result := StringReplace(Result, '${' + chave + '}', ValorChave, [rfReplaceAll]); + end; + end; + end; -function TDotEnv4Delphi.Token: string; + function RemoverAspas(const valor: string): string; + var + positionOfLastQuote: integer; + begin + if (valor.StartsWith('"')) or (valor.StartsWith(#39)) then + begin + positionOfLastQuote := Pos('"', Copy(valor, 2, length(valor) - 1)); + if positionOfLastQuote = 0 then + positionOfLastQuote := Pos(#39, Copy(valor, 2, length(valor) - 1)); + + if positionOfLastQuote > 0 then + begin + Result := StringReplace(valor, '"', '', [rfReplaceAll]); + Result := StringReplace(valor, #39, '', [rfReplaceAll]); + end; + end + else + Result := valor; + end; + begin + Result := Trim(RemoverAspas(Interpolar(RemoverComentario(valor)))); + end; + + procedure PopulateDictionary(const Dict: TDictionary); + var + fFile : tstringlist; + position : Integer; + begin + fFile := TStringList.Create; + try + fFile.LoadFromFile(EnvPath); + for position := 0 to fFile.Count - 1 do + begin + if not (fFile.Names[position].ToUpper = EmptyStr) then + begin + Dict.Add(fFile.Names[position].ToUpper, PegarValor(fFile.Values[fFile.Names[position]])); + end; + end; + finally + FreeAndNil(fFile) + end; + end; begin - Result := Env('TOKEN'); + if FileExists(EnvPath) then + begin + EnvDict.Clear; + PopulateDictionary(EnvDict); + end; end; - +{$ENDREGION} +//-------------------------------------------------------------------------------------------------------------------------- +{$REGION 'Main methods of DotEnv4Delphi Class'} +/// +/// Use this method to get the value of the variable you inform in the "name" parameter from either Environment or DotEnv file +/// +/// The name of the variable you want to get its value function TDotEnv4Delphi.Env(const name: string): string; begin if fromDotEnvFile then @@ -124,12 +280,151 @@ function TDotEnv4Delphi.Env(const name: string): string; Result := ReadValueFromEnvFile(name); end; +/// +/// Use this method to get the value of the variable you inform in the "EnvVar" parameter from either Environment or DotEnv file +/// +/// The Enum name of the variable you want to get its value +function TDotEnv4Delphi.Env(const EnvVar: TEnvVar): string; +begin + Result := Env(GetEnumName(TypeInfo(TEnvVar), integer(EnvVar))); +end; + +/// +/// Use this method to get the version of DotEnv4Delphi +/// +function TDotEnv4Delphi.GetVersion: string; +begin + Result := fVersion; +end; + +/// +/// Use this method to set some specific configurations. The first could be if you only want to read values from a DotEnv file +/// +/// Set it to True to only use variables declared in the DotEnv file function TDotEnv4Delphi.Config(const OnlyFromEnvFile: Boolean): iDotEnv4Delphi; begin Result := Self; fromDotEnvFile := OnlyFromEnvFile; end; +/// +/// Use this method to set some specific configurations. The first could be if you only want to read values from a DotEnv file and you can specify a path to the DotEnv file +/// +/// Set the path of the DotEnv file you want to use +/// Set it to True to only use variables declared in the DotEnv file +function TDotEnv4Delphi.Config(const path: string; OnlyFromEnvFile: Boolean): iDotEnv4Delphi; +begin + Result := Self; + fromDotEnvFile := OnlyFromEnvFile; + if (path <> EmptyStr) and (path <> EnvPath) then + begin + EnvPath := path; + ReadEnvFile; + end; +end; +{$ENDREGION} +//-------------------------------------------------------------------------------------------------------------------------- +{$REGION 'Methods to help development'} +/// +/// Gets the variable value and returns True if the environment is set to Development +/// +function TDotEnv4Delphi.isDevelopment: Boolean; +var + Dev: string; +begin + Result := false; + + Dev := Env('Development'); + + if Dev = EmptyStr then + Dev := Env('DEVELOPMENT'); + + if (Dev <> EmptyStr) and (Dev.ToUpper = 'TRUE') then + Result := True; +end; + +/// +/// Gets the variable value and returns the Operating System +/// +function TDotEnv4Delphi.OS: string; +begin + Result := Env(TEnvVar.OS); +end; + +/// +/// Gets the variable value and returns the Name of Client machine. +/// +function TDotEnv4Delphi.ClientName: string; +begin + Result := Env(TEnvVar.CLIENTNAME); +end; + +/// +/// Gets the variable value and returns the Path of common program files folder. +/// +function TDotEnv4Delphi.CommonProgramFiles: string; +begin + Result := Env(TEnvVar.COMMONPROGRAMFILES); +end; + +/// +/// Gets the variable value and returns the Name of Computer code is running on. +/// +function TDotEnv4Delphi.ComputerName: string; +begin + Result := Env(TEnvVar.COMPUTERNAME); +end; + +/// +/// Gets the variable value and returns the Type of CPU architecture. For example, X86 for Intel Pentium processors. +/// +function TDotEnv4Delphi.ProcessorArchitecture: string; +begin + Result := Env(TEnvVar.PROCESSOR_ARCHITECTURE); +end; + +/// +/// Gets the variable value and returns the Path of the program files folder. +/// +function TDotEnv4Delphi.ProgramFiles: String; +begin + Result := Env(TEnvVar.PROGRAMFILES); +end; + +/// +/// Gets the variable value and returns the Path of the Windows folder. +/// +function TDotEnv4Delphi.WindowsDir: string; +begin + Result := Env(TEnvVar.WINDIR); +end; + +/// +/// Gets the variable value and returns the Path of the temporary files folder. +/// +function TDotEnv4Delphi.TEMP_Dir: string; +begin + Result := Env(TEnvVar.TEMP); +end; + +/// +/// Gets the variable value and returns the Path of the application data folder. +/// +function TDotEnv4Delphi.AppData: string; +begin + Result := Env(TEnvVar.APPDATA); +end; + +function TDotEnv4Delphi.AppPath: string; +begin + Result := ExtractFileDir(ParamStr(0)); +end; +{$ENDREGION} +//-------------------------------------------------------------------------------------------------------------------------- +{$REGION 'Methods to access variables for a WebAPI'} +/// +/// Read the variable and fill the BaseUrl of the webAPI +/// function TDotEnv4Delphi.BaseUrl: string; var Base: string; @@ -142,17 +437,58 @@ function TDotEnv4Delphi.BaseUrl: string; Result := Base; end; -function TDotEnv4Delphi.Config(const path: string; OnlyFromEnvFile: Boolean): iDotEnv4Delphi; +/// +/// Read the variable and fill the Secret Key of the webAPI +/// +function TDotEnv4Delphi.SecretKey: string; +var + fSecret: string; begin - Result := Self; - fromDotEnvFile := OnlyFromEnvFile; - if (path <> EmptyStr) and (path <> EnvPath) then - begin - EnvPath := path; - ReadEnvFile; - end; + fSecret := Env('SECRET_KEY'); + + if fSecret = EmptyStr then + fSecret := Env('Secret_Key'); + + if fSecret = EmptyStr then + fSecret := Env('SecretKey'); + + if fSecret = EmptyStr then + fSecret := Env('SECRETKEY'); + + Result := fSecret; +end; + +/// +/// Read the variable and fill the Port of the webAPI +/// +function TDotEnv4Delphi.Port: integer; +var + _port: string; +begin + Result := 0; + + _port := Env('Port'); + + if _Port = EmptyStr then + _port := Env('PORT'); + + if _Port <> EmptyStr then + Result := StrToInt(_Port); end; +/// +/// Read the variable and fill the Token of the webAPI +/// +function TDotEnv4Delphi.Token: string; +begin + Result := Env('TOKEN'); +end; +{$ENDREGION} +//-------------------------------------------------------------------------------------------------------------------------- +{$REGION 'Methods to work with Database connections'} +/// +/// Read variable and get the connection string +/// function TDotEnv4Delphi.ConnectionString: string; var ConnStr: string; @@ -171,14 +507,9 @@ function TDotEnv4Delphi.ConnectionString: string; Result := ConnStr; end; -constructor TDotEnv4Delphi.Create; -begin - EnvDict := TDictionary.create; - EnvPath := ExtractFilePath(ParamStr(0)) + '.env'; - fromDotEnvFile := False; - ReadEnvFile; -end; - +/// +/// Read variable and get the Database URL +/// function TDotEnv4Delphi.DatabaseURL: string; var fDBURL: string; @@ -197,6 +528,9 @@ function TDotEnv4Delphi.DatabaseURL: string; Result := fDBURL; end; +/// +/// Read variable and get the DB Host +/// function TDotEnv4Delphi.DBHost: string; var db_host: string; @@ -215,6 +549,9 @@ function TDotEnv4Delphi.DBHost: string; Result := db_host; end; +/// +/// Read variable and get the DB Password +/// function TDotEnv4Delphi.DBPassword: string; var Pass: string; @@ -233,37 +570,27 @@ function TDotEnv4Delphi.DBPassword: string; Result := Pass; end; -destructor TDotEnv4Delphi.Destroy; -begin - FreeAndNil(EnvDict); - inherited; -end; - -function TDotEnv4Delphi.isDevelopment: Boolean; +/// +/// Read variable and get the Port to use to access the Database +/// +function TDotEnv4Delphi.DBPort: integer; var - Dev: string; + _port: string; begin - Result := false; - - Dev := Env('Development'); + Result := 0; - if Dev = EmptyStr then - Dev := Env('DEVELOPMENT'); + _port := Env('DBPort'); - if (Dev <> EmptyStr) and (Dev.ToUpper = 'TRUE') then - Result := True; -end; - -function TDotEnv4Delphi.Env(const EnvVar: TEnvVar): string; -begin - Result := Env(GetEnumName(TypeInfo(TEnvVar), integer(EnvVar))); -end; + if _Port = EmptyStr then + _port := Env('DBPORT'); -function TDotEnv4Delphi.GetVersion: string; -begin - Result := fVersion; + if _Port <> EmptyStr then + Result := StrToInt(_Port); end; +/// +/// Read variable and get the Hostname to connect to the Database +/// function TDotEnv4Delphi.Hostname: string; var _host: string; @@ -282,14 +609,9 @@ function TDotEnv4Delphi.Hostname: string; Result := _host; end; -class function TDotEnv4Delphi.New: iDotEnv4Delphi; -begin - if not Assigned(FInstance) then - FInstance := Self.Create; - - Result := FInstance; -end; - +/// +/// Read variable and get the Password +/// function TDotEnv4Delphi.Password: string; var _pass: string; @@ -301,124 +623,12 @@ function TDotEnv4Delphi.Password: string; Result := _pass; end; - -function TDotEnv4Delphi.Port: integer; -var - _port: string; -begin - Result := 0; - - _port := Env('Port'); - - if _Port = EmptyStr then - _port := Env('PORT'); - - if _Port <> EmptyStr then - Result := StrToInt(_Port); -end; - -procedure TDotEnv4Delphi.ReadEnvFile; - - function PegarValor(const valor: string): string; - - function RemoverComentario(const valor: string): string; - var - positionOfLastQuote: integer; - begin - if (valor.StartsWith('"')) or (valor.StartsWith(#39)) then - begin - positionOfLastQuote := Pos('"', Copy(valor, 2, length(valor) - 1)); - if positionOfLastQuote = 0 then - positionOfLastQuote := Pos(#39, Copy(valor, 2, length(valor) - 1)); - - if positionOfLastQuote > 0 then - begin - if Pos('#', valor) > positionOfLastQuote then - Result := Copy(valor, 1, Pos('#', valor) - 1); - end; - end - else - begin - if Pos('#', valor) > 0 then - Result := Copy(valor, 1, Pos('#', valor) - 1) - else - Result := valor; - end; - end; - - function Interpolar(const valor: string): string; - var - PosIni, PosFim : integer; - chave, ValorChave: string; - begin - Result := valor; - if (not valor.StartsWith('"')) and (not valor.StartsWith(#39)) then - begin - while Pos('${', Result) > 0 do - begin - PosIni := Pos('${', Result); - PosFim := Pos('}', Result); - chave := Copy(Result, PosIni + 2, PosFim - (PosIni + 2)); - ValorChave := Env(chave); - Result := StringReplace(Result, '${' + chave + '}', ValorChave, [rfReplaceAll]); - end; - end; - end; - - function RemoverAspas(const valor: string): string; - var - positionOfLastQuote: integer; - begin - if (valor.StartsWith('"')) or (valor.StartsWith(#39)) then - begin - positionOfLastQuote := Pos('"', Copy(valor, 2, length(valor) - 1)); - if positionOfLastQuote = 0 then - positionOfLastQuote := Pos(#39, Copy(valor, 2, length(valor) - 1)); - - if positionOfLastQuote > 0 then - begin - Result := StringReplace(valor, '"', '', [rfReplaceAll]); - Result := StringReplace(valor, #39, '', [rfReplaceAll]); - end; - end - else - Result := valor; - end; - begin - Result := Trim(RemoverAspas(Interpolar(RemoverComentario(valor)))); - end; - - procedure PopulateDictionary(const Dict: TDictionary); - var - fFile : tstringlist; - EnvFile : string; - position : Integer; - begin - fFile := TStringList.Create; - try - fFile.LoadFromFile(EnvPath); - for position := 0 to fFile.Count - 1 do - begin - if not (fFile.Names[position].ToUpper = EmptyStr) then - begin - Dict.Add(fFile.Names[position].ToUpper, PegarValor(fFile.Values[fFile.Names[position]])); - end; - end; - finally - FreeAndNil(fFile) - end; - end; -begin - if FileExists(EnvPath) then - begin - EnvDict.Clear; - PopulateDictionary(EnvDict); - end; -end; +{$ENDREGION} initialization begin + //Here the instance of the DotEnv4Delphi is created to be used in a Sigleton Pattern way DotEnv := tDotEnv4Delphi.New; end;