Browse Source

init: add --tmp-location (based on patch from radeknovotny94 in https://trac.osgeo.org/grass/ticket/3537)

Creates a location in program's tmp dir which is deleted at the end.
Meant for use with --exec. Possible to use without it as well (e.g. with GUI).
CRS needs to be specified using -c.
Does not write to a rc file to user's settings at the end.
Based on grass-tmp-loc-2.diff from Radek Novotny submitted in https://trac.osgeo.org/grass/ticket/3537.


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@72790 15284696-431f-4ddb-bdfa-cd5b030d7da7
Vaclav Petras 7 years ago
parent
commit
dc18c8d177
2 changed files with 99 additions and 11 deletions
  1. 52 11
      lib/init/grass.py
  2. 47 0
      lib/init/grass7.html

+ 52 - 11
lib/init/grass.py

@@ -226,6 +226,7 @@ def debug(msg):
 
 
 
 
 def readfile(path):
 def readfile(path):
+    debug("Reading %s" % path)
     f = open(path, 'r')
     f = open(path, 'r')
     s = f.read()
     s = f.read()
     f.close()
     f.close()
@@ -233,6 +234,7 @@ def readfile(path):
 
 
 
 
 def writefile(path, s):
 def writefile(path, s):
+    debug("Writing %s" % path)
     f = open(path, 'w')
     f = open(path, 'w')
     f.write(s)
     f.write(s)
     f.close()
     f.close()
@@ -290,6 +292,7 @@ Geographic Resources Analysis Support System (GRASS GIS).
           [-e] [-f] [-text | -gtext | -gui] [--config param]
           [-e] [-f] [-text | -gtext | -gui] [--config param]
           [[[GISDBASE/]LOCATION_NAME/]MAPSET]
           [[[GISDBASE/]LOCATION_NAME/]MAPSET]
   $CMD_NAME [FLAG]... GISDBASE/LOCATION_NAME/MAPSET --exec EXECUTABLE [EPARAM]...
   $CMD_NAME [FLAG]... GISDBASE/LOCATION_NAME/MAPSET --exec EXECUTABLE [EPARAM]...
+  $CMD_NAME -c [geofile | EPSG] --tmp-location --exec EXECUTABLE [EPARAM]...
 
 
 {flags}:
 {flags}:
   -h or -help or --help or --h   {help_flag}
   -h or -help or --help or --h   {help_flag}
@@ -307,6 +310,7 @@ Geographic Resources Analysis Support System (GRASS GIS).
                                    {config_detail}
                                    {config_detail}
   --exec EXECUTABLE              {exec_}
   --exec EXECUTABLE              {exec_}
                                    {exec_detail}
                                    {exec_detail}
+  --tmp-location                 {tmp_location}
 
 
 {params}:
 {params}:
   GISDBASE                       {gisdbase}
   GISDBASE                       {gisdbase}
@@ -363,6 +367,7 @@ Geographic Resources Analysis Support System (GRASS GIS).
     executable=_("GRASS module, script or any other executable"),
     executable=_("GRASS module, script or any other executable"),
     executable_params=_("parameters of the executable"),
     executable_params=_("parameters of the executable"),
     standard_flags=_("standard flags"),
     standard_flags=_("standard flags"),
+    tmp_location=_("create temporary location (use with -c and --exec flags)"),
     )
     )
 
 
 
 
@@ -886,12 +891,16 @@ def get_mapset_invalid_reason(gisdbase, location, mapset):
                      mapset=mapset, loc=location)
                      mapset=mapset, loc=location)
 
 
 
 
-def set_mapset(gisrc, arg, geofile=None, create_new=False):
+def set_mapset(gisrc, arg=None, geofile=None, create_new=False,
+               tmp_location=False, tmpdir=None):
     """Selected Location and Mapset are checked and created if requested
     """Selected Location and Mapset are checked and created if requested
 
 
     The gisrc (GRASS environment file) is written at the end
     The gisrc (GRASS environment file) is written at the end
     (nothing is returned).
     (nothing is returned).
+
+    tmp_location requires tmpdir (which is used as gisdbase)
     """
     """
+    # TODO: arg param seems to be always mapset or dash, refactor
     l = None
     l = None
 
 
     if arg == '-':
     if arg == '-':
@@ -925,6 +934,18 @@ def set_mapset(gisrc, arg, geofile=None, create_new=False):
         l, location_name = os.path.split(l)
         l, location_name = os.path.split(l)
         gisdbase = l
         gisdbase = l
 
 
+    # all was None for tmp loc so that case goes here quickly
+    # TODO: but the above code needs review anyway
+    if tmp_location:
+        # set gisdbase to temporary directory
+        gisdbase = tmpdir
+        # we are already in a unique directory, so we can use fixed name
+        location_name = "tmploc"
+        # we need only one mapset
+        mapset = "PERMANENT"
+        debug("Using temporary location <{gdb}{sep}{lc}>".format(
+            gdb=gisdbase, lc=location_name, sep=os.path.sep))
+
     if gisdbase and location_name and mapset:
     if gisdbase and location_name and mapset:
         location = os.path.join(gisdbase, location_name, mapset)
         location = os.path.join(gisdbase, location_name, mapset)
 
 
@@ -938,11 +959,12 @@ def set_mapset(gisrc, arg, geofile=None, create_new=False):
                 # 'location' is not valid, the user wants to create
                 # 'location' is not valid, the user wants to create
                 # mapset on the fly
                 # mapset on the fly
                 if not is_location_valid(gisdbase, location_name):
                 if not is_location_valid(gisdbase, location_name):
-                    # 'location_name' is not a valid GRASS location,
-                    # create new location and 'PERMANENT' mapset
-                    gisdbase = os.path.join(gisdbase, location_name)
-                    location_name = mapset
-                    mapset = "PERMANENT"
+                    if not tmp_location:
+                        # 'location_name' is not a valid GRASS location,
+                        # create new location and 'PERMANENT' mapset
+                        gisdbase = os.path.join(gisdbase, location_name)
+                        location_name = mapset
+                        mapset = "PERMANENT"
                     if is_location_valid(gisdbase, location_name):
                     if is_location_valid(gisdbase, location_name):
                         fatal(_("Failed to create new location. "
                         fatal(_("Failed to create new location. "
                                 "The location <%s> already exists." % location_name))
                                 "The location <%s> already exists." % location_name))
@@ -1774,7 +1796,7 @@ class Parameters(object):
         self.force_gislock_removal = None
         self.force_gislock_removal = None
         self.mapset = None
         self.mapset = None
         self.geofile = None
         self.geofile = None
-
+        self.tmp_location = False
 
 
 def parse_cmdline(argv, default_gui):
 def parse_cmdline(argv, default_gui):
     """Parse the standard part of command line parameters"""
     """Parse the standard part of command line parameters"""
@@ -1812,13 +1834,18 @@ def parse_cmdline(argv, default_gui):
         elif i == "--config":
         elif i == "--config":
             print_params()
             print_params()
             sys.exit()
             sys.exit()
+        elif i == "--tmp-location":
+            params.tmp_location = True
         else:
         else:
             args.append(i)
             args.append(i)
     if len(args) > 1:
     if len(args) > 1:
         params.mapset = args[1]
         params.mapset = args[1]
         params.geofile = args[0]
         params.geofile = args[0]
     elif len(args) == 1:
     elif len(args) == 1:
-        params.mapset = args[0]
+        if params.tmp_location:
+            params.geofile = args[0]
+        else: 
+            params.mapset = args[0]
     else:
     else:
         params.mapset = None
         params.mapset = None
     return params
     return params
@@ -1882,9 +1909,17 @@ def main():
         params = parse_cmdline(sys.argv[1:], default_gui=default_gui)
         params = parse_cmdline(sys.argv[1:], default_gui=default_gui)
     if params.exit_grass and not params.create_new:
     if params.exit_grass and not params.create_new:
         fatal(_("Flag -e requires also flag -c"))
         fatal(_("Flag -e requires also flag -c"))
+    if params.tmp_location and not params.create_new:
+        fatal(_("Flag --tmp-location requires also flag -c"))
+    # Theoretically -c is not needed, CRS could be value of --tmp-location
+    # or, considering current code, CRS could be just taken from args.
+    # We allow --tmp-location without --exec (usefulness to be evaluated).
 
 
     grass_gui = params.grass_gui  # put it to variable, it is used a lot
     grass_gui = params.grass_gui  # put it to variable, it is used a lot
 
 
+    # TODO: with --tmp-location there is no point in loading settings
+    # i.e. rc file from home dir, but the code is too spread out
+    # to disable it at this point
     gisrcrc = get_gisrc_from_config_dir(grass_config_dir, batch_job)
     gisrcrc = get_gisrc_from_config_dir(grass_config_dir, batch_job)
 
 
     # Set the username
     # Set the username
@@ -1969,7 +2004,7 @@ def main():
         save_gui(gisrc, grass_gui)
         save_gui(gisrc, grass_gui)
 
 
     # Parsing argument to get LOCATION
     # Parsing argument to get LOCATION
-    if not params.mapset:
+    if not params.mapset and not params.tmp_location:
         # Try interactive startup
         # Try interactive startup
         # User selects LOCATION and MAPSET if not set
         # User selects LOCATION and MAPSET if not set
         if not set_mapset_interactive(grass_gui):
         if not set_mapset_interactive(grass_gui):
@@ -1979,7 +2014,12 @@ def main():
                     "'grass-gui').").format(grass_gui))
                     "'grass-gui').").format(grass_gui))
     else:
     else:
         # Try non-interactive start up
         # Try non-interactive start up
-        if params.create_new and params.geofile:
+        if params.tmp_location:
+            # tmp loc requires other things to be set as well
+            set_mapset(gisrc=gisrc, geofile=params.geofile, 
+                       create_new=True,
+                       tmp_location=params.tmp_location, tmpdir=tmpdir)
+        elif params.create_new and params.geofile:
             set_mapset(gisrc=gisrc, arg=params.mapset,
             set_mapset(gisrc=gisrc, arg=params.mapset,
                        geofile=params.geofile, create_new=True)
                        geofile=params.geofile, create_new=True)
         else:
         else:
@@ -2062,7 +2102,8 @@ def main():
         # save 'last used' GISRC after removing variables which shouldn't
         # save 'last used' GISRC after removing variables which shouldn't
         # be saved, e.g. d.mon related
         # be saved, e.g. d.mon related
         clean_env(gisrc)
         clean_env(gisrc)
-        writefile(gisrcrc, readfile(gisrc))
+        if not params.tmp_location:
+            writefile(gisrcrc, readfile(gisrc))
         # After this point no more grass modules may be called
         # After this point no more grass modules may be called
         done_message()
         done_message()
 
 

+ 47 - 0
lib/init/grass7.html

@@ -51,6 +51,12 @@
 
 
 <dt><b>--exec EXECUTABLE</b>
 <dt><b>--exec EXECUTABLE</b>
 <dd> Execute GRASS module or script. The provided executable will be executed in a GRASS GIS non-interactive session.
 <dd> Execute GRASS module or script. The provided executable will be executed in a GRASS GIS non-interactive session.
+
+<dt><b>--tmp-location</b>
+<dd> Run using a temporary location which is created based on the given
+coordinate reference system and deleted at the end of the execution
+(use with -c and --exec flags)
+
 </dl>
 </dl>
 
 
 <h3>Parameters:</h3>
 <h3>Parameters:</h3>
@@ -360,6 +366,47 @@ for vector in gscript.list_strings(type='vector'):
     print(vector)
     print(vector)
 </pre></div>
 </pre></div>
 
 
+<h4>Using temporary location</h4>
+
+Creating a new temporary location based on a georeferenced file's
+projection coordinate reference system (CRS) and simultaneously starting
+computation in a shell script:
+
+<div class="code"><pre>
+grass75 -c elevation.tiff --tmp-location --exec test.sh
+</pre></div>
+
+The same, but using an EPSG code and a Python script:
+
+<div class="code"><pre>
+grass75 -c EPSG:3358 --tmp-location --exec test.py
+</pre></div>
+
+Finally, for special cases, we can create an XY location without any CRS:
+
+<div class="code"><pre>
+grass75 -c --tmp-location --exec test.py
+</pre></div>
+
+Temporary location is automatically deleted after computation,
+so the script is expected to export, link or otherwise preserve the
+output data before ending.
+
+<p>
+A single command can be also executed, e.g. to examine properties of the
+temporary location:
+
+<div class="code"><pre>
+grass75 -c EPSG:3358 --tmp-location --exec g.proj -p
+</pre></div>
+
+A temporary XY location with single command is useful, e.g. to show
+help text of a module:
+
+<div class="code"><pre>
+grass75 -c --tmp-location --exec r.neighbors --help
+</pre></div>
+
 <h4>Troubleshooting</h4>
 <h4>Troubleshooting</h4>
 Importantly, to avoid an <tt>"[Errno 8] Exec format error"</tt> there must be a 
 Importantly, to avoid an <tt>"[Errno 8] Exec format error"</tt> there must be a 
 <a href="https://en.wikipedia.org/wiki/Shebang_%28Unix%29">shebang</a> line at the top of
 <a href="https://en.wikipedia.org/wiki/Shebang_%28Unix%29">shebang</a> line at the top of