Browse Source

libgis: Add function to read or read again GISRC var (#2244)

The session file (GISRC file) can be read again (force read) with a double underscore function, but when GISRC environment variable changes, the old file is read because cashed value of GISRC is read. This adds a new function which forces the the update (reading) of the variable regardless of its current value similarly to the file content reading.

This also moves the 'no GISRC' error message to the dedicated reading function (from a function of opening environment/variable/session file).

Runs the C test isolated using a process with multiprocessing otherwise other tests fail.

Also syncs LD_LIBRARY_PATH handling in Pylint workflow to pytest workflow.
Vaclav Petras 3 năm trước cách đây
mục cha
commit
941b533cad
4 tập tin đã thay đổi với 72 bổ sung7 xóa
  1. 3 4
      .github/workflows/pylint.yml
  2. 1 0
      include/grass/defs/gis.h
  3. 17 3
      lib/gis/env.c
  4. 51 0
      lib/gis/tests/lib_gis_env_test.py

+ 3 - 4
.github/workflows/pylint.yml

@@ -55,10 +55,6 @@ jobs:
         run: |
           echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV
 
-      - name: Set LD_LIBRARY_PATH for compilation
-        run: |
-          echo "LD_LIBRARY_PATH=$HOME/install/lib" >> $GITHUB_ENV
-
       - name: Build
         run: .github/workflows/build_${{ matrix.os }}.sh $HOME/install
 
@@ -72,12 +68,14 @@ jobs:
       - name: Run Pylint on grass package
         run: |
           export PYTHONPATH=`grass --config python_path`:$PYTHONPATH
+          export LD_LIBRARY_PATH=$HOME/install/grass81/lib:$LD_LIBRARY_PATH
           cd python
           pylint --persistent=no --py-version=${{ matrix.min-python-version }} --jobs=$(nproc) grass
 
       - name: Run Pylint on wxGUI
         run: |
           export PYTHONPATH=`grass --config python_path`:$PYTHONPATH
+          export LD_LIBRARY_PATH=$HOME/install/grass81/lib:$LD_LIBRARY_PATH
           cd gui/wxpython
           pylint --persistent=no --py-version=${{ matrix.min-python-version }} --jobs=$(nproc) *
 
@@ -85,4 +83,5 @@ jobs:
         run: |
           pip install pytest pytest-pylint
           export PYTHONPATH=`grass --config python_path`:$PYTHONPATH
+          export LD_LIBRARY_PATH=$HOME/install/grass81/lib:$LD_LIBRARY_PATH
           pytest --pylint -m pylint --pylint-rcfile=.pylintrc --pylint-jobs=$(nproc) --pylint-ignore-patterns="python/.*,gui/wxpython/.*,doc/.*,man/.*,utils/.*,locale/.*,raster/.*,imagery/.*,scripts/r.in.wms/wms_drv.py,scripts/g.extension/g.extension.py,temporal/t.rast.accdetect/t.rast.accdetect.py,temporal/t.rast.accumulate/t.rast.accumulate.py,scripts/d.rast.edit/d.rast.edit.py"

+ 1 - 0
include/grass/defs/gis.h

@@ -323,6 +323,7 @@ void G_create_alt_env(void);
 void G_switch_env(void);
 void G__read_mapset_env(void);
 void G__read_gisrc_env(void);
+void G__read_gisrc_path(void);
 
 /* error.c */
 #ifndef CTYPESGEN

+ 17 - 3
lib/gis/env.c

@@ -114,6 +114,22 @@ void G__read_gisrc_env(void)
     force_read_env(G_VAR_GISRC);
 }
 
+/*!
+ * \brief Read or read again the GISRC (session) environment variable
+ *
+ * The GISRC environment variable will be read and its value
+ * stored, ignoring if it was read before.
+ *
+ * Calls G_fatal_error when the GISRC variable is not set.
+ */
+void G__read_gisrc_path(){
+    st->gisrc = getenv("GISRC");
+    if (!st->gisrc) {
+        G_fatal_error(_("No active GRASS session: "
+                        "GISRC environment variable not set"));
+    }
+}
+
 static void parse_env(FILE *fd, int loc)
 {
     /* Account for long lines up to GPATH_MAX. 
@@ -307,11 +323,9 @@ static FILE *open_env(const char *mode, int loc)
 
     if (loc == G_VAR_GISRC) {
 	if (!st->gisrc)
-	    st->gisrc = getenv("GISRC");
+	    G__read_gisrc_path();
 
 	if (!st->gisrc) {
-            G_fatal_error(_("No active GRASS session: "
-                            "GISRC environment variable not set"));
 	    return NULL;
 	}
 	strcpy(buf, st->gisrc);

+ 51 - 0
lib/gis/tests/lib_gis_env_test.py

@@ -0,0 +1,51 @@
+"""Test environment and GIS environment functions"""
+
+import multiprocessing
+
+import grass.script as gs
+import grass.script.setup as grass_setup
+
+
+def run_in_subprocess(function):
+    """Run function in a separate process
+
+    The function must take a Queue and put its result there.
+    The result is then returned from this function.
+    """
+    queue = multiprocessing.Queue()
+    process = multiprocessing.Process(target=function, args=(queue,))
+    process.start()
+    result = queue.get()
+    process.join()
+    return result
+
+
+def test_reading_respects_change_of_session(tmp_path):
+    """Check new session file path is retrieved and the file is read"""
+
+    # The switching must happen in one process to test that the reading functions
+    # are not using the cached values. However, the test itself needs to be
+    # process-separated otherwise other tests will be influenced by the loaded
+    # libraries and initialized data structures.
+
+    def switch_through_locations(queue):
+        """Switches through a list of locations"""
+        # Just to be sure we don't influence other tests.
+        # pylint: disable=import-outside-toplevel
+        import grass.pygrass.utils as pygrass_utils
+        import grass.lib.gis as libgis
+
+        names = []
+        for location_name in ["test1", "test2", "abc"]:
+            # pylint: disable=protected-access
+            gs.core._create_location_xy(tmp_path, location_name)
+            with grass_setup.init(tmp_path / location_name):
+                libgis.G__read_gisrc_path()
+                libgis.G__read_gisrc_env()
+                names.append((pygrass_utils.getenv("LOCATION_NAME"), location_name))
+        queue.put(names)
+
+    names = run_in_subprocess(switch_through_locations)
+
+    for getenv_name, expected_name in names:
+        assert getenv_name == expected_name, f"All recorded names: {names}"