User Tools

Site Tools


k6:k6.1:k6.1.2:start

6.1.2 Base directories

Before turning to the static properties Desktop.ConfigDir, Desktop.DataDir, Desktop.RuntimeDir and Desktop.CacheDir of the Desktop (gb.desktop) class, you should read the information at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [1] carefully. The chapter in [1] gives a good introduction to the concept of base directories defined by environment variables such as $XDG_CONFIG_HOME or $XDG_DATA_HOME, to name two.

In a console, for selected environment variables, these values were read out for the user 'hans' (that is the author):

hans@mint-183 ~ $ echo $XDG_CONFIG_HOME
(blank or not set)
hans@mint-183 ~ $ echo $XDG_DATA_HOME
(blank or not set)
hans@mint-183 ~ $ echo $XDG_RUNTIME_DIR
/run/user/1000
hans@mint-183 ~ $ echo $XDG_CACHE_HOME
(blank or not set)

With this source code snippet you can query the current paths on your system as Gambas has read them out and defined them in case they are empty or not set:

Print "ConfigDir  = "; Desktop.ConfigDir    ' $XDG_CONFIG_HOME
Print "DataDir    = "; Desktop.DataDir      ' $XDG_DATA_HOME
Print "RuntimeDir = "; Desktop.RuntimeDir   ' $XDG_RUNTIME_DIR
Print "CacheDir   = "; Desktop.CacheDir     ' $XDG_CACHE_HOME

In the Gambas IDE console, the author produced the following output (B):

ConfigDir  = /home/hans/.config
DataDir    = /home/hans/.local/share
RuntimeDir = /run/user/1000
CacheDir   = /home/hans/.cache

The difference between the two outputs (A) and (B) is quickly explained: If one of the above environment variables is empty or not set, Gambas will fall back on standard directories according to the specification in [1].

In addition, if the environment variable $XDG_RUNTIME_DIR is empty or not set, then applications should fall back on a substitute directory such as /tmp with similar functionality. In the file in the Gambas source code gambas_source_code/comp/src/gb.desktop/.src/Desktop.class, the Desktop.ConfigDir, Desktop.DataDir, Desktop.RuntimeDir and Desktop.CacheDir properties of the Desktop (gb.desktop) class are defined as function values like this:

Static Private Function ConfigDir_Read() As String
  Return GetDir("XDG_CONFIG_HOME", User.Home &/ ".config")
End
Static Private Function DataDir_Read() As String
  Return GetDir("XDG_DATA_HOME", User.Home &/ ".local/share")
End
Static Private Function CacheDir_Read() As String
  Return GetDir("XDG_CACHE_HOME", User.Home &/ ".cache")
End
Static Private Function RuntimeDir_Read() As String
  Dim sPath As String = Env["XDG_RUNTIME_DIR"]
  If Not sPath Then
    sPath = File.Dir(Temp$())
    Error "gb.desktop: warning: XDG_RUNTIME_DIR is not set default to "; sPath
  Endif
  Return sPath
End

6.1.2.1 Base Directory 1 - Desktop.ConfigDir

Static Property Read ConfigDir As String

Returns the base directory where user-specific configuration files should be stored.

Examples:

Public sConfigDir As String
 
Public Sub _new()
  ...
  sGlobalConfigDir = Desktop.ConfigDir &/ sVendor &/ Lower(sAppName) ' ~/.config/gambasbook/pathproject
  If Not Exist(sGlobalConfigDir) Then Shell.MkDir(sGlobalConfigDir)
  ...
  hSettings = New Settings(sGlobalConfigDir &/ File.SetExt(Lower(sAppName), "conf"))
' ~/.config/gambasbook/pathproject/pathproject.conf
  ...
End
 
Public Sub Form_Open()
  ...
  If hSettings["First/Value", 0] < 2 Then ' The 'About' window is displayed exactly 2 times
     i = hSettings["First/Value", 0]
     Inc i
     hSettings["First/Value"] = i
     hSettings.Save()
     FAbout.ShowModal()
  Endif
 
End

Some Gambas programs store scripts - for example in shell, Perl, Python or Gambas - as `hooks` that are executed by the Gambas program on certain events. In this way, the script intervenes in the configuration of the programme. These scripts or the agreed directory that is searched by your programme should then be located in the base directory Desktop.ConfigDir.In programming, according to https://de.wikipedia.org/wiki/Hook_(computer science), `hook` refers to an interface with which programme source code of other languages can be integrated into a programme in order to extend it, to change their flow or to intercept certain events.

6.1.2.2 Base Directory 2 - Desktop.DataDir

Static Property Read DataDir As String

Returns the base directory where user-specific data files are to be (permanently) stored.

6.1.2.2.1 Example 1

In this base directory, among other things, the projects from the Gambas software farm are stored, which have been selected and installed in the start window of the IDE under 'Software farm …' in the dialogue. Example: /home/hans/.local/share/gambas3/src/ajmsoftware/gbAutoMount or Desktop.DataDir &/ “gambas3/src/ajmsoftware/gbAutoMount”.

The `ajmsoftware` stands for the developer name (vendor) and `gbAutoMount` for the project name.

6.1.2.2.2 Example 2

Scripts (shell scripts and scripts in other languages such as Gambas or Python or Perl or PHP) that you have copied into the project directory or newly created there can be executed in the IDE without any problems if the script file has the necessary permissions, which are set for the case of a new script file with `rw-rw-r–'. Therefore, you must change these rights so that at least the owner has the right to execute the script file.

Case 1 - Script Test in the Gambas IDE

While the statement

txaResult.Insert(File.Load(sScriptPath))

with the path sScriptPath = “…/scripts/test_script.sh” displays the contents of the script file in the project directory in the TextArea txaResult, the following statement generates an error:

CHMOD sScriptPath To "..x......"

The reason is that the CHMOD instruction - just like the SHELL instruction - requires an absolute path! Therefore, the following two instructions work without problems:

CHMOD SetFullPath(sScriptPath) To "..x......"
SHELL SetFullPath(sScriptPath) To sStore

This is the source code for the function SetFullPath(sPath As String):

Public Function SetFullPath(sPath As String) As String
 
  Dim sFullPath As String
 
  If Left(sPath, 1) = "~" Then
     sFullPath = User.Home & Mid(sPath, 1 + 1)
  Else If Exist(sPath) And Left(sPath, 1) <> "/" Then
     sFullPath = Application.Path &/ sPath
  Else
     sFullPath = sPath
  Endif
 
  Return sFullPath
 
End

Case 2 - Script test in the project directory.

You have to take a completely different approach if you create an executable file *.gambas, open it in the project directory and start the programme there.

hans@mint-183 ~/Schreibtisch/RunScriptCHMOD $ gbr3 ./runscript.gambas

The reason is that files in a Gambas archive can only be read - execution fails! The following approach has proven successful for this case:

  1. First, the required directories are created if they do not already exist.
  2. Then the script file is copied to a suitable base directory at runtime.
  3. Then the required permissions of the copy of the script file are set.
  4. Then the shell script is executed.
  5. Finally, the script can be deleted.

Source code:

Public Sub btnRunScript_Click()
 
  Dim sStore As String
 
  sRelativeScriptPath = ".../scripts/test_script.sh"
  sAbsoluteScriptPath = Desktop.DataDir &/ File.BaseName(sRelativeScriptPath) & ".sh"
 
  Copy sRelativeScriptPath To sAbsoluteScriptPath
' Chmod sAbsoluteScriptPath To "r-xr-xr-x" ' All rights are explicitly reset
  Chmod sAbsoluteScriptPath To "..x......"
' Only the "Execute" right is set for the owner - all others are retained!
 
  txaResult.Clear()
  Shell sAbsoluteScriptPath To sStore
  If sStore Then
     txaResult.Text = sStore
     txaResult.Pos = 0
  Else
     Message.Error(Error.Text & "!")
  Endif
 
  If Exist(sAbsoluteScriptPath) Then Kill sAbsoluteScriptPath
 
End

Or you can decide to copy the script file into a temporary file and choose /tmp as the base directory. Since the script is only needed temporarily, the above source text changes:

Public Sub btnRunScript_Click()
 
  Dim sStore As String
 
  sRelativeScriptPath = "scripts/test_script.sh"
  sTempScriptPath = Temp(File.BaseName(sRelativeScriptPath)) & ".sh"
' Absolute Path: /tmp/gambas.1000/4979/test_script.tmp.sh
  If Not Exist(sTempScriptPath) Then Copy sRelativeScriptPath To sTempScriptPath
' Chmod sTempScriptPath To "r-xr-xr-x"  ' All rights are explicitly reset
  Chmod sTempScriptPath To "..x......"
' Only the "Execute" right is set for the owner - all others are retained
 
  txaResult.Clear()
  Shell sTempScriptPath To sStore
  If sStore Then
     txaResult.Text = sStore
     txaResult.Pos = 0
  Else
     Message.Error(Error.Text & "!")
  Endif
End

Good to know: The file with the path sTempScriptPath is automatically deleted when the Gambas programme is terminated.

Example 3

If you take a look at the source code (app/src/gambas3/.src/Project/Farm/CSoftware.class) regarding the software to maintain the database of installed software from the software farm:

Public Sub GetInstalledDir() As String
  Return Desktop.DataDir &/ "gambas3/src" &/ LCase(Vendor) &/ Name
End

you will see that Desktop.DataDir is selected as the installation directory. The name of the developer can be specified via the 'Vendor' entry in the project properties.

6.1.2.3 Base directory 3 - Desktop.CacheDir

Static Property Read CacheDir As String

Returns the base directory where user-specific, non-essential files should be stored. It is defined by the environment variable $XDG_CACHE_HOME. If $XDG_CACHE_HOME is not set or is empty, the default ~/.cache is used.

6.1.2.4 Base Directory 4 - Desktop.RuntimeDir

Static Property Read RuntimeDir As String

Returns the (base) directory /run/user/User-ID such as /run/user/1000 where user-specific, runtime-only files and other file objects such as local Unix sockets or named pipes are to be (temporarily) stored. The directory must belong to the user. He must be the only one who has read and write access to it. His Unix access mode must be 0700. The directory is defined by the environment variable $XDG_RUNTIME_DIR:

hans@mint-183 ~ $ echo $XDG_RUNTIME_DIR
/run/user/1000

The /run directory a virtual, temporary file system. It exists in the main memory and is automatically emptied when the computer is restarted.

Example

Public Sub _new()
 ...
  sGlobalRuntimeDir = Desktop.RuntimeDir &/ sVendor &/ Lower(sAppName)
' /run/user/1000/gambasbook/pathproject
  If Not Exist(sGlobalRuntimeDir) Then Shell.MkDir(sGlobalRuntimeDir)
  ...
  sGlobalScriptsDir = sGlobalRuntimeDir &/ GetDirPath(sLocalScriptsDir)
' /run/user/1000/gambasbook/pathproject/scripts
  If Not Exist(sGlobalScriptsDir) Then
     Shell.MkDir(sGlobalScriptsDir)
  Endif
  For Each sFile In Dir(sLocalScriptsDir, "*.{sh,sql,pl,py,gbs}")
    If Not Exist(sGlobalScriptsDir &/ sFile) Then
       Copy sLocalScriptsDir &/ sFile To sGlobalScriptsDir &/ sFile
       Chmod sGlobalScriptsDir &/ sFile To "..x......"
    Endif
  Next
  ...
End

First, all scripts with the appropriate filter for the extension are temporarily stored in the base directory sGlobalScriptsDir: /run/user/user_id/gambasbook/pathproject/scripts).For each copied script file, the right to execute (user) is set.

This is how the script dump.sh is called in an EXEC instruction:

Private Sub GetDBDumpExec()
 
  Dim aExecCommand As String[]
 
' The file extension .sql is automatically supplemented with the Dump command!
  aExecCommand = [sTempScriptPath, sGlobalDBHostDir &/ sDBName, sGlobalDBHostDir &/ "dump." & sDBTableName]
  Exec aExecCommand Wait
End

In the directory ~/.local/share/gambasbook/pathproject/data/databases the file contacts.sql is saved.

Using base directories for permanent storage of selected files may require three different base directories to be used for a project. This certainly promotes the idea of always using the base paths for certain files in the same way.

In my opinion, however, there is nothing to be said against permanently storing all relevant files for a project in a base directory such as Desktop.DataDir with a trailing NameSpace/ProjectName.

6.1.2.5 Application.Name, Application.Dir and Application.Path

Using the Application.Name, Application.Path and Application.Dir properties of the Application (gb) class holds some surprises. If you want to use these properties in your projects, then you should read the following sections carefully. The considerations presented also apply to the project type 'Library' and 'Component'.

6.1.2.5.1 Application.Name

The documentation says: 'Return the application name, as defined in the IDE project properties dialog.' This text is inaccurate and should be changed to:

'Returns the name of the application to run.'

If the application is executed in the IDE, it is the project name - as defined in the 'New Project' dialog.The project name is also the name of the automatically created project directory.If the application is executed outside the IDE directly or with `gbr3 path2project/archive_name.gambas`, it is the name of the executable file archive_name.gambas.If the application is executed outside the IDE with `gbx3 path2project_directory`, it is the name of the project directory.'

The following 4 cases demonstrate the use of the Application.Name property in a project.

Case 1: Running the application in the IDE - project name 'GetAppName'.

B1
Figure 6.1.2.5.1: Start in the IDE

Case 2: Execution in the project directory GetAppName.

$ gbx3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppName

B2
Figure 6.1.2.5.2: Start in the project directory

Case 3: Execution in the project directory GetAppName.

The name of the executable file has been changed from the (default) name GetAppName.gambas to get.app.name.gambas

$ gbr3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppName/get.app.name.gambas

B3
Figure 6.1.2.5.3: Start in the project directory

Case 4 - Running a copy of the project directory.

The original project directory ../GetAppName was copied to ../GetAppNameCopy and the programme was started there.

hans@mint-183 ~ $ gbx3 ~/GB3BUCH/6K_Stream/6.1_Pfade/BuchProgramm/GetAppNameCopy

B4
Figure 6.1.2.5.4: Start in a copy of the project directory

Conclusion: you should refrain from renaming a project directory or the existing Gambas archive *.gambas - without necessity - if you want to safely use the Application.Name property as an implementation detail in your project.

6.1.2.5.2 Application.Dir

For the Application.Dir property, the documentation states:

'Returns the application directory. It is the current working directory defined at application startup.' 'Returns the programme directory. It is the current working directory defined at application startup'.

Here is a suggestion for an extended definition:

A) Returns the application directory as default working directory if in Gambas execution mode.
B) Returns the user home directory as default working directory if in development mode (inside the IDE).

The Application.Dir property returns the CWD (current working directory) - as it is set at the time the programme is started.

The Gambas process inherits its CWD from the IDE. If you start the IDE from your “Programs” menu, the CWD is the home directory.In all other cases, it is the directory from which you started the program. Do this experiment: Open a terminal. Type 'cd /tmp'. Start the Gambas IDE with 'gambas3'. Now you are in the IDE. In a project, 'Print Application.Dir' returns /tmp!

Gambas has no concept of relative file system paths. Any relative path you pass to, for example, OPEN, File.Load(…) or similar is interpreted as relative to the files in the project directory. To get into the computer's file system, you must use absolute paths. In this case, the use of the Application.Dir property can become useful.

Example:

Assume that you have created a program myprogram.gambas that needs to be passed a file 'myfile' for processing with a command line argument. For example, in order for the File.Load(absolutepath2myfile) or Picture.Load(absolutepath2myfile) methods to load the file, the file path must be absolute, which is user-unfriendly. As a user, instead of

$ gbr3 ./myprogram.gambas absolutepath2myfile
$ gbr3 ./myprogram.gambas myfile

instead of <code_b_14>, as you are used to from programmes in other programming languages with relative paths. You can use Application.Dir for exactly this case:

Source code excerpt for the ShowImageD project.

' Gambas class file
 
Public Sub Form_Open()
 
  Dim sImagePath As String
' Assumption: The image path is relative to the CWD - as in all other languages.
' The image is located in the project directory.
 
  sImagePath = Application.Args[1]
  If sImagePath Not Begins "/" Then sImagePath = Application.Dir &/ sImagePath
 
  piboxImage.Picture = Picture.Load(sImagePath)
 
End

Program start in two variants:

hans@mint-183 ~/Schreibtisch/ShowImageD $ gbr3 ./ShowImageD.gambas hgb.png
hans@mint-183 ~/Schreibtisch/ShowImageD $ gbx3 /home/hans/Schreibtisch/ShowImageD -- hgb.png

B
Figure 6.1.2.5.5: Start with the image hgb.png

Conclusion: You can also use the Application.Env[“PWD”] property for Application.Dir. It uses the appropriate environment variable to display the CWD if it is set correctly. Taking up this idea, using the $PWD environment variable directly in Bash or in another shell could be a mediating approach:

$ gbr3 ./myprogram.gambas $PWD/myfile

Source code excerpt ShowImageP

' Gambas class file
 
Public Sub Form_Open()
 
  Dim sImagePath As String
 
  sImagePath = Application.Args[1]
  piboxImage.Picture = Picture.Load(sImagePath)
 
End

Programme start:

hans@mint-183 ~/Schreibtisch/ShowImageP $ gbr3 ./ShowImageP.gambas $PWD/hgb.png
hans@mint-183 ~/Schreibtisch/ShowImageP $ gbx3 /home/hans/Schreibtisch/ShowImageP -- $PWD/hgb.png

Conclusion: the current working directory [CWD] is only interesting for command line programs and in Gambas one writes GUI programs much more often. The latter resort to file selection dialogues and these dialogues return absolute paths. The Application.Dir property is therefore used quite little.

6.1.2.5.3 Application.Path

The `Application.Path` property always returns the project directory where the source code of the project is located.

This gives rise to the following considerations:

(1) The Application.Path property is at most to be used for debugging or for phases of program development in the IDE, for example to store files created by the program in a special developer mode in the project directory.

(2) The Application.Path property should not be used as an implementation detail of a project because otherwise the program will not work if a user decides to create an executable archive file *.gambas from the project and open it. In this case all project files are stored in an archive and Application.Path makes no sense!

Example project 'Intro':

When the program is started, an image is displayed as an intro. The image hgb.png is in the project folder in the (sub-)folder 'images'. The executable archive file is named show.intro.gambas. The source code is short:

' Gambas class file
 
Public Sub Form_Open()
 
  Dim sImagePath As String
 
  FMain.Icon = Picture.Load(".../symbols/form_icon.png")
  sImagePath = Application.Path &/ "images/hgb.png"
 
  piboxImage.Picture = Picture.Load(sImagePath)
 
End

(a) Start in the IDE with F5 or via the button in the toolbar with the symbol ► → ok
(b) The program is started directly in the project directory → ok
(c) Start console: hans@mint-183 ~/Desk $ gbr3 Intro/show.intro.gambas → ok
(d) Start console: hans@mint-183 ~/desk $ gbx3 Intro → ok

Finally, copy only the executable archive file show.intro.gambas to the home directory and start it directly there:

BError
Figure 6.1.2.5.6: Start in the home directory

The error is understandable because the Application.Path property no longer points to the /home/hans/Desk/Intro directory but to /home/hans and therefore the image file cannot be loaded. What now - what to do? Here is a suggestion:

Replace the line

sImagePath = Application.Path &/ "images/hgb.png"

with

sImagePath = ".../images/hgb.png"

and the error is eliminated because the resolution of the relative path is now always correct!

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k6/k6.1/k6.1.2/start.txt · Last modified: 16.01.2022 (external edit)

Page Tools