فهرست منبع

init: Start shell only with TTY (#768)

Start the (sub-)shell only when running in an interactive terminal (TTY).
Without checking this, the start fails in contexts when terminal is not available,
for example, running command from Alt+F2 dialog on many Linux distributions.
The same situation can be created using the nohup command.

A failure to retrieve shell PID from gisenv is no longer considered an error
for cases when shell was not started.

The interactive shell can be forced regadless of the TTY by using --text in the command line.

This solves Trac ticket 3295 (GRASS GIS fails to start without terminal).
https://trac.osgeo.org/grass/ticket/3295
Vaclav Petras 4 سال پیش
والد
کامیت
171db2e53f
2فایلهای تغییر یافته به همراه66 افزوده شده و 38 حذف شده
  1. 5 2
      gui/wxpython/lmgr/frame.py
  2. 61 36
      lib/init/grass.py

+ 5 - 2
gui/wxpython/lmgr/frame.py

@@ -2620,8 +2620,11 @@ class GMFrame(wx.Frame):
         """Quit GRASS terminal"""
         """Quit GRASS terminal"""
         try:
         try:
             shellPid = int(grass.gisenv()['PID'])
             shellPid = int(grass.gisenv()['PID'])
-        except:
-            grass.warning(_("Unable to exit GRASS shell: unknown PID"))
+        except (KeyError, ValueError) as error:
+            Debug.msg(
+                1,
+                "No PID for GRASS shell (assuming no shell running): {}".format(error)
+            )
             return
             return
 
 
         Debug.msg(1, "Exiting shell with pid={0}".format(shellPid))
         Debug.msg(1, "Exiting shell with pid={0}".format(shellPid))

+ 61 - 36
lib/init/grass.py

@@ -1771,13 +1771,16 @@ def run_batch_job(batch_job):
 def start_gui(grass_gui):
 def start_gui(grass_gui):
     """Start specified GUI
     """Start specified GUI
 
 
-    :param grass_gui: GUI name (allowed values: 'wxpython')
+    :param grass_gui: GUI name (supported values: 'wxpython')
+
+    Returns the process for a supported GUI, None otherwise.
     """
     """
     # Start the chosen GUI but ignore text
     # Start the chosen GUI but ignore text
     debug("GRASS GUI should be <%s>" % grass_gui)
     debug("GRASS GUI should be <%s>" % grass_gui)
     # Check for gui interface
     # Check for gui interface
     if grass_gui == "wxpython":
     if grass_gui == "wxpython":
-        Popen([os.getenv('GRASS_PYTHON'), wxpath("wxgui.py")])
+        return Popen([os.getenv('GRASS_PYTHON'), wxpath("wxgui.py")])
+    return None
 
 
 
 
 def close_gui():
 def close_gui():
@@ -2066,6 +2069,11 @@ def grep(pattern, lines):
     return [elem for elem in lines if expr.match(elem)]
     return [elem for elem in lines if expr.match(elem)]
 
 
 
 
+def io_is_interactive():
+    """Return True if running in an interactive terminal (TTY), False otherwise"""
+    return sys.stdin.isatty() and sys.stdout.isatty()
+
+
 def print_params():
 def print_params():
     """Write compile flags and other configuration to stderr"""
     """Write compile flags and other configuration to stderr"""
     params = sys.argv[2:]
     params = sys.argv[2:]
@@ -2292,6 +2300,17 @@ def main():
 
 
     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
 
 
+    # A shell is activated when using TTY.
+    # Explicit --[g]text in command line, forces a shell to be activated.
+    force_shell = grass_gui in ["text", "gtext"]
+    use_shell = io_is_interactive() or force_shell
+    if not use_shell:
+        # If no shell is used, always use actual GUI as GUI, even when "text" is set as
+        # a GUI in the gisrcrc becasue otherwise there would be nothing for the user
+        # unless running in the batch mode. (The gisrcrc file is loaded later on in case
+        # nothing was provided in the command line).
+        grass_gui = default_gui
+
     # TODO: with --tmp-location there is no point in loading settings
     # 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
     # i.e. rc file from home dir, but the code is too spread out
     # to disable it at this point
     # to disable it at this point
@@ -2432,43 +2451,48 @@ def main():
         clean_all()
         clean_all()
         sys.exit(0)
         sys.exit(0)
     else:
     else:
-        show_banner()
-        say_hello()
-        show_info(shellname=shellname,
-                  grass_gui=grass_gui, default_gui=default_gui)
-        if grass_gui == "wxpython":
-            message(_("Launching <%s> GUI in the background, please wait...")
-                    % grass_gui)
-        if sh in ['csh', 'tcsh']:
-            shell_process = csh_startup(mapset_settings.full_mapset,
-                                        grass_env_file)
-        elif sh in ['zsh']:
-            shell_process = sh_like_startup(mapset_settings.full_mapset,
-                                            mapset_settings.location,
-                                            grass_env_file,
-                                            "zsh")
-        elif sh in ['bash', 'msh', 'cygwin']:
-            shell_process = sh_like_startup(mapset_settings.full_mapset,
-                                            mapset_settings.location,
-                                            grass_env_file,
-                                            "bash")
+        if use_shell:
+            show_banner()
+            say_hello()
+            show_info(shellname=shellname,
+                      grass_gui=grass_gui, default_gui=default_gui)
+            if grass_gui == "wxpython":
+                message(_("Launching <%s> GUI in the background, please wait...")
+                        % grass_gui)
+            if sh in ['csh', 'tcsh']:
+                shell_process = csh_startup(mapset_settings.full_mapset,
+                                            grass_env_file)
+            elif sh in ['zsh']:
+                shell_process = sh_like_startup(mapset_settings.full_mapset,
+                                                mapset_settings.location,
+                                                grass_env_file,
+                                                "zsh")
+            elif sh in ['bash', 'msh', 'cygwin']:
+                shell_process = sh_like_startup(mapset_settings.full_mapset,
+                                                mapset_settings.location,
+                                                grass_env_file,
+                                                "bash")
+            else:
+                shell_process = default_startup(mapset_settings.full_mapset,
+                                                mapset_settings.location)
         else:
         else:
-            shell_process = default_startup(mapset_settings.full_mapset,
-                                            mapset_settings.location)
+            shell_process = None
 
 
         # start GUI and register shell PID in rc file
         # start GUI and register shell PID in rc file
-        start_gui(grass_gui)
-        kv = {}
-        kv['PID'] = str(shell_process.pid)
-
-        # grass_prompt() tries to read gisrc while write_gisrc() is adding PID
-        # to this file, so don't rewrite it; just append PID to make it
-        # available to grass_prompt() at all times (PR #548)
-        write_gisrc(kv, gisrc, append=True)
+        gui_process = start_gui(grass_gui)
 
 
-        exit_val = shell_process.wait()
-        if exit_val != 0:
-            warning(_("Failed to start shell '%s'") % os.getenv('SHELL'))
+        if shell_process:
+            kv = {}
+            kv['PID'] = str(shell_process.pid)
+            # grass_prompt() tries to read gisrc while write_gisrc() is adding PID
+            # to this file, so don't rewrite it; just append PID to make it
+            # available to grass_prompt() at all times (PR #548)
+            write_gisrc(kv, gisrc, append=True)
+            exit_val = shell_process.wait()
+            if exit_val != 0:
+                warning(_("Failed to start shell '%s'") % os.getenv('SHELL'))
+        else:
+            gui_process.wait()
 
 
         # close GUI if running
         # close GUI if running
         close_gui()
         close_gui()
@@ -2480,7 +2504,8 @@ def main():
         # After this point no more grass modules may be called
         # After this point no more grass modules may be called
         # done message at last: no atexit.register()
         # done message at last: no atexit.register()
         # or register done_message()
         # or register done_message()
-        done_message()
+        if use_shell:
+            done_message()
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
     main()
     main()