Skip to content

Refactor and simplify the startup procedure used by initGRASS - #109

Open
stevenpawley wants to merge 24 commits into
OSGeo:mainfrom
stevenpawley:main
Open

Refactor and simplify the startup procedure used by initGRASS#109
stevenpawley wants to merge 24 commits into
OSGeo:mainfrom
stevenpawley:main

Conversation

@stevenpawley

Copy link
Copy Markdown
Member

Summary

This PR refactors and simplifies the startup procedure used by initGRASS() to broadly match the process used within grass.script.setup.init().

The original procedure performed all operations inline, within a single function. In this PR, the platform-specific setup and session initialization code has been extracted into separate internal helper functions. This should make initGRASS() easier to follow, test, and maintain, without any other user-facing changes.

Overview of GRASS startup procedure

Original startup procedure using in rgrass

  1. Configures temporary-file handling via RGRASS_TEMPDIR

  2. Checks for existing GRASS state:

    • checks whether the GISRC environment variable identifies an existing active session;
    • checks whether the GIS_LOCK environment variable is set;
    • asks whether these should be overridden when necessary.
  3. Creates the pid and validates the initGRASS main arguments

  4. Determines the GRASS installation directory:

    • uses the gisBase argument when supplied;
    • otherwise tries the GRASS_INSTALLATION environment variable;
    • otherwise runs grass --config path.
  5. Checks that gisBase exists and contains bin and scripts folders

  6. Reads the GRASS major version

  7. Enters a large inline, platform-specific branch:

    On Windows:

    • sets GISBASE and HOME environment variables
    • defines the add-on directory using the addon_base argument or %APPDATA%\GRASS8\addons
    • inspects OSGEO4W_ROOT and uses it to define PROJ coordinate-transformation library location:
      • sets GRASS_PROJSHARE to <OSGEO4W_ROOT>/share/proj for OSGEO4W
      • sets GRASS_PROJSHARE to /share/proj for standalone GRASS
    • modifies PATH, PYTHONPATH, and, where applicable, PYTHONHOME;
    • chooses the initial GISRC path (decides where to create the temporary session configuration file)
      • on Windows, grass normally places it in the selected home directory;
      • if that location is not writable, it falls back to a file in R’s temporary directory;
      • sets GISRC=C:/path/to/the/session-file
    • checks whether the GISRC already existed at that location and decides what to do
      based on the override argument
    • if the current working directory is not writable, replaces the GISRC path
      with a file in RGRASS_TEMPDIR.
    • writes a preliminary GISRC containing:
      • GISDBASE: the current working directory returned by getwd()
      • LOCATION_NAME:
      • MAPSET:
    • optionally calls g.dirseps.exe to convert the GISRC path windows/unix style
      and replaces the GISRC environment variable with that converted path
    • sets the Windows executable suffix used by rgrass (addEXE);
    • selects or creates gisDbase; optionally calls g.dirseps.exe to convert
      its path.

    On Unix:

    • sets GISBASE and resolves the home value;
    • defines and configures the add-on directory;
    • modifies PATH, LD_LIBRARY_PATH, and PYTHONPATH;
    • chooses the GISRC path;
    • checks whether the GISRC already exists;
    • selects or creates gisDbase;
    • writes a preliminary GISRC missing the location and mapset values:
      • GISDBASE: the selected or temporary database path;
      • LOCATION_NAME:;
      • MAPSET:.
  8. Sets GIS_LOCK and records the session and cleanup state in .GRASS_CACHE.

  9. Calls g.gisenv initially to set GISDBASE.

  10. Determines and creates the final session directory structure:

    • Generate location if omitted.
    • Create the location.
    • Create PERMANENT.
    • Generate mapset if omitted.
    • Create the mapset.
  11. Calls g.gisenv repeatedly to set the final:

    • GISDBASE;
    • LOCATION_NAME;
    • MAPSET;
    • GRASS_GUI=text.
  12. Sets GISBASE, GISDBASE, LOCATION_NAME, and MAPSET.

  13. Checks GRASS compatibility (g.version, check compatibility)

  14. Selects the Python executable (OSGeo4W python3.exe or python.exe; or python3/python based on the GRASS version)

  15. Creates DEFAULT_WIND and the mapset WIND files, then configures the
    region and optional projection supplied through SG.

  16. Return session metadata (returns output from gmeta())

New startup procedure

  1. Configure temporary-file handling (sets RGRASS_TEMPDIR)
  2. Check existing GISRC and GIS lock state
  3. Resolve and validate the lock identifier and arguments
  4. Discover GRASS (gisBase <- search_grass())
  5. Validate GRASS (validate_gisbase(gisBase))
  6. Read structured version information (gv <- grass_version(gisBase))
  7. Resolve the home directory once (home <- set_home_path(home))
  8. Resolve and create the complete session layout:
    • session <- create_session_directories(...)
    • This determines and creates (gisDbase, location, PERMANENT, mapset, loc_path).
    • The session therefore has final names and directories before GISRC creation.
  9. Configure the platform runtime:
    • setup_runtime_env_windows(...)
    • setup_runtime_env_unix(...)
    • These helpers configure: GISBASE, add-on paths, executable paths, library paths, Python paths, Windows OSGeo4W checks and PROJ configuration
  10. Normalize Windows paths using R. No GRASS executable is called at this stage.
  11. Write the complete GISRC once (write_gisrc(...))
  12. Set lock and cleanup state
  13. Set process environment variables (GISBASE, GISDBASE, LOCATION_NAME, and MAPSET)
  14. Check GRASS compatibility
  15. Configure Python (set_grass_python(...))
  16. Initialize region and projection files (write_wind(...))
  17. Return session metadata (returns output from gmeta())

Key differences

The old process was incremental. It first wrote a partial GISRC containing GISDBASE and blank LOCATION_NAME and MAPSET values. This gave g.gisenv enough configuration to run. It then used GRASS itself to set GISDBASE, LOCATION_NAME, MAPSET, and GRASS_GUI=text in the GISRC, after creating the location and mapset directories. On Windows, it also used g.dirseps.exe to normalize paths.

The new process prepares the complete session details in R first, then writes one final GISRC with the actual database, location, and mapset values.

The GISRC file is now written with the final session values directly:

  • GISDBASE
  • LOCATION_NAME
  • MAPSET
  • GRASS_GUI

This removes the need to initialize the file with placeholder values and subsequently update it through multiple g.gisenv calls.

Windows startup paths are now normalized using R instead of invoking g.dirseps.exe. This simplifies startup because the old executable-based conversion required a preliminary GISRC file. The existing use_g.dirseps.exe argument is retained for compatibility, although normalization is now performed by R rather than by the executable. I'd like to deprecate this argument in later versions.

Specific changes

  • Extracted GRASS installation discovery and validation.
  • Extracted GRASS version detection.
  • Extracted home-directory configuration.
  • Extracted environment path handling.
  • Extracted GRASS add-on path configuration.
  • Separated Unix and Windows runtime environment setup.
  • Extracted session database, location, and mapset creation.
  • Extracted GISRC creation and configuration.
  • Extracted GRASS Python executable selection.
  • Extracted region-file initialization.
  • Added unit tests for the new helpers.

Testing

The following initGRASS scenarios were tested successfully:

  • Linux system installation of GRASS.
  • Linux conda-forge installation of GRASS 8.5.
  • Windows OSGeo4W installation (starting rgrass from an active GRASS session).
  • Starting R from the OSGeo4W shell (without an existing GRASS session).

Review considerations

Review would be helpful for:

  • General reliability and similar user-facing behavior when using initGRASS
  • Windows path normalization
  • GRASS Python selection
  • Whether use_g.dirseps.exe should remain as a compatibility argument or be deprecated in a future release.

…S(). When R starts inside an existing GRASS location, initGRASS() isn’t called, so temporary output paths became /file….
…tu is missing proper SSL/TLS certificates needed to verify GitHub's server certificate when cloning the repository over HTTPS.
…no longer available in the Ubuntu package repositories. The current version of Pandoc in the Ubuntu repositories already handles citations natively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant