From 3919e22a79b4ac76a69aa7a39b34bf7084b574ed Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 23 Feb 2021 11:05:08 -0600 Subject: [PATCH 01/45] wxGUI: startup screen code removed, instead the idea of demolocation is implemented. --- gui/wxpython/Makefile | 2 +- gui/wxpython/datacatalog/catalog.py | 35 +- gui/wxpython/datacatalog/infomanager.py | 32 +- gui/wxpython/gis_set.py | 955 ------------------------ gui/wxpython/gis_set_error.py | 41 - lib/init/grass.py | 201 ++--- python/grass/app/data.py | 32 +- python/grass/grassdb/checks.py | 23 + 8 files changed, 198 insertions(+), 1123 deletions(-) delete mode 100644 gui/wxpython/gis_set.py delete mode 100644 gui/wxpython/gis_set_error.py diff --git a/gui/wxpython/Makefile b/gui/wxpython/Makefile index 97d7d45d2c6..251c3a70159 100644 --- a/gui/wxpython/Makefile +++ b/gui/wxpython/Makefile @@ -14,7 +14,7 @@ SRCFILES := $(wildcard icons/*.py scripts/*.py xml/*) \ mapswipe/*.py modules/*.py nviz/*.py psmap/*.py rdigit/*.py \ rlisetup/*.py startup/*.py timeline/*.py vdigit/*.py \ vnet/*.py web_services/*.py wxplot/*.py iscatt/*.py tplot/*.py photo2image/*.py image2target/*.py) \ - gis_set.py gis_set_error.py wxgui.py README + wxgui.py README DSTFILES := $(patsubst %,$(DSTDIR)/%,$(SRCFILES)) \ $(patsubst %.py,$(DSTDIR)/%.pyc,$(filter %.py,$(SRCFILES))) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 1248ace86f0..b1a013115f4 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -26,10 +26,12 @@ from datacatalog.infomanager import DataCatalogInfoManager from gui_core.wrap import Menu from gui_core.forms import GUI +from grass.script import gisenv from grass.pydispatch.signal import Signal from grass.grassdb.checks import is_current_mapset_in_demolocation +from startup.guiutils import read_gisrc class DataCatalog(wx.Panel): @@ -65,9 +67,23 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, # some layout self._layout() - # show data structure infobar for first-time user with proper layout + # show infobar if applicable if is_current_mapset_in_demolocation(): - wx.CallLater(2000, self.showDataStructureInfo) + grassrc = read_gisrc() + if grassrc['REASON'] == "invalid": + if (grassrc['UNUSED_GISDBASE'] == os.getcwd() and + grassrc['UNUSED_LOCATION_NAME'] == "" and + grassrc['UNUSED_MAPSET'] == ""): + # show data structure infobar for first-time user + wx.CallLater(2000, self.showDataStructureInfo) + else: + wx.CallLater(2000, self.showBasicDemolocationInfo) + elif "owned by different user" in grassrc['REASON']: + # show basic info + wx.CallLater(2000, self.showBasicDemolocationInfo) + elif grassrc['REASON'] == "locked": + # show info allowing to switch to locked mapset + wx.CallLater(2000, self.showLockedMapsetInfo) def _layout(self): """Do layout""" @@ -85,6 +101,12 @@ def _layout(self): def showDataStructureInfo(self): self.infoManager.ShowDataStructureInfo(self.OnCreateLocation) + def showLockedMapsetInfo(self): + self.infoManager.ShowLockedMapsetInfo(self.OnSwitchMapset) + + def showBasicDemolocationInfo(self): + self.infoManager.ShowBasicDemolocationInfo() + def showImportDataInfo(self): self.infoManager.ShowImportDataInfo(self.OnImportOgrLayers, self.OnImportGdalLayers) @@ -135,6 +157,15 @@ def OnDownloadLocation(self, event): db_node, loc_node, mapset_node = self.tree.GetCurrentDbLocationMapsetNode() self.tree.DownloadLocation(db_node) + def OnSwitchMapset(self, event): + """Switch to given mapset""" + grassrc = read_gisrc() + grassdb=grassrc['UNUSED_GISDBASE'] + location=grassrc['UNUSED_LOCATION_NAME'] + mapset=grassrc['UNUSED_MAPSET'] + self.tree.SwitchMapset(grassdb, location, mapset) + event.Skip() + def OnImportGdalLayers(self, event): """Convert multiple GDAL layers to GRASS raster map layers""" from modules.import_export import GdalImportDialog diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index da277e58630..be26a582273 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -20,7 +20,7 @@ import wx from grass.script import gisenv - +from startup.guiutils import read_gisrc class DataCatalogInfoManager: """Manager for all things related to info bar in Data Catalog""" @@ -58,5 +58,35 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler ).format(loc=gisenv()['LOCATION_NAME']) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) + def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): + """Show info when last used mapset is locked""" + grassrc = read_gisrc() + buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] + message = _( + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked." + "GRASS GIS has started in the default Location {loc} which uses " + "WGS 84 (EPSG:4326). To continue, set usable mapset through Data " + "Catalog below, or remove .gislock and switch to last usable mapset." + ).format(lastdb=grassrc['UNUSED_GISDBASE'], + lastloc=grassrc['UNUSED_LOCATION_NAME'], + lastmapset=grassrc['UNUSED_MAPSET'], + loc=gisenv()['LOCATION_NAME']) + self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) + + def ShowBasicDemolocationInfo(self): + """Show info when last used mapset is invalid or owned by different user""" + grassrc = read_gisrc() + message = _( + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is {reason}." + "GRASS GIS has started in the default Location {loc} which uses " + "WGS 84 (EPSG:4326). To continue, find or create usable mapset through " + "Data catalog below." + ).format(lastdb=grassrc['UNUSED_GISDBASE'], + lastmapset=grassrc['UNUSED_MAPSET'], + lastloc=grassrc['UNUSED_LOCATION_NAME'], + reason=grassrc['REASON'], + loc=gisenv()['LOCATION_NAME']) + self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) + def _onLearnMore(self, event): self._giface.Help(entry="grass_database") diff --git a/gui/wxpython/gis_set.py b/gui/wxpython/gis_set.py deleted file mode 100644 index 2ca305c6e58..00000000000 --- a/gui/wxpython/gis_set.py +++ /dev/null @@ -1,955 +0,0 @@ -""" -@package gis_set - -GRASS start-up screen. - -Initialization module for wxPython GRASS GUI. -Location/mapset management (selection, creation, etc.). - -Classes: - - gis_set::GRASSStartup - - gis_set::GListBox - - gis_set::StartUp - -(C) 2006-2014 by the GRASS Development Team - -This program is free software under the GNU General Public License -(>=v2). Read the file COPYING that comes with GRASS for details. - -@author Michael Barton and Jachym Cepicky (original author) -@author Martin Landa (various updates) -""" - -import os -import sys -import copy -import platform - -# i18n is taken care of in the grass library code. -# So we need to import it before any of the GUI code. - -from core import globalvar -import wx -# import adv and html before wx.App is created, otherwise -# we get annoying "Debug: Adding duplicate image handler for 'Windows bitmap file'" -# during download location dialog start up, remove when not needed -import wx.adv -import wx.html -import wx.lib.mixins.listctrl as listmix - -from grass.grassdb.checks import get_lockfile_if_present -from grass.app import get_possible_database_path - -from core.gcmd import GError, RunCommand -from core.utils import GetListOfLocations, GetListOfMapsets -from startup.guiutils import (SetSessionMapset, - create_mapset_interactively, - create_location_interactively, - rename_mapset_interactively, - rename_location_interactively, - delete_mapset_interactively, - delete_location_interactively, - download_location_interactively) -import startup.guiutils as sgui -from gui_core.widgets import StaticWrapText -from gui_core.wrap import Button, ListCtrl, StaticText, StaticBox, \ - TextCtrl, BitmapFromImage - - -class GRASSStartup(wx.Frame): - exit_success = 0 - # 2 is file not found from python interpreter - exit_user_requested = 5 - - """GRASS start-up screen""" - - def __init__(self, parent=None, id=wx.ID_ANY, - style=wx.DEFAULT_FRAME_STYLE): - - # - # GRASS variables - # - self.gisbase = os.getenv("GISBASE") - self.grassrc = sgui.read_gisrc() - self.gisdbase = self.GetRCValue("GISDBASE") - - # - # list of locations/mapsets - # - self.listOfLocations = [] - self.listOfMapsets = [] - self.listOfMapsetsSelectable = [] - - wx.Frame.__init__(self, parent=parent, id=id, style=style) - - self.locale = wx.Locale(language=wx.LANGUAGE_DEFAULT) - - # scroll panel was used here but not properly and is probably not need - # as long as it is not high too much - self.panel = wx.Panel(parent=self, id=wx.ID_ANY) - - # i18N - - # - # graphical elements - # - # image - try: - if os.getenv('ISISROOT'): - name = os.path.join( - globalvar.GUIDIR, - "images", - "startup_banner_isis.png") - else: - name = os.path.join( - globalvar.GUIDIR, "images", "startup_banner.png") - self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, - wx.Bitmap(name=name, - type=wx.BITMAP_TYPE_PNG)) - except: - self.hbitmap = wx.StaticBitmap( - self.panel, wx.ID_ANY, BitmapFromImage( - wx.EmptyImage(530, 150))) - - # labels - # crashes when LOCATION doesn't exist - # get version & revision - grassVersion, grassRevisionStr = sgui.GetVersion() - - self.gisdbase_box = StaticBox( - parent=self.panel, id=wx.ID_ANY, label=" %s " % - _("1. Select GRASS GIS database directory")) - self.location_box = StaticBox( - parent=self.panel, id=wx.ID_ANY, label=" %s " % - _("2. Select GRASS Location")) - self.mapset_box = StaticBox( - parent=self.panel, id=wx.ID_ANY, label=" %s " % - _("3. Select GRASS Mapset")) - - self.lmessage = StaticWrapText(parent=self.panel) - # It is not clear if all wx versions supports color, so try-except. - # The color itself may not be correct for all platforms/system settings - # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html - # there is no 'warning' color. - try: - self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0)) - except AttributeError: - pass - - self.gisdbase_panel = wx.Panel(parent=self.panel) - self.location_panel = wx.Panel(parent=self.panel) - self.mapset_panel = wx.Panel(parent=self.panel) - - self.ldbase = StaticText( - parent=self.gisdbase_panel, id=wx.ID_ANY, - label=_("GRASS GIS database directory contains Locations.")) - - self.llocation = StaticWrapText( - parent=self.location_panel, id=wx.ID_ANY, - label=_("All data in one Location is in the same " - " coordinate reference system (projection)." - " One Location can be one project." - " Location contains Mapsets."), - style=wx.ALIGN_LEFT) - - self.lmapset = StaticWrapText( - parent=self.mapset_panel, id=wx.ID_ANY, - label=_("Mapset contains GIS data related" - " to one project, task within one project," - " subregion or user."), - style=wx.ALIGN_LEFT) - - try: - for label in [self.ldbase, self.llocation, self.lmapset]: - label.SetForegroundColour( - wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - except AttributeError: - # for explanation of try-except see above - pass - - # buttons - self.bstart = Button(parent=self.panel, id=wx.ID_ANY, - label=_("Start &GRASS session")) - self.bstart.SetDefault() - self.bexit = Button(parent=self.panel, id=wx.ID_EXIT) - self.bstart.SetMinSize((180, self.bexit.GetSize()[1])) - self.bhelp = Button(parent=self.panel, id=wx.ID_HELP) - self.bbrowse = Button(parent=self.gisdbase_panel, id=wx.ID_ANY, - label=_("&Browse")) - self.bmapset = Button(parent=self.mapset_panel, id=wx.ID_ANY, - # GTC New mapset - label=_("&New")) - self.bmapset.SetToolTip(_("Create a new Mapset in selected Location")) - self.bwizard = Button(parent=self.location_panel, id=wx.ID_ANY, - # GTC New location - label=_("N&ew")) - self.bwizard.SetToolTip( - _( - "Create a new location using location wizard." - " After location is created successfully," - " GRASS session is started.")) - self.rename_location_button = Button(parent=self.location_panel, id=wx.ID_ANY, - # GTC Rename location - label=_("Ren&ame")) - self.rename_location_button.SetToolTip(_("Rename selected location")) - self.delete_location_button = Button(parent=self.location_panel, id=wx.ID_ANY, - # GTC Delete location - label=_("De&lete")) - self.delete_location_button.SetToolTip(_("Delete selected location")) - self.download_location_button = Button(parent=self.location_panel, id=wx.ID_ANY, - label=_("Do&wnload")) - self.download_location_button.SetToolTip(_("Download sample location")) - - self.rename_mapset_button = Button(parent=self.mapset_panel, id=wx.ID_ANY, - # GTC Rename mapset - label=_("&Rename")) - self.rename_mapset_button.SetToolTip(_("Rename selected mapset")) - self.delete_mapset_button = Button(parent=self.mapset_panel, id=wx.ID_ANY, - # GTC Delete mapset - label=_("&Delete")) - self.delete_mapset_button.SetToolTip(_("Delete selected mapset")) - - # textinputs - self.tgisdbase = TextCtrl( - parent=self.gisdbase_panel, id=wx.ID_ANY, value="", size=( - 300, -1), style=wx.TE_PROCESS_ENTER) - - # Locations - self.lblocations = GListBox(parent=self.location_panel, - id=wx.ID_ANY, size=(180, 200), - choices=self.listOfLocations) - self.lblocations.SetColumnWidth(0, 180) - - # TODO: sort; but keep PERMANENT on top of list - # Mapsets - self.lbmapsets = GListBox(parent=self.mapset_panel, - id=wx.ID_ANY, size=(180, 200), - choices=self.listOfMapsets) - self.lbmapsets.SetColumnWidth(0, 180) - - # layout & properties, first do layout so everything is created - self._do_layout() - self._set_properties(grassVersion, grassRevisionStr) - - # events - self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse) - self.bstart.Bind(wx.EVT_BUTTON, self.OnStart) - self.bexit.Bind(wx.EVT_BUTTON, self.OnExit) - self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp) - self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset) - self.bwizard.Bind(wx.EVT_BUTTON, self.OnCreateLocation) - - self.rename_location_button.Bind(wx.EVT_BUTTON, self.OnRenameLocation) - self.delete_location_button.Bind(wx.EVT_BUTTON, self.OnDeleteLocation) - self.download_location_button.Bind(wx.EVT_BUTTON, self.OnDownloadLocation) - self.rename_mapset_button.Bind(wx.EVT_BUTTON, self.OnRenameMapset) - self.delete_mapset_button.Bind(wx.EVT_BUTTON, self.OnDeleteMapset) - - self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation) - self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMapset) - self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart) - self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase) - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - - def _set_properties(self, version, revision): - """Set frame properties - - :param version: Version in the form of X.Y.Z - :param revision: Version control revision with leading space - - *revision* should be an empty string in case of release and - otherwise it needs a leading space to be separated from the rest - of the title. - """ - self.SetTitle(_("GRASS GIS %s Startup%s") % (version, revision)) - self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"), - wx.BITMAP_TYPE_ICO)) - - self.bstart.SetToolTip(_("Enter GRASS session")) - self.bstart.Enable(False) - self.bmapset.Enable(False) - # this all was originally a choice, perhaps just mapset needed - self.rename_location_button.Enable(False) - self.delete_location_button.Enable(False) - self.rename_mapset_button.Enable(False) - self.delete_mapset_button.Enable(False) - - # set database - if not self.gisdbase: - # sets an initial path for gisdbase if nothing in GISRC - if os.path.isdir(os.getenv("HOME")): - self.gisdbase = os.getenv("HOME") - else: - self.gisdbase = os.getcwd() - try: - self.tgisdbase.SetValue(self.gisdbase) - except UnicodeDecodeError: - wx.MessageBox(parent=self, caption=_("Error"), - message=_("Unable to set GRASS database. " - "Check your locale settings."), - style=wx.OK | wx.ICON_ERROR | wx.CENTRE) - - self.OnSetDatabase(None) - location = self.GetRCValue("LOCATION_NAME") - if location == "" or location is None: - return - if not os.path.isdir(os.path.join(self.gisdbase, location)): - location = None - - # list of locations - self.UpdateLocations(self.gisdbase) - try: - self.lblocations.SetSelection(self.listOfLocations.index(location), - force=True) - self.lblocations.EnsureVisible( - self.listOfLocations.index(location)) - except ValueError: - sys.stderr.write( - _("ERROR: Location <%s> not found\n") % - self.GetRCValue("LOCATION_NAME")) - if len(self.listOfLocations) > 0: - self.lblocations.SetSelection(0, force=True) - self.lblocations.EnsureVisible(0) - location = self.listOfLocations[0] - else: - return - - # list of mapsets - self.UpdateMapsets(os.path.join(self.gisdbase, location)) - mapset = self.GetRCValue("MAPSET") - if mapset: - try: - self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset), - force=True) - self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset)) - except ValueError: - sys.stderr.write(_("ERROR: Mapset <%s> not found\n") % mapset) - self.lbmapsets.SetSelection(0, force=True) - self.lbmapsets.EnsureVisible(0) - - def _do_layout(self): - sizer = wx.BoxSizer(wx.VERTICAL) - self.sizer = sizer # for the layout call after changing message - dbase_sizer = wx.BoxSizer(wx.HORIZONTAL) - - location_mapset_sizer = wx.BoxSizer(wx.HORIZONTAL) - - gisdbase_panel_sizer = wx.BoxSizer(wx.VERTICAL) - gisdbase_boxsizer = wx.StaticBoxSizer(self.gisdbase_box, wx.VERTICAL) - - btns_sizer = wx.BoxSizer(wx.HORIZONTAL) - - self.gisdbase_panel.SetSizer(gisdbase_panel_sizer) - - # gis data directory - - gisdbase_boxsizer.Add(self.gisdbase_panel, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=1) - - gisdbase_panel_sizer.Add(dbase_sizer, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=1) - gisdbase_panel_sizer.Add(self.ldbase, proportion=0, - flag=wx.EXPAND | wx.ALL, - border=1) - - dbase_sizer.Add(self.tgisdbase, proportion=1, - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, - border=1) - dbase_sizer.Add(self.bbrowse, proportion=0, - flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, - border=1) - - gisdbase_panel_sizer.Fit(self.gisdbase_panel) - - # location and mapset lists - - def layout_list_box(box, panel, list_box, buttons, description): - panel_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer = wx.BoxSizer(wx.HORIZONTAL) - box_sizer = wx.StaticBoxSizer(box, wx.VERTICAL) - buttons_sizer = wx.BoxSizer(wx.VERTICAL) - - panel.SetSizer(panel_sizer) - panel_sizer.Fit(panel) - - main_sizer.Add(list_box, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=1) - main_sizer.Add(buttons_sizer, proportion=0, - flag=wx.ALL, - border=1) - for button in buttons: - buttons_sizer.Add(button, proportion=0, - flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, - border=3) - box_sizer.Add(panel, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=1) - panel_sizer.Add(main_sizer, proportion=1, - flag=wx.EXPAND | wx.ALL, - border=1) - panel_sizer.Add(description, proportion=0, - flag=wx.EXPAND | wx.ALL, - border=1) - return box_sizer - - location_boxsizer = layout_list_box( - box=self.location_box, - panel=self.location_panel, - list_box=self.lblocations, - buttons=[self.bwizard, self.rename_location_button, - self.delete_location_button, - self.download_location_button], - description=self.llocation) - mapset_boxsizer = layout_list_box( - box=self.mapset_box, - panel=self.mapset_panel, - list_box=self.lbmapsets, - buttons=[self.bmapset, self.rename_mapset_button, - self.delete_mapset_button], - description=self.lmapset) - - # location and mapset sizer - location_mapset_sizer.Add(location_boxsizer, proportion=1, - flag=wx.LEFT | wx.RIGHT | wx.EXPAND, - border=3) - location_mapset_sizer.Add(mapset_boxsizer, proportion=1, - flag=wx.RIGHT | wx.EXPAND, - border=3) - - # buttons - btns_sizer.Add(self.bstart, proportion=0, - flag=wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, - border=5) - btns_sizer.Add(self.bexit, proportion=0, - flag=wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, - border=5) - btns_sizer.Add(self.bhelp, proportion=0, - flag=wx.ALIGN_CENTER_HORIZONTAL | - wx.ALIGN_CENTER_VERTICAL | - wx.ALL, - border=5) - - # main sizer - sizer.Add(self.hbitmap, - proportion=0, - flag=wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.ALL, - border=3) # image - sizer.Add(gisdbase_boxsizer, proportion=0, - flag=wx.RIGHT | wx.LEFT | wx.TOP | wx.EXPAND, - border=3) # GISDBASE setting - - # warning/error message - sizer.Add(self.lmessage, - proportion=0, - flag=wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, border=5) - sizer.Add(location_mapset_sizer, proportion=1, - flag=wx.RIGHT | wx.LEFT | wx.EXPAND, - border=1) - sizer.Add(btns_sizer, proportion=0, - flag=wx.ALIGN_CENTER_VERTICAL | - wx.ALIGN_CENTER_HORIZONTAL | - wx.RIGHT | wx.LEFT, - border=3) - - self.panel.SetAutoLayout(True) - self.panel.SetSizer(sizer) - sizer.Fit(self.panel) - sizer.SetSizeHints(self) - self.Layout() - - def _showWarning(self, text): - """Displays a warning, hint or info message to the user. - - This function can be used for all kinds of messages except for - error messages. - - .. note:: - There is no cleaning procedure. You should call _hideMessage when - you know that there is everything correct now. - """ - self.lmessage.SetLabel(text) - self.sizer.Layout() - - def _showError(self, text): - """Displays a error message to the user. - - This function should be used only when something serious and unexpected - happens, otherwise _showWarning should be used. - - .. note:: - There is no cleaning procedure. You should call _hideMessage when - you know that there is everything correct now. - """ - self.lmessage.SetLabel(_("Error: {text}").format(text=text)) - self.sizer.Layout() - - def _hideMessage(self): - """Clears/hides the error message.""" - # we do no hide widget - # because we do not want the dialog to change the size - self.lmessage.SetLabel("") - self.sizer.Layout() - - def GetRCValue(self, value): - """Return GRASS variable (read from GISRC) - """ - if value in self.grassrc: - return self.grassrc[value] - else: - return None - - def SuggestDatabase(self): - """Suggest (set) possible GRASS Database value""" - # only if nothing is set ( comes from init script) - if self.GetRCValue("LOCATION_NAME") != "": - return - path = get_possible_database_path() - if path: - try: - self.tgisdbase.SetValue(path) - except UnicodeDecodeError: - # restore previous state - # wizard gives error in this case, we just ignore - path = None - self.tgisdbase.SetValue(self.gisdbase) - # if we still have path - if path: - self.gisdbase = path - self.OnSetDatabase(None) - else: - # nothing found - # TODO: should it be warning, hint or message? - self._showWarning(_( - 'GRASS needs a directory (GRASS database) ' - 'in which to store its data. ' - 'Create one now if you have not already done so. ' - 'A popular choice is "grassdata", located in ' - 'your home directory. ' - 'Press Browse button to select the directory.')) - - def OnCreateLocation(self, event): - """Location wizard started""" - grassdatabase, location, mapset = ( - create_location_interactively(self, self.gisdbase) - ) - if location is not None: - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset)) - self.bstart.SetFocus() - self.tgisdbase.SetValue(grassdatabase) - self.OnSetDatabase(None) - self.UpdateMapsets(os.path.join(grassdatabase, location)) - self.lblocations.SetSelection( - self.listOfLocations.index(location)) - self.lbmapsets.SetSelection(0) - self.SetLocation(grassdatabase, location, mapset) - - # the event can be refactored out by using lambda in bind - def OnRenameMapset(self, event): - """Rename selected mapset - """ - location = self.listOfLocations[self.lblocations.GetSelection()] - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - try: - newmapset = rename_mapset_interactively(self, self.gisdbase, - location, mapset) - if newmapset: - self.OnSelectLocation(None) - self.lbmapsets.SetSelection( - self.listOfMapsets.index(newmapset)) - except Exception as e: - GError(parent=self, - message=_("Unable to rename mapset: %s") % e, - showTraceback=False) - - def OnRenameLocation(self, event): - """Rename selected location - """ - location = self.listOfLocations[self.lblocations.GetSelection()] - try: - newlocation = rename_location_interactively(self, self.gisdbase, - location) - if newlocation: - self.UpdateLocations(self.gisdbase) - self.lblocations.SetSelection( - self.listOfLocations.index(newlocation)) - self.UpdateMapsets(newlocation) - except Exception as e: - GError(parent=self, - message=_("Unable to rename location: %s") % e, - showTraceback=False) - - def OnDeleteMapset(self, event): - """ - Delete selected mapset - """ - location = self.listOfLocations[self.lblocations.GetSelection()] - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - if (delete_mapset_interactively(self, self.gisdbase, location, mapset)): - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(0) - - def OnDeleteLocation(self, event): - """ - Delete selected location - """ - location = self.listOfLocations[self.lblocations.GetSelection()] - try: - if (delete_location_interactively(self, self.gisdbase, location)): - self.UpdateLocations(self.gisdbase) - self.lblocations.SetSelection(0) - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(0) - except Exception as e: - GError(parent=self, - message=_("Unable to delete location: %s") % e, - showTraceback=False) - - def OnDownloadLocation(self, event): - """ - Download location online - """ - grassdatabase, location, mapset = download_location_interactively( - self, self.gisdbase - ) - if location: - # get the new location to the list - self.UpdateLocations(grassdatabase) - # seems to be used in similar context - self.UpdateMapsets(os.path.join(grassdatabase, location)) - self.lblocations.SetSelection( - self.listOfLocations.index(location)) - # wizard does this as well, not sure if needed - self.SetLocation(grassdatabase, location, mapset) - # seems to be used in similar context - self.OnSelectLocation(None) - - def UpdateLocations(self, dbase): - """Update list of locations""" - try: - self.listOfLocations = GetListOfLocations(dbase) - except (UnicodeEncodeError, UnicodeDecodeError) as e: - GError(parent=self, - message=_("Unicode error detected. " - "Check your locale settings. Details: {0}").format(e), - showTraceback=False) - - self.lblocations.Clear() - self.lblocations.InsertItems(self.listOfLocations, 0) - - if len(self.listOfLocations) > 0: - self._hideMessage() - self.lblocations.SetSelection(0) - else: - self.lblocations.SetSelection(wx.NOT_FOUND) - self._showWarning(_("No GRASS Location found in '%s'." - " Create a new Location or choose different" - " GRASS database directory.") - % self.gisdbase) - - return self.listOfLocations - - def UpdateMapsets(self, location): - """Update list of mapsets""" - self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item - - self.listOfMapsetsSelectable = list() - self.listOfMapsets = GetListOfMapsets(self.gisdbase, location) - - self.lbmapsets.Clear() - - # disable mapset with denied permission - locationName = os.path.basename(location) - - ret = RunCommand('g.mapset', - read=True, - flags='l', - location=locationName, - gisdbase=self.gisdbase) - - if ret: - for line in ret.splitlines(): - self.listOfMapsetsSelectable += line.split(' ') - else: - self.SetLocation(self.gisdbase, locationName, "PERMANENT") - # first run only - self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets) - - disabled = [] - idx = 0 - for mapset in self.listOfMapsets: - if mapset not in self.listOfMapsetsSelectable or \ - get_lockfile_if_present(self.gisdbase, - locationName, mapset): - disabled.append(idx) - idx += 1 - - self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled) - - return self.listOfMapsets - - def OnSelectLocation(self, event): - """Location selected""" - if event: - self.lblocations.SetSelection(event.GetIndex()) - - if self.lblocations.GetSelection() != wx.NOT_FOUND: - self.UpdateMapsets( - os.path.join( - self.gisdbase, - self.listOfLocations[ - self.lblocations.GetSelection()])) - else: - self.listOfMapsets = [] - - disabled = [] - idx = 0 - try: - locationName = self.listOfLocations[ - self.lblocations.GetSelection()] - except IndexError: - locationName = '' - - for mapset in self.listOfMapsets: - if mapset not in self.listOfMapsetsSelectable or \ - get_lockfile_if_present(self.gisdbase, - locationName, mapset): - disabled.append(idx) - idx += 1 - - self.lbmapsets.Clear() - self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled) - - if len(self.listOfMapsets) > 0: - self.lbmapsets.SetSelection(0) - if locationName: - # enable start button when location and mapset is selected - self.bstart.Enable() - self.bstart.SetFocus() - self.bmapset.Enable() - # replacing disabled choice, perhaps just mapset needed - self.rename_location_button.Enable() - self.delete_location_button.Enable() - self.rename_mapset_button.Enable() - self.delete_mapset_button.Enable() - else: - self.lbmapsets.SetSelection(wx.NOT_FOUND) - self.bstart.Enable(False) - self.bmapset.Enable(False) - # this all was originally a choice, perhaps just mapset needed - self.rename_location_button.Enable(False) - self.delete_location_button.Enable(False) - self.rename_mapset_button.Enable(False) - self.delete_mapset_button.Enable(False) - - def OnSelectMapset(self, event): - """Mapset selected""" - self.lbmapsets.SetSelection(event.GetIndex()) - - if event.GetText() not in self.listOfMapsetsSelectable: - self.lbmapsets.SetSelection(self.FormerMapsetSelection) - else: - self.FormerMapsetSelection = event.GetIndex() - event.Skip() - - def OnSetDatabase(self, event): - """Database set""" - gisdbase = self.tgisdbase.GetValue() - self._hideMessage() - if not os.path.exists(gisdbase): - self._showError(_("Path '%s' doesn't exist.") % gisdbase) - return - - self.gisdbase = self.tgisdbase.GetValue() - self.UpdateLocations(self.gisdbase) - - self.OnSelectLocation(None) - - def OnBrowse(self, event): - """'Browse' button clicked""" - if not event: - defaultPath = os.getenv('HOME') - else: - defaultPath = "" - - dlg = wx.DirDialog(parent=self, message=_("Choose GIS Data Directory"), - defaultPath=defaultPath, style=wx.DD_DEFAULT_STYLE) - - if dlg.ShowModal() == wx.ID_OK: - self.gisdbase = dlg.GetPath() - self.tgisdbase.SetValue(self.gisdbase) - self.OnSetDatabase(event) - - dlg.Destroy() - - def OnCreateMapset(self, event): - """Create new mapset""" - gisdbase = self.tgisdbase.GetValue() - location = self.listOfLocations[self.lblocations.GetSelection()] - try: - mapset = create_mapset_interactively(self, gisdbase, location) - if mapset: - self.OnSelectLocation(None) - self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset)) - self.bstart.SetFocus() - except Exception as e: - GError(parent=self, - message=_("Unable to create new mapset: %s") % e, - showTraceback=False) - - def OnStart(self, event): - """'Start GRASS' button clicked""" - dbase = self.tgisdbase.GetValue() - location = self.listOfLocations[self.lblocations.GetSelection()] - mapset = self.listOfMapsets[self.lbmapsets.GetSelection()] - - lockfile = get_lockfile_if_present(dbase, location, mapset) - if lockfile: - dlg = wx.MessageDialog( - parent=self, - message=_( - "GRASS is already running in selected mapset <%(mapset)s>\n" - "(file %(lock)s found).\n\n" - "Concurrent use not allowed.\n\n" - "Do you want to try to remove .gislock (note that you " - "need permission for this operation) and continue?") % - {'mapset': mapset, 'lock': lockfile}, - caption=_("Lock file found"), - style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE) - - ret = dlg.ShowModal() - dlg.Destroy() - if ret == wx.ID_YES: - dlg1 = wx.MessageDialog( - parent=self, - message=_( - "ARE YOU REALLY SURE?\n\n" - "If you really are running another GRASS session doing this " - "could corrupt your data. Have another look in the processor " - "manager just to be sure..."), - caption=_("Lock file found"), - style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE) - - ret = dlg1.ShowModal() - dlg1.Destroy() - - if ret == wx.ID_YES: - try: - os.remove(lockfile) - except IOError as e: - GError(_("Unable to remove '%(lock)s'.\n\n" - "Details: %(reason)s") % {'lock': lockfile, 'reason': e}) - else: - return - else: - return - self.SetLocation(dbase, location, mapset) - self.ExitSuccessfully() - - def SetLocation(self, dbase, location, mapset): - SetSessionMapset(dbase, location, mapset) - - def ExitSuccessfully(self): - self.Destroy() - sys.exit(self.exit_success) - - def OnExit(self, event): - """'Exit' button clicked""" - self.Destroy() - sys.exit(self.exit_user_requested) - - def OnHelp(self, event): - """'Help' button clicked""" - - # help text in lib/init/helptext.html - RunCommand('g.manual', entry='helptext') - - def OnCloseWindow(self, event): - """Close window event""" - event.Skip() - sys.exit(self.exit_user_requested) - - -class GListBox(ListCtrl, listmix.ListCtrlAutoWidthMixin): - """Use wx.ListCtrl instead of wx.ListBox, different style for - non-selectable items (e.g. mapsets with denied permission)""" - - def __init__(self, parent, id, size, - choices, disabled=[]): - ListCtrl.__init__( - self, parent, id, size=size, style=wx.LC_REPORT | wx.LC_NO_HEADER | - wx.LC_SINGLE_SEL | wx.BORDER_SUNKEN) - - listmix.ListCtrlAutoWidthMixin.__init__(self) - - self.InsertColumn(0, '') - - self.selected = wx.NOT_FOUND - - self._LoadData(choices, disabled) - - def _LoadData(self, choices, disabled=[]): - """Load data into list - - :param choices: list of item - :param disabled: list of indices of non-selectable items - """ - idx = 0 - count = self.GetItemCount() - for item in choices: - index = self.InsertItem(count + idx, item) - self.SetItem(index, 0, item) - - if idx in disabled: - self.SetItemTextColour(idx, wx.Colour(150, 150, 150)) - idx += 1 - - def Clear(self): - self.DeleteAllItems() - - def InsertItems(self, choices, pos, disabled=[]): - self._LoadData(choices, disabled) - - def SetSelection(self, item, force=False): - if item != wx.NOT_FOUND and \ - (platform.system() != 'Windows' or force): - # Windows -> FIXME - self.SetItemState( - item, - wx.LIST_STATE_SELECTED, - wx.LIST_STATE_SELECTED) - - self.selected = item - - def GetSelection(self): - return self.selected - - -class StartUp(wx.App): - """Start-up application""" - - def OnInit(self): - StartUp = GRASSStartup() - StartUp.CenterOnScreen() - self.SetTopWindow(StartUp) - StartUp.Show() - StartUp.SuggestDatabase() - - return 1 - - -if __name__ == "__main__": - if os.getenv("GISBASE") is None: - sys.exit("Failed to start GUI, GRASS GIS is not running.") - - GRASSStartUp = StartUp(0) - GRASSStartUp.MainLoop() diff --git a/gui/wxpython/gis_set_error.py b/gui/wxpython/gis_set_error.py deleted file mode 100644 index 7bd93fe5806..00000000000 --- a/gui/wxpython/gis_set_error.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -@package gis_set_error - -GRASS start-up screen error message. - -(C) 2010-2011 by the GRASS Development Team - -This program is free software under the GNU General Public License -(>=v2). Read the file COPYING that comes with GRASS for details. - -@author Martin Landa -""" - -import sys - -# i18n is taken care of in the grass library code. -# So we need to import it before any of the GUI code. -# NOTE: in this particular case, we don't really need the grass library; -# NOTE: we import it just for the side effects of gettext.install() - -import wx - - -def main(): - app = wx.App() - - if len(sys.argv) == 1: - msg = "Unknown reason" - else: - msg = '' - for m in sys.argv[1:]: - msg += m - - wx.MessageBox(caption="Error", - message=msg, - style=wx.OK | wx.ICON_ERROR) - - app.MainLoop() - -if __name__ == "__main__": - main() diff --git a/lib/init/grass.py b/lib/init/grass.py index e50e7cb0cf4..381b9f55001 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -549,9 +549,6 @@ def create_gisrc(tmpdir, gisrcrc): # remove invalid GISRC file to avoid disturbing error messages: try: s = readfile(gisrcrc) - if "UNKNOWN" in s: - try_remove(gisrcrc) - s = None except: s = None @@ -605,14 +602,20 @@ def write_gisrc(kv, filename, append=False): f.close() -def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): +def set_mapset_info_to_gisrc(gisrc, grassdb, location, mapset, + unused_grassdb=None, unused_location=None, + unused_mapset=None, reason=None): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) else: kv = {} - kv["GISDBASE"] = grassdb - kv["LOCATION_NAME"] = location - kv["MAPSET"] = mapset + kv['GISDBASE'] = grassdb + kv['LOCATION_NAME'] = location + kv['MAPSET'] = mapset + kv['UNUSED_GISDBASE'] = unused_grassdb + kv['UNUSED_LOCATION_NAME'] = unused_location + kv['UNUSED_MAPSET'] = unused_mapset + kv['REASON'] = reason write_gisrc(kv, gisrc) @@ -838,7 +841,11 @@ def create_initial_gisrc(filename): r"""GISDBASE: %s LOCATION_NAME: MAPSET: -""" +UNUSED_GISDBASE: None +UNUSED_LOCATION_NAME: None +UNUSED_MAPSET: None +REASON: None +""" % os.getcwd() ) writefile(filename, s) @@ -1165,7 +1172,7 @@ def set_mapset( ) ) writefile(os.path.join(path, "WIND"), s) - set_mapset_to_gisrc(gisrc, gisdbase, location_name, mapset) + set_mapset_info_to_gisrc(gisrc, gisdbase, location_name, mapset) else: fatal( _( @@ -1176,77 +1183,6 @@ def set_mapset( ) -def set_mapset_interactive(grass_gui): - """User selects Location and Mapset in an interative way - - The gisrc (GRASS environment file) is written at the end. - """ - if not os.path.exists(wxpath("gis_set.py")) and grass_gui != "text": - debug("No GUI available, switching to text mode") - return False - - # Check for text interface - if grass_gui == "text": - # TODO: maybe this should be removed and solved from outside - # this depends on what we expect from this function - # should gisrc be ok after running or is it allowed to be still not set - pass - # Check for GUI - elif grass_gui in ("gtext", "wxpython"): - gui_startup(grass_gui) - else: - # Shouldn't need this but you never know - fatal( - _( - "Invalid user interface specified - <%s>. " - "Use the --help option to see valid interface names." - ) - % grass_gui - ) - - return True - - -def gui_startup(grass_gui): - """Start GUI for startup (setting gisrc file)""" - if grass_gui in ("wxpython", "gtext"): - ret = call([os.getenv("GRASS_PYTHON"), wxpath("gis_set.py")]) - - # this if could be simplified to three branches (0, 5, rest) - # if there is no need to handle unknown code separately - if ret == 0: - pass - elif ret in [1, 2]: - # 1 probably error coming from gis_set.py - # 2 probably file not found from python interpreter - # formerly we were starting in text mode instead, now we just fail - # which is more straightforward for everybody - fatal( - _( - "Error in GUI startup. See messages above (if any)" - " and if necessary, please" - " report this error to the GRASS developers.\n" - "On systems with package manager, make sure you have the right" - " GUI package, probably named grass-gui, installed.\n" - "To run GRASS GIS in text mode use the --text flag.\n" - "Use '--help' for further options\n" - " {cmd_name} --help\n" - "See also: https://grass.osgeo.org/{cmd_name}/manuals/helptext.html" - ).format(cmd_name=CMD_NAME) - ) - elif ret == 5: # defined in gui/wxpython/gis_set.py - # User wants to exit from GRASS - message(_("Exit was requested in GUI.\nGRASS GIS will not start. Bye.")) - sys.exit(0) - else: - fatal( - _( - "Invalid return code from GUI startup script.\n" - "Please advise GRASS developers of this error." - ) - ) - - # we don't follow the LOCATION_NAME legacy naming here but we have to still # translate to it, so always double check class MapsetSettings(object): @@ -1260,6 +1196,10 @@ def __init__(self): self.location = None self.mapset = None self._full_mapset = None + self.unused_gisdbase = None + self.unused_location = None + self.unused_mapset = None + self.reason = None # TODO: perhaps full_mapset would be better as mapset_path # TODO: works only when set for the first time @@ -1275,6 +1215,28 @@ def full_mapset(self): def is_valid(self): return self.gisdbase and self.location and self.mapset + def get_reason_mapset_not_usable(self): + """Check if a mapset is usable for a new session""" + from grass.grassdb.checks import get_reason_mapset_not_usable + self.reason = get_reason_mapset_not_usable(self._full_mapset) + return self.reason + + +def getMapsetSettings(gisrc): + """Get the settings of Location and Mapset from the gisrc file""" + mapset_settings = MapsetSettings() + kv = read_gisrc(gisrc) + mapset_settings.gisdbase = kv.get('GISDBASE') + mapset_settings.location = kv.get('LOCATION_NAME') + mapset_settings.mapset = kv.get('MAPSET') + mapset_settings.unused_gisdbase = kv.get('UNUSED_GISDBASE') + mapset_settings.unused_location = kv.get('UNUSED_LOCATION_NAME') + mapset_settings.unused_mapset = kv.get('UNUSED_MAPSET') + mapset_settings.reason = kv.get('REASON') + if not mapset_settings.is_valid(): + return None + return mapset_settings + # TODO: does it really makes sense to tell user about gisrcrc? # anything could have happened in between loading from gisrcrc and now @@ -1284,11 +1246,7 @@ def load_gisrc(gisrc, gisrcrc): :returns: MapsetSettings object """ - mapset_settings = MapsetSettings() - kv = read_gisrc(gisrc) - mapset_settings.gisdbase = kv.get("GISDBASE") - mapset_settings.location = kv.get("LOCATION_NAME") - mapset_settings.mapset = kv.get("MAPSET") + mapset_settings = getMapsetSettings(gisrc) if not mapset_settings.is_valid(): fatal( _( @@ -1307,17 +1265,9 @@ def load_gisrc(gisrc, gisrcrc): return mapset_settings -def can_start_in_gisrc_mapset(gisrc, ignore_lock=False): +def can_start_in_gisrc_mapset(mapset_settings, ignore_lock=False): """Check if a mapset from a gisrc file is usable for a new session""" from grass.grassdb.checks import can_start_in_mapset - - mapset_settings = MapsetSettings() - kv = read_gisrc(gisrc) - mapset_settings.gisdbase = kv.get("GISDBASE") - mapset_settings.location = kv.get("LOCATION_NAME") - mapset_settings.mapset = kv.get("MAPSET") - if not mapset_settings.is_valid(): - return False return can_start_in_mapset( mapset_path=mapset_settings.full_mapset, ignore_lock=ignore_lock ) @@ -2505,6 +2455,7 @@ def main(): # Create the session grassrc file gisrc = create_gisrc(tmpdir, gisrcrc) + print(gisrc) ensure_home() # Set PATH, PYTHONPATH, ... @@ -2555,39 +2506,49 @@ def main(): save_gui(gisrc, grass_gui) # Parsing argument to get LOCATION + # Mapset is not specified in command line arguments if not params.mapset and not params.tmp_location: - # Mapset is not specified in command line arguments. + # Get mapset parameters from gisrc file + mapset_settings = getMapsetSettings(gisrc) + # Check if mapset from gisrc is usable last_mapset_usable = can_start_in_gisrc_mapset( - gisrc=gisrc, ignore_lock=params.force_gislock_removal + mapset_settings = mapset_settings, + ignore_lock=params.force_gislock_removal ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: - import grass.app as ga - from grass.grassdb.checks import can_start_in_mapset - # Try to use demolocation - grassdb, location, mapset = ga.ensure_demolocation() - demo_mapset_usable = can_start_in_mapset( - mapset_path=os.path.join(grassdb, location, mapset), - ignore_lock=params.force_gislock_removal, + # Find reason why mapset is not usable + mapset_settings.get_reason_mapset_not_usable() + + # Ensure demolocation + import grass.app as ga + grassdb, location = ga.ensure_demolocation() + # Ensure usable mapset + mapset = ga.ensure_usable_mapset(grassdb, location) + if mapset is None: + sys.exit("Failed to start GUI, GRASS GIS is not running.") + + # Write mapset info to gisrc file + set_mapset_info_to_gisrc( + gisrc=gisrc, + grassdb=grassdb, + location=location, + mapset=mapset, + unused_grassdb=mapset_settings.gisdbase, + unused_location=mapset_settings.location, + unused_mapset=mapset_settings.mapset, + reason=mapset_settings.reason + ) + else: + mapset_settings.reason=None + # Write mapset info to gisrc file + set_mapset_info_to_gisrc( + gisrc=gisrc, + grassdb=mapset_settings.gisdbase, + location=mapset_settings.location, + mapset=mapset_settings.mapset ) - debug(f"demo_mapset_usable: {demo_mapset_usable}") - if demo_mapset_usable: - set_mapset_to_gisrc( - gisrc=gisrc, grassdb=grassdb, location=location, mapset=mapset - ) - else: - # Try interactive startup - # User selects LOCATION and MAPSET if not set - if not set_mapset_interactive(grass_gui): - # No GUI available, update gisrc file - fatal( - _( - "<{0}> requested, but not available. Run GRASS in text " - "mode (--text) or install missing package (usually " - "'grass-gui')." - ).format(grass_gui) - ) else: # Mapset was specified in command line parameters. if params.tmp_location: diff --git a/python/grass/app/data.py b/python/grass/app/data.py index c0ee93a9b29..0f0eba83b8c 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -17,6 +17,8 @@ import getpass import sys from shutil import copytree, ignore_patterns +from grass.grassdb.create import (create_mapset, get_default_mapset_name) +from grass.grassdb.checks import (mapset_exists, can_start_in_mapset) from grass.grassdb.checks import is_location_valid @@ -144,15 +146,39 @@ def create_startup_location_in_grassdb(grassdatabase, startup_location_name): def ensure_demolocation(): """Ensure that demolocation exists - Creates both database directory and location if needed. + Creates database directory and location if needed. + Ensures the usable mapset for startup. - Returns the db, location name, and preferred mapset of the demolocation. + Returns the db, location name and usable mapset. """ grassdb = get_possible_database_path() + # If nothing found, try to create GRASS directory and copy startup loc if grassdb is None: grassdb = create_database_directory() location = "world_latlong_wgs84" if not is_location_valid(grassdb, location): create_startup_location_in_grassdb(grassdb, location) - return (grassdb, location, "PERMANENT") + return (grassdb, location) + + +def ensure_usable_mapset(grassdb, location): + """Ensure that usable mapset exists + + Finds the usable mapset. + It can create the new one named after user if needed. + """ + mapset_name = "PERMANENT" + mapset_path = os.path.join(grassdb, location, mapset_name) + index = 2 + while not can_start_in_mapset(mapset_path, ignore_lock=False): + if mapset_name == "PERMANENT": + mapset_name = get_default_mapset_name() + else: + mapset_name = get_default_mapset_name() + '_' + str(index) + index = index + 1 + if not mapset_exists(grassdb, location, mapset_name): + create_mapset(grassdb, location, mapset_name) + mapset_path = os.path.join(grassdb, location, mapset_name) + return mapset_name + diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 0b4fe01512a..06fbf9e8692 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -169,6 +169,29 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): return True +def get_reason_mapset_not_usable(mapset_path): + """It gets reasons when: + * Mapset is invalid. + * Mapset is owned by different user. + * Mapset is locked. + + Returns message as string if there was a reason, otherwise None. + """ + message = None + + # Check whether mapset is valid + if not is_mapset_valid(mapset_path): + message = _("invalid") + # Check whether mapset is owned by current user + elif not is_current_user_mapset_owner(mapset_path): + owner = get_mapset_owner(mapset_path) + message = _("owned by different user '{}'").format(owner) + # Check whether mapset is locked + elif is_mapset_locked(mapset_path): + message = _("locked") + return message + + def dir_contains_location(path): """Return True if directory *path* contains a valid location""" if not os.path.isdir(path): From 3b1f5c17c2556a5ed6e495a1d461a12959fbf3e6 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 24 Feb 2021 11:05:39 -0600 Subject: [PATCH 02/45] wxGUI: minor edits --- gui/wxpython/datacatalog/catalog.py | 1 - lib/init/grass.py | 1 - 2 files changed, 2 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index b1a013115f4..a62c05cbdcb 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -26,7 +26,6 @@ from datacatalog.infomanager import DataCatalogInfoManager from gui_core.wrap import Menu from gui_core.forms import GUI -from grass.script import gisenv from grass.pydispatch.signal import Signal diff --git a/lib/init/grass.py b/lib/init/grass.py index 381b9f55001..d80be7a5a61 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2455,7 +2455,6 @@ def main(): # Create the session grassrc file gisrc = create_gisrc(tmpdir, gisrcrc) - print(gisrc) ensure_home() # Set PATH, PYTHONPATH, ... From fa3adeb94b5638d20ded19dca7bad312ba7542d5 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 24 Feb 2021 11:16:34 -0600 Subject: [PATCH 03/45] flake8 --- gui/wxpython/datacatalog/catalog.py | 8 ++++---- gui/wxpython/datacatalog/infomanager.py | 1 + lib/init/grass.py | 6 +++--- python/grass/app/data.py | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index a62c05cbdcb..7de7da4cc74 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -72,7 +72,7 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, if grassrc['REASON'] == "invalid": if (grassrc['UNUSED_GISDBASE'] == os.getcwd() and grassrc['UNUSED_LOCATION_NAME'] == "" and - grassrc['UNUSED_MAPSET'] == ""): + grassrc['UNUSED_MAPSET'] == ""): # show data structure infobar for first-time user wx.CallLater(2000, self.showDataStructureInfo) else: @@ -159,9 +159,9 @@ def OnDownloadLocation(self, event): def OnSwitchMapset(self, event): """Switch to given mapset""" grassrc = read_gisrc() - grassdb=grassrc['UNUSED_GISDBASE'] - location=grassrc['UNUSED_LOCATION_NAME'] - mapset=grassrc['UNUSED_MAPSET'] + grassdb = grassrc['UNUSED_GISDBASE'] + location = grassrc['UNUSED_LOCATION_NAME'] + mapset = grassrc['UNUSED_MAPSET'] self.tree.SwitchMapset(grassdb, location, mapset) event.Skip() diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index be26a582273..e0dd548a864 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -22,6 +22,7 @@ from grass.script import gisenv from startup.guiutils import read_gisrc + class DataCatalogInfoManager: """Manager for all things related to info bar in Data Catalog""" diff --git a/lib/init/grass.py b/lib/init/grass.py index d80be7a5a61..052686bfc03 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -845,7 +845,7 @@ def create_initial_gisrc(filename): UNUSED_LOCATION_NAME: None UNUSED_MAPSET: None REASON: None -""" +""" % os.getcwd() ) writefile(filename, s) @@ -2511,7 +2511,7 @@ def main(): mapset_settings = getMapsetSettings(gisrc) # Check if mapset from gisrc is usable last_mapset_usable = can_start_in_gisrc_mapset( - mapset_settings = mapset_settings, + mapset_settings=mapset_settings, ignore_lock=params.force_gislock_removal ) debug(f"last_mapset_usable: {last_mapset_usable}") @@ -2540,7 +2540,7 @@ def main(): reason=mapset_settings.reason ) else: - mapset_settings.reason=None + mapset_settings.reason = None # Write mapset info to gisrc file set_mapset_info_to_gisrc( gisrc=gisrc, diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 0f0eba83b8c..47f46474ad4 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -181,4 +181,3 @@ def ensure_usable_mapset(grassdb, location): create_mapset(grassdb, location, mapset_name) mapset_path = os.path.join(grassdb, location, mapset_name) return mapset_name - From 726c0167ea9ce3da6abc70b858cac2457dd20769 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 24 Feb 2021 11:28:56 -0600 Subject: [PATCH 04/45] black --- lib/init/grass.py | 58 ++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 052686bfc03..73b6ae4d599 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -602,20 +602,27 @@ def write_gisrc(kv, filename, append=False): f.close() -def set_mapset_info_to_gisrc(gisrc, grassdb, location, mapset, - unused_grassdb=None, unused_location=None, - unused_mapset=None, reason=None): +def set_mapset_info_to_gisrc( + gisrc, + grassdb, + location, + mapset, + unused_grassdb=None, + unused_location=None, + unused_mapset=None, + reason=None, +): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) else: kv = {} - kv['GISDBASE'] = grassdb - kv['LOCATION_NAME'] = location - kv['MAPSET'] = mapset - kv['UNUSED_GISDBASE'] = unused_grassdb - kv['UNUSED_LOCATION_NAME'] = unused_location - kv['UNUSED_MAPSET'] = unused_mapset - kv['REASON'] = reason + kv["GISDBASE"] = grassdb + kv["LOCATION_NAME"] = location + kv["MAPSET"] = mapset + kv["UNUSED_GISDBASE"] = unused_grassdb + kv["UNUSED_LOCATION_NAME"] = unused_location + kv["UNUSED_MAPSET"] = unused_mapset + kv["REASON"] = reason write_gisrc(kv, gisrc) @@ -1218,6 +1225,7 @@ def is_valid(self): def get_reason_mapset_not_usable(self): """Check if a mapset is usable for a new session""" from grass.grassdb.checks import get_reason_mapset_not_usable + self.reason = get_reason_mapset_not_usable(self._full_mapset) return self.reason @@ -1226,13 +1234,13 @@ def getMapsetSettings(gisrc): """Get the settings of Location and Mapset from the gisrc file""" mapset_settings = MapsetSettings() kv = read_gisrc(gisrc) - mapset_settings.gisdbase = kv.get('GISDBASE') - mapset_settings.location = kv.get('LOCATION_NAME') - mapset_settings.mapset = kv.get('MAPSET') - mapset_settings.unused_gisdbase = kv.get('UNUSED_GISDBASE') - mapset_settings.unused_location = kv.get('UNUSED_LOCATION_NAME') - mapset_settings.unused_mapset = kv.get('UNUSED_MAPSET') - mapset_settings.reason = kv.get('REASON') + mapset_settings.gisdbase = kv.get("GISDBASE") + mapset_settings.location = kv.get("LOCATION_NAME") + mapset_settings.mapset = kv.get("MAPSET") + mapset_settings.unused_gisdbase = kv.get("UNUSED_GISDBASE") + mapset_settings.unused_location = kv.get("UNUSED_LOCATION_NAME") + mapset_settings.unused_mapset = kv.get("UNUSED_MAPSET") + mapset_settings.reason = kv.get("REASON") if not mapset_settings.is_valid(): return None return mapset_settings @@ -1268,6 +1276,7 @@ def load_gisrc(gisrc, gisrcrc): def can_start_in_gisrc_mapset(mapset_settings, ignore_lock=False): """Check if a mapset from a gisrc file is usable for a new session""" from grass.grassdb.checks import can_start_in_mapset + return can_start_in_mapset( mapset_path=mapset_settings.full_mapset, ignore_lock=ignore_lock ) @@ -1731,9 +1740,7 @@ def script_path(batch_job): script_in_addon_path = None if "GRASS_ADDON_BASE" in os.environ: script_in_addon_path = os.path.join( - os.environ["GRASS_ADDON_BASE"], - "scripts", - batch_job[0], + os.environ["GRASS_ADDON_BASE"], "scripts", batch_job[0], ) if script_in_addon_path and os.path.exists(script_in_addon_path): batch_job[0] = script_in_addon_path @@ -1746,8 +1753,7 @@ def script_path(batch_job): proc = Popen(batch_job, shell=False, env=os.environ) except OSError as error: error_message = _("Execution of <{cmd}> failed:\n" "{error}").format( - cmd=batch_job_string, - error=error, + cmd=batch_job_string, error=error, ) # No such file or directory if error.errno == errno.ENOENT: @@ -2511,8 +2517,7 @@ def main(): mapset_settings = getMapsetSettings(gisrc) # Check if mapset from gisrc is usable last_mapset_usable = can_start_in_gisrc_mapset( - mapset_settings=mapset_settings, - ignore_lock=params.force_gislock_removal + mapset_settings=mapset_settings, ignore_lock=params.force_gislock_removal ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: @@ -2522,6 +2527,7 @@ def main(): # Ensure demolocation import grass.app as ga + grassdb, location = ga.ensure_demolocation() # Ensure usable mapset mapset = ga.ensure_usable_mapset(grassdb, location) @@ -2537,7 +2543,7 @@ def main(): unused_grassdb=mapset_settings.gisdbase, unused_location=mapset_settings.location, unused_mapset=mapset_settings.mapset, - reason=mapset_settings.reason + reason=mapset_settings.reason, ) else: mapset_settings.reason = None @@ -2546,7 +2552,7 @@ def main(): gisrc=gisrc, grassdb=mapset_settings.gisdbase, location=mapset_settings.location, - mapset=mapset_settings.mapset + mapset=mapset_settings.mapset, ) else: # Mapset was specified in command line parameters. From bb4587432daab71b5fde0cfb2649bf32d5244f5a Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Fri, 5 Mar 2021 07:40:33 -0600 Subject: [PATCH 05/45] wxGUI: variable reason removed from gisrc, only last_mapset_path is now noted in gisrc, and only is needed. --- gui/wxpython/datacatalog/catalog.py | 55 +++++++------ gui/wxpython/datacatalog/infomanager.py | 60 +++++++++----- gui/wxpython/datacatalog/tree.py | 6 +- gui/wxpython/startup/guiutils.py | 10 +++ lib/init/grass.py | 103 ++++++++++++------------ python/grass/app/data.py | 2 +- python/grass/grassdb/checks.py | 5 +- python/grass/grassdb/manage.py | 11 +++ 8 files changed, 152 insertions(+), 100 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 7de7da4cc74..64f5c9cc70c 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -29,8 +29,11 @@ from grass.pydispatch.signal import Signal -from grass.grassdb.checks import is_current_mapset_in_demolocation -from startup.guiutils import read_gisrc +from startup.guiutils import (read_gisrc, + is_nonstandard_startup, + is_first_time_user) +from grass.grassdb.checks import get_reason_mapset_not_usable +from grass.grassdb.manage import split_mapset_path class DataCatalog(wx.Panel): @@ -67,22 +70,23 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self._layout() # show infobar if applicable - if is_current_mapset_in_demolocation(): - grassrc = read_gisrc() - if grassrc['REASON'] == "invalid": - if (grassrc['UNUSED_GISDBASE'] == os.getcwd() and - grassrc['UNUSED_LOCATION_NAME'] == "" and - grassrc['UNUSED_MAPSET'] == ""): - # show data structure infobar for first-time user - wx.CallLater(2000, self.showDataStructureInfo) - else: - wx.CallLater(2000, self.showBasicDemolocationInfo) - elif "owned by different user" in grassrc['REASON']: - # show basic info - wx.CallLater(2000, self.showBasicDemolocationInfo) - elif grassrc['REASON'] == "locked": - # show info allowing to switch to locked mapset - wx.CallLater(2000, self.showLockedMapsetInfo) + if is_nonstandard_startup(): + if is_first_time_user(): + # show data structure infobar for first-time user + wx.CallLater(2000, self.showDataStructureInfo) + else: + # get reason why last used mapset is not usable + last_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + reason = get_reason_mapset_not_usable(last_mapset_path) + if reason == "invalid": + # show invalid mapset info + wx.CallLater(2000, self.showInvalidMapsetInfo) + elif reason == "owned by different user": + # show different mapset owner info + wx.CallLater(2000, self.showDifferentMapsetOwnerInfo) + elif reason == "locked": + # show info allowing to switch to locked mapset + wx.CallLater(2000, self.showLockedMapsetInfo) def _layout(self): """Do layout""" @@ -100,12 +104,15 @@ def _layout(self): def showDataStructureInfo(self): self.infoManager.ShowDataStructureInfo(self.OnCreateLocation) + def showInvalidMapsetInfo(self): + self.infoManager.ShowInvalidMapsetInfo() + + def showDifferentMapsetOwnerInfo(self): + self.infoManager.ShowDifferentMapsetOwnerInfo() + def showLockedMapsetInfo(self): self.infoManager.ShowLockedMapsetInfo(self.OnSwitchMapset) - def showBasicDemolocationInfo(self): - self.infoManager.ShowBasicDemolocationInfo() - def showImportDataInfo(self): self.infoManager.ShowImportDataInfo(self.OnImportOgrLayers, self.OnImportGdalLayers) @@ -158,10 +165,8 @@ def OnDownloadLocation(self, event): def OnSwitchMapset(self, event): """Switch to given mapset""" - grassrc = read_gisrc() - grassdb = grassrc['UNUSED_GISDBASE'] - location = grassrc['UNUSED_LOCATION_NAME'] - mapset = grassrc['UNUSED_MAPSET'] + last_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + grassdb, location, mapset = split_mapset_path(last_mapset_path) self.tree.SwitchMapset(grassdb, location, mapset) event.Skip() diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index e0dd548a864..56040c90216 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -21,6 +21,8 @@ from grass.script import gisenv from startup.guiutils import read_gisrc +from grass.grassdb.manage import split_mapset_path +from grass.grassdb.checks import get_mapset_owner class DataCatalogInfoManager: @@ -59,35 +61,53 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler ).format(loc=gisenv()['LOCATION_NAME']) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) + def ShowInvalidMapsetInfo(self): + """Show info when last used mapset is invalid""" + last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) + message = _( + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is invalid." + "GRASS GIS has started in the default Location {loc} which uses " + "WGS 84 (EPSG:4326). To continue, find or create usable mapset through " + "Data catalog below." + ).format(lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, + loc=gisenv()['LOCATION_NAME']) + self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) + + def ShowDifferentMapsetOwnerInfo(self): + """Show info when last used mapset is owned by different user""" + last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) + owner = get_mapset_owner(last_used_mapset_path) + message = _( + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is owned " + "by different user '{owner}'. GRASS GIS has started in the default Location " + "{loc} which uses WGS 84 (EPSG:4326). To continue, find or create " + "usable mapset through Data catalog below." + ).format(lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, + owner=owner, + loc=gisenv()['LOCATION_NAME']) + self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) + def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): """Show info when last used mapset is locked""" - grassrc = read_gisrc() + last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked." "GRASS GIS has started in the default Location {loc} which uses " "WGS 84 (EPSG:4326). To continue, set usable mapset through Data " - "Catalog below, or remove .gislock and switch to last usable mapset." - ).format(lastdb=grassrc['UNUSED_GISDBASE'], - lastloc=grassrc['UNUSED_LOCATION_NAME'], - lastmapset=grassrc['UNUSED_MAPSET'], + "Catalog below, or remove .gislock and switch to last used mapset." + ).format(lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, loc=gisenv()['LOCATION_NAME']) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) - def ShowBasicDemolocationInfo(self): - """Show info when last used mapset is invalid or owned by different user""" - grassrc = read_gisrc() - message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is {reason}." - "GRASS GIS has started in the default Location {loc} which uses " - "WGS 84 (EPSG:4326). To continue, find or create usable mapset through " - "Data catalog below." - ).format(lastdb=grassrc['UNUSED_GISDBASE'], - lastmapset=grassrc['UNUSED_MAPSET'], - lastloc=grassrc['UNUSED_LOCATION_NAME'], - reason=grassrc['REASON'], - loc=gisenv()['LOCATION_NAME']) - self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) - def _onLearnMore(self, event): self._giface.Help(entry="grass_database") diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index c2b7874713b..2762b9e1315 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -61,7 +61,9 @@ get_reason_mapset_not_removable, get_reasons_location_not_removable, get_mapset_name_invalid_reason, - get_location_name_invalid_reason + get_location_name_invalid_reason, + is_nonstandard_startup, + is_first_time_user ) from grass.grassdb.manage import ( rename_mapset, @@ -969,7 +971,7 @@ def CreateLocation(self, grassdb_node): action='new') # show data import infobar for first-time user with proper layout - if is_current_mapset_in_demolocation(): + if is_nonstandard_startup() and is_first_time_user(): self.showImportDataInfo.emit() # switch to PERMANENT mapset in newly created location diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index dd18330dd21..f8ea640d4ff 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -138,6 +138,16 @@ def read_gisrc(): return grassrc +def is_nonstandard_startup(): + return 'LAST_MAPSET_PATH' in read_gisrc().keys() + + +def is_first_time_user(): + return read_gisrc()['LAST_MAPSET_PATH'] == os.path.join(os.getcwd(), + "", + "") + + def GetVersion(): """Gets version and revision diff --git a/lib/init/grass.py b/lib/init/grass.py index 73b6ae4d599..69e9f78bd15 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -555,6 +555,11 @@ def create_gisrc(tmpdir, gisrcrc): # Copy the global grassrc file to the session grassrc file if s: writefile(gisrc, s) + + # remove last mapset path from gisrc if applicable + line_number = search_string_in_gisrc(gisrc, "LAST_MAPSET_PATH") + if line_number: + delete_line_from_file(gisrc, line_number) return gisrc @@ -593,6 +598,27 @@ def read_env_file(path): return kv +def delete_line_from_file(path, number): + """Delete line given by number from file (number 1 = first row)""" + with open(path, "r") as f: + lines = f.readlines() + del lines[number] + with open(path, "w") as f: + for line in lines: + f.write(line) + + +def search_string_in_gisrc(path, string_to_search): + """Search for line number of given string""" + line_number = 0 + with open(path, "r") as f: + for line in f: + if string_to_search in line: + return line_number + line_number += 1 + return None + + def write_gisrc(kv, filename, append=False): # use append=True to avoid a race condition between write_gisrc() and # grass_prompt() on startup (PR #548) @@ -602,16 +628,7 @@ def write_gisrc(kv, filename, append=False): f.close() -def set_mapset_info_to_gisrc( - gisrc, - grassdb, - location, - mapset, - unused_grassdb=None, - unused_location=None, - unused_mapset=None, - reason=None, -): +def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) else: @@ -619,10 +636,15 @@ def set_mapset_info_to_gisrc( kv["GISDBASE"] = grassdb kv["LOCATION_NAME"] = location kv["MAPSET"] = mapset - kv["UNUSED_GISDBASE"] = unused_grassdb - kv["UNUSED_LOCATION_NAME"] = unused_location - kv["UNUSED_MAPSET"] = unused_mapset - kv["REASON"] = reason + write_gisrc(kv, gisrc) + + +def set_last_mapset_to_gisrc(gisrc, last_mapset_path): + if os.access(gisrc, os.R_OK): + kv = read_gisrc(gisrc) + else: + kv = {} + kv["LAST_MAPSET_PATH"] = last_mapset_path write_gisrc(kv, gisrc) @@ -848,10 +870,6 @@ def create_initial_gisrc(filename): r"""GISDBASE: %s LOCATION_NAME: MAPSET: -UNUSED_GISDBASE: None -UNUSED_LOCATION_NAME: None -UNUSED_MAPSET: None -REASON: None """ % os.getcwd() ) @@ -1179,7 +1197,7 @@ def set_mapset( ) ) writefile(os.path.join(path, "WIND"), s) - set_mapset_info_to_gisrc(gisrc, gisdbase, location_name, mapset) + set_mapset_to_gisrc(gisrc, gisdbase, location_name, mapset) else: fatal( _( @@ -1203,10 +1221,6 @@ def __init__(self): self.location = None self.mapset = None self._full_mapset = None - self.unused_gisdbase = None - self.unused_location = None - self.unused_mapset = None - self.reason = None # TODO: perhaps full_mapset would be better as mapset_path # TODO: works only when set for the first time @@ -1222,13 +1236,6 @@ def full_mapset(self): def is_valid(self): return self.gisdbase and self.location and self.mapset - def get_reason_mapset_not_usable(self): - """Check if a mapset is usable for a new session""" - from grass.grassdb.checks import get_reason_mapset_not_usable - - self.reason = get_reason_mapset_not_usable(self._full_mapset) - return self.reason - def getMapsetSettings(gisrc): """Get the settings of Location and Mapset from the gisrc file""" @@ -1237,10 +1244,6 @@ def getMapsetSettings(gisrc): mapset_settings.gisdbase = kv.get("GISDBASE") mapset_settings.location = kv.get("LOCATION_NAME") mapset_settings.mapset = kv.get("MAPSET") - mapset_settings.unused_gisdbase = kv.get("UNUSED_GISDBASE") - mapset_settings.unused_location = kv.get("UNUSED_LOCATION_NAME") - mapset_settings.unused_mapset = kv.get("UNUSED_MAPSET") - mapset_settings.reason = kv.get("REASON") if not mapset_settings.is_valid(): return None return mapset_settings @@ -1740,7 +1743,9 @@ def script_path(batch_job): script_in_addon_path = None if "GRASS_ADDON_BASE" in os.environ: script_in_addon_path = os.path.join( - os.environ["GRASS_ADDON_BASE"], "scripts", batch_job[0], + os.environ["GRASS_ADDON_BASE"], + "scripts", + batch_job[0], ) if script_in_addon_path and os.path.exists(script_in_addon_path): batch_job[0] = script_in_addon_path @@ -1753,7 +1758,8 @@ def script_path(batch_job): proc = Popen(batch_job, shell=False, env=os.environ) except OSError as error: error_message = _("Execution of <{cmd}> failed:\n" "{error}").format( - cmd=batch_job_string, error=error, + cmd=batch_job_string, + error=error, ) # No such file or directory if error.errno == errno.ENOENT: @@ -2522,33 +2528,30 @@ def main(): debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: - # Find reason why mapset is not usable - mapset_settings.get_reason_mapset_not_usable() - # Ensure demolocation import grass.app as ga grassdb, location = ga.ensure_demolocation() + # Ensure usable mapset mapset = ga.ensure_usable_mapset(grassdb, location) if mapset is None: sys.exit("Failed to start GUI, GRASS GIS is not running.") # Write mapset info to gisrc file - set_mapset_info_to_gisrc( - gisrc=gisrc, - grassdb=grassdb, - location=location, - mapset=mapset, - unused_grassdb=mapset_settings.gisdbase, - unused_location=mapset_settings.location, - unused_mapset=mapset_settings.mapset, - reason=mapset_settings.reason, + set_mapset_to_gisrc( + gisrc=gisrc, grassdb=grassdb, location=location, mapset=mapset + ) + # Write last mapset path to gisrc file + last_mapset_path = os.path.join( + mapset_settings.gisdbase, + mapset_settings.location, + mapset_settings.mapset, ) + set_last_mapset_to_gisrc(gisrc=gisrc, last_mapset_path=last_mapset_path) else: - mapset_settings.reason = None # Write mapset info to gisrc file - set_mapset_info_to_gisrc( + set_mapset_to_gisrc( gisrc=gisrc, grassdb=mapset_settings.gisdbase, location=mapset_settings.location, diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 47f46474ad4..991c5f4bff8 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -170,7 +170,7 @@ def ensure_usable_mapset(grassdb, location): """ mapset_name = "PERMANENT" mapset_path = os.path.join(grassdb, location, mapset_name) - index = 2 + index = 1 while not can_start_in_mapset(mapset_path, ignore_lock=False): if mapset_name == "PERMANENT": mapset_name = get_default_mapset_name() diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 06fbf9e8692..342a26569fd 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -177,6 +177,8 @@ def get_reason_mapset_not_usable(mapset_path): Returns message as string if there was a reason, otherwise None. """ + if mapset_path is None: + return message = None # Check whether mapset is valid @@ -184,8 +186,7 @@ def get_reason_mapset_not_usable(mapset_path): message = _("invalid") # Check whether mapset is owned by current user elif not is_current_user_mapset_owner(mapset_path): - owner = get_mapset_owner(mapset_path) - message = _("owned by different user '{}'").format(owner) + message = _("owned by different user") # Check whether mapset is locked elif is_mapset_locked(mapset_path): message = _("locked") diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index 54dfc755711..8aebabf03e5 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -46,3 +46,14 @@ def rename_mapset(database, location, old_name, new_name): def rename_location(database, old_name, new_name): """Rename location from *old_name* to *new_name*""" os.rename(os.path.join(database, old_name), os.path.join(database, new_name)) + + +def split_mapset_path(mapset_path): + """Split mapset path to three part - grassdb, location, mapset""" + head_tail = os.path.split(mapset_path) + location_path = head_tail[0] + mapset = head_tail[1] + head_tail = os.path.split(location_path) + grassdb = head_tail[0] + location = head_tail[1] + return grassdb, location, mapset From d95011bc3847b09d7c1a4a9064bb68dd83c96a0e Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Fri, 5 Mar 2021 07:54:52 -0600 Subject: [PATCH 06/45] black --- python/grass/app/data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 991c5f4bff8..154f4afd611 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -17,8 +17,8 @@ import getpass import sys from shutil import copytree, ignore_patterns -from grass.grassdb.create import (create_mapset, get_default_mapset_name) -from grass.grassdb.checks import (mapset_exists, can_start_in_mapset) +from grass.grassdb.create import create_mapset, get_default_mapset_name +from grass.grassdb.checks import mapset_exists, can_start_in_mapset from grass.grassdb.checks import is_location_valid @@ -175,7 +175,7 @@ def ensure_usable_mapset(grassdb, location): if mapset_name == "PERMANENT": mapset_name = get_default_mapset_name() else: - mapset_name = get_default_mapset_name() + '_' + str(index) + mapset_name = get_default_mapset_name() + "_" + str(index) index = index + 1 if not mapset_exists(grassdb, location, mapset_name): create_mapset(grassdb, location, mapset_name) From 5f94aa4bff94e0c899a54fcf5231e68b9b7d71b2 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Fri, 5 Mar 2021 07:59:03 -0600 Subject: [PATCH 07/45] flake8 --- gui/wxpython/datacatalog/tree.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 2762b9e1315..cde963bb5bf 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -76,8 +76,7 @@ from grass.script import gisenv from grass.grassdb.data import map_exists from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, - is_different_mapset_owner, - is_current_mapset_in_demolocation) + is_different_mapset_owner) from grass.exceptions import CalledModuleError From 3959d55efaa5b77d462076381a47cc8aa5572e49 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Mon, 8 Mar 2021 10:24:21 -0600 Subject: [PATCH 08/45] Path to the default database is now configurable through RC file. --- lib/init/grass.py | 29 ++++++++++++++++++++----- python/grass/app/data.py | 46 ++++++++++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 69e9f78bd15..d0786e96261 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -639,6 +639,15 @@ def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): write_gisrc(kv, gisrc) +def set_default_gisdbase_to_gisrc(gisrc, default_gisdbase): + if os.access(gisrc, os.R_OK): + kv = read_gisrc(gisrc) + else: + kv = {} + kv["DEFAULT_GISDBASE"] = default_gisdbase + write_gisrc(kv, gisrc) + + def set_last_mapset_to_gisrc(gisrc, last_mapset_path): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) @@ -2528,19 +2537,27 @@ def main(): debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: - # Ensure demolocation + # Ensure default gisdbase import grass.app as ga + if "DEFAULT_GISDBASE" in read_gisrc(gisrc).keys(): + default_gisdbase = ga.ensure_default_gisdbase(read_gisrc(gisrc).get("DEFAULT_GISDBASE")) + else: + default_gisdbase = ga.ensure_default_gisdbase() - grassdb, location = ga.ensure_demolocation() + # Ensure default location + default_location = ga.ensure_default_location(default_gisdbase) # Ensure usable mapset - mapset = ga.ensure_usable_mapset(grassdb, location) + mapset = ga.ensure_usable_mapset(default_gisdbase, default_location) if mapset is None: sys.exit("Failed to start GUI, GRASS GIS is not running.") # Write mapset info to gisrc file set_mapset_to_gisrc( - gisrc=gisrc, grassdb=grassdb, location=location, mapset=mapset + gisrc=gisrc, + grassdb=default_gisdbase, + location=default_location, + mapset=mapset, ) # Write last mapset path to gisrc file last_mapset_path = os.path.join( @@ -2549,13 +2566,15 @@ def main(): mapset_settings.mapset, ) set_last_mapset_to_gisrc(gisrc=gisrc, last_mapset_path=last_mapset_path) + # Write default grass database to gisrc file + set_default_gisdbase_to_gisrc(gisrc=gisrc, default_gisdbase=default_gisdbase) else: # Write mapset info to gisrc file set_mapset_to_gisrc( gisrc=gisrc, grassdb=mapset_settings.gisdbase, location=mapset_settings.location, - mapset=mapset_settings.mapset, + mapset=mapset_settings.mapset ) else: # Mapset was specified in command line parameters. diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 154f4afd611..2c457d0d3cf 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -143,23 +143,41 @@ def create_startup_location_in_grassdb(grassdatabase, startup_location_name): return False -def ensure_demolocation(): - """Ensure that demolocation exists +def ensure_default_gisdbase(default_gisdbase=None): + """Ensure that default gisdbase exists + Creates database directory either based on default gisdbase obtained from + gisrc file or on the default path determined according to OS. + + Returns the db""" + + if default_gisdbase: + if not os.path.exists(default_gisdbase): + try: + os.mkdir(default_gisdbase) + return default_gisdbase + except OSError: + pass + return default_gisdbase + else: + default_gisdbase = get_possible_database_path() + # If nothing found, try to create GRASS directory + if not default_gisdbase: + default_gisdbase = create_database_directory() + return default_gisdbase + - Creates database directory and location if needed. - Ensures the usable mapset for startup. +def ensure_default_location(default_gisdbase): + """Ensure that default location exists + Creates location if needed. - Returns the db, location name and usable mapset. + Returns the db and location name. """ - grassdb = get_possible_database_path() - - # If nothing found, try to create GRASS directory and copy startup loc - if grassdb is None: - grassdb = create_database_directory() - location = "world_latlong_wgs84" - if not is_location_valid(grassdb, location): - create_startup_location_in_grassdb(grassdb, location) - return (grassdb, location) + + default_location = "world_latlong_wgs84" + if not is_location_valid(default_gisdbase, default_location): + # If not valid, copy startup loc + create_startup_location_in_grassdb(default_gisdbase, default_location) + return default_location def ensure_usable_mapset(grassdb, location): From 1d50ec9f28379adbd5a60611cfe5ed6f0305a944 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Mon, 8 Mar 2021 10:28:10 -0600 Subject: [PATCH 09/45] black --- lib/init/grass.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index d0786e96261..e6e3197e5f3 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2539,8 +2539,11 @@ def main(): # Ensure default gisdbase import grass.app as ga + if "DEFAULT_GISDBASE" in read_gisrc(gisrc).keys(): - default_gisdbase = ga.ensure_default_gisdbase(read_gisrc(gisrc).get("DEFAULT_GISDBASE")) + default_gisdbase = ga.ensure_default_gisdbase( + read_gisrc(gisrc).get("DEFAULT_GISDBASE") + ) else: default_gisdbase = ga.ensure_default_gisdbase() @@ -2567,14 +2570,16 @@ def main(): ) set_last_mapset_to_gisrc(gisrc=gisrc, last_mapset_path=last_mapset_path) # Write default grass database to gisrc file - set_default_gisdbase_to_gisrc(gisrc=gisrc, default_gisdbase=default_gisdbase) + set_default_gisdbase_to_gisrc( + gisrc=gisrc, default_gisdbase=default_gisdbase + ) else: # Write mapset info to gisrc file set_mapset_to_gisrc( gisrc=gisrc, grassdb=mapset_settings.gisdbase, location=mapset_settings.location, - mapset=mapset_settings.mapset + mapset=mapset_settings.mapset, ) else: # Mapset was specified in command line parameters. From 276f4e483befb274f65798afc507e7ee2a111eb7 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Sun, 14 Mar 2021 03:30:45 -0500 Subject: [PATCH 10/45] wxGUI: first time user and nonstandard startup is now strictly separated. --- gui/wxpython/datacatalog/catalog.py | 56 ++++----- gui/wxpython/datacatalog/infomanager.py | 70 ++++++----- gui/wxpython/datacatalog/tree.py | 5 +- gui/wxpython/lmgr/frame.py | 6 +- gui/wxpython/startup/guiutils.py | 20 ++- lib/init/grass.py | 158 ++++++++++++++---------- python/grass/app/data.py | 66 +++------- python/grass/grassdb/checks.py | 7 +- 8 files changed, 196 insertions(+), 192 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 64f5c9cc70c..42ca523cc89 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -30,8 +30,8 @@ from grass.pydispatch.signal import Signal from startup.guiutils import (read_gisrc, - is_nonstandard_startup, - is_first_time_user) + nonstandard_startup, + first_time_user) from grass.grassdb.checks import get_reason_mapset_not_usable from grass.grassdb.manage import split_mapset_path @@ -65,28 +65,28 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.infoManager = DataCatalogInfoManager(infobar=self.infoBar, giface=self.giface) self.tree.showImportDataInfo.connect(self.showImportDataInfo) - # some layout self._layout() - # show infobar if applicable - if is_nonstandard_startup(): - if is_first_time_user(): - # show data structure infobar for first-time user - wx.CallLater(2000, self.showDataStructureInfo) - else: - # get reason why last used mapset is not usable - last_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] - reason = get_reason_mapset_not_usable(last_mapset_path) - if reason == "invalid": - # show invalid mapset info - wx.CallLater(2000, self.showInvalidMapsetInfo) - elif reason == "owned by different user": - # show different mapset owner info - wx.CallLater(2000, self.showDifferentMapsetOwnerInfo) - elif reason == "locked": - # show info allowing to switch to locked mapset - wx.CallLater(2000, self.showLockedMapsetInfo) + # show infobar for first-time user if applicable + if first_time_user(): + # show data structure infobar for first-time user + wx.CallLater(2500, self.showDataStructureInfo) + + # show infobar if last used mapset is not usable + if nonstandard_startup(): + # get reason why last used mapset is not usable + last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] + reason = get_reason_mapset_not_usable(last_mapset_path) + if reason == "invalid": + # show invalid mapset info + wx.CallLater(2000, self.infoManager.ShowInvalidMapsetInfo) + elif reason == "owned by different user": + # show different mapset owner info + wx.CallLater(2000, self.infoManager.ShowDifferentMapsetOwnerInfo) + elif reason == "locked": + # show info allowing to switch to locked mapset + wx.CallLater(2000, self.showLockedMapsetInfo) def _layout(self): """Do layout""" @@ -104,14 +104,8 @@ def _layout(self): def showDataStructureInfo(self): self.infoManager.ShowDataStructureInfo(self.OnCreateLocation) - def showInvalidMapsetInfo(self): - self.infoManager.ShowInvalidMapsetInfo() - - def showDifferentMapsetOwnerInfo(self): - self.infoManager.ShowDifferentMapsetOwnerInfo() - def showLockedMapsetInfo(self): - self.infoManager.ShowLockedMapsetInfo(self.OnSwitchMapset) + self.infoManager.ShowLockedMapsetInfo(self.OnSwitchToLastUsedMapset) def showImportDataInfo(self): self.infoManager.ShowImportDataInfo(self.OnImportOgrLayers, self.OnImportGdalLayers) @@ -163,9 +157,9 @@ def OnDownloadLocation(self, event): db_node, loc_node, mapset_node = self.tree.GetCurrentDbLocationMapsetNode() self.tree.DownloadLocation(db_node) - def OnSwitchMapset(self, event): - """Switch to given mapset""" - last_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + def OnSwitchToLastUsedMapset(self, event): + """Switch to last used mapset""" + last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] grassdb, location, mapset = split_mapset_path(last_mapset_path) self.tree.SwitchMapset(grassdb, location, mapset) event.Skip() diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index 56040c90216..b76c12bb449 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -34,8 +34,10 @@ def __init__(self, infobar, giface): def ShowDataStructureInfo(self, onCreateLocationHandler): """Show info about the data hierarchy focused on the first-time user""" - buttons = [("Create new Location", onCreateLocationHandler), - ("Learn More", self._onLearnMore)] + buttons = [ + ("Create new Location", onCreateLocationHandler), + ("Learn More", self._onLearnMore), + ] message = _( "GRASS GIS helps you organize your data using Locations (projects) " "which contain Mapsets (subprojects). All data in one Location is " @@ -44,13 +46,15 @@ def ShowDataStructureInfo(self, onCreateLocationHandler): "which uses WGS 84 (EPSG:4326). Consider creating a new Location with a CRS " "specific to your area. You can do it now or anytime later from " "the toolbar above." - ).format(loc=gisenv()['LOCATION_NAME']) + ).format(loc=gisenv()["LOCATION_NAME"]) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler): """Show info about the data import focused on the first-time user""" - buttons = [("Import vector data", OnImportOgrLayersHandler), - ("Import raster data", OnImportGdalLayersHandler)] + buttons = [ + ("Import vector data", OnImportOgrLayersHandler), + ("Import raster data", OnImportGdalLayersHandler), + ] message = _( "You have successfully created a new Location {loc}. " "Currently you are in its PERMANENT Mapset which is used for " @@ -58,55 +62,61 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler "Mapsets. You can create new Mapsets for different tasks by right " "clicking on the Location name.\n\n" "To import data, go to the toolbar above or use the buttons below." - ).format(loc=gisenv()['LOCATION_NAME']) + ).format(loc=gisenv()["LOCATION_NAME"]) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) def ShowInvalidMapsetInfo(self): """Show info when last used mapset is invalid""" - last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) message = _( "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is invalid." - "GRASS GIS has started in the default Location {loc} which uses " - "WGS 84 (EPSG:4326). To continue, find or create usable mapset through " + "GRASS GIS has started in the temporary Location {loc}. " + "To continue, find or create usable location through " "Data catalog below." - ).format(lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, - loc=gisenv()['LOCATION_NAME']) + ).format( + lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, + loc=gisenv()["LOCATION_NAME"], + ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) def ShowDifferentMapsetOwnerInfo(self): """Show info when last used mapset is owned by different user""" - last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) owner = get_mapset_owner(last_used_mapset_path) message = _( "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is owned " - "by different user '{owner}'. GRASS GIS has started in the default Location " - "{loc} which uses WGS 84 (EPSG:4326). To continue, find or create " - "usable mapset through Data catalog below." - ).format(lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, - owner=owner, - loc=gisenv()['LOCATION_NAME']) + "by different user '{owner}'. GRASS GIS has started in the temporary " + "Location {loc}. To continue, find or create usable location through " + "Data catalog below." + ).format( + lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, + owner=owner, + loc=gisenv()["LOCATION_NAME"], + ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): """Show info when last used mapset is locked""" - last_used_mapset_path = read_gisrc()['LAST_MAPSET_PATH'] + last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked." - "GRASS GIS has started in the default Location {loc} which uses " - "WGS 84 (EPSG:4326). To continue, set usable mapset through Data " - "Catalog below, or remove .gislock and switch to last used mapset." - ).format(lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, - loc=gisenv()['LOCATION_NAME']) + "GRASS GIS has started in the temporary Location {loc}. " + "To continue, find or create usable location through " + "Data Catalog below, or remove .gislock and switch to last used mapset." + ).format( + lastdb=lastdb, + lastloc=lastloc, + lastmapset=lastmapset, + loc=gisenv()["LOCATION_NAME"], + ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) def _onLearnMore(self, event): diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index cde963bb5bf..080971568e7 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -62,8 +62,7 @@ get_reasons_location_not_removable, get_mapset_name_invalid_reason, get_location_name_invalid_reason, - is_nonstandard_startup, - is_first_time_user + first_time_user ) from grass.grassdb.manage import ( rename_mapset, @@ -970,7 +969,7 @@ def CreateLocation(self, grassdb_node): action='new') # show data import infobar for first-time user with proper layout - if is_nonstandard_startup() and is_first_time_user(): + if first_time_user(): self.showImportDataInfo.emit() # switch to PERMANENT mapset in newly created location diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index cb6533fd99a..24bae782c7c 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -68,8 +68,8 @@ from datacatalog.catalog import DataCatalog from gui_core.forms import GUI from gui_core.wrap import Menu, TextEntryDialog -from grass.grassdb.checks import is_current_mapset_in_demolocation from startup.guiutils import ( + first_time_user, switch_mapset_interactively, create_mapset_interactively, create_location_interactively @@ -456,9 +456,9 @@ def show_demo(): lchecked=True, lcmd=["d.vect", "map={}".format(layer_name)], ) - if is_current_mapset_in_demolocation(): + if first_time_user(): # Show only after everything is initialized for proper map alignment. - wx.CallLater(1000, show_demo) + wx.CallLater(1500, show_demo) def AddNvizTools(self, firstTime): """Add nviz notebook page diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index f8ea640d4ff..e41c09ff485 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -22,6 +22,8 @@ from grass.grassdb.checks import ( is_mapset_locked, get_mapset_lock_info, + is_current_mapset_in_default_location, + is_mapset_current, is_mapset_name_valid, is_location_name_valid, get_mapset_name_invalid_reason, @@ -138,14 +140,20 @@ def read_gisrc(): return grassrc -def is_nonstandard_startup(): - return 'LAST_MAPSET_PATH' in read_gisrc().keys() +def nonstandard_startup(): + if 'LAST_MAPSET_PATH' in read_gisrc().keys(): + return is_mapset_current(os.environ["TMPDIR"], "tmploc", "PERMANENT") + return False -def is_first_time_user(): - return read_gisrc()['LAST_MAPSET_PATH'] == os.path.join(os.getcwd(), - "", - "") +def first_time_user(): + if "LAST_MAPSET_PATH" in read_gisrc().keys(): + if is_current_mapset_in_default_location: + initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( + os.getcwd(), "", "" + ) + return initial_gisrc + return False def GetVersion(): diff --git a/lib/init/grass.py b/lib/init/grass.py index e6e3197e5f3..2325279118e 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -229,6 +229,25 @@ def writefile(path, s): f.close() +def readlines(path, skipped_parameter=None): + debug("Reading %s" % path) + number = 0 + with open(path, "r") as f: + lines = f.readlines() + for line in lines: + if skipped_parameter in line: + del lines[number] + number += 1 + return lines + + +def writelines(path, lines): + debug("Writing %s" % path) + with open(path, "w") as f: + for line in lines: + f.write(line) + + def call(cmd, **kwargs): """Wrapper for subprocess.call to deal with platform-specific issues""" if WINDOWS: @@ -556,10 +575,6 @@ def create_gisrc(tmpdir, gisrcrc): if s: writefile(gisrc, s) - # remove last mapset path from gisrc if applicable - line_number = search_string_in_gisrc(gisrc, "LAST_MAPSET_PATH") - if line_number: - delete_line_from_file(gisrc, line_number) return gisrc @@ -598,27 +613,6 @@ def read_env_file(path): return kv -def delete_line_from_file(path, number): - """Delete line given by number from file (number 1 = first row)""" - with open(path, "r") as f: - lines = f.readlines() - del lines[number] - with open(path, "w") as f: - for line in lines: - f.write(line) - - -def search_string_in_gisrc(path, string_to_search): - """Search for line number of given string""" - line_number = 0 - with open(path, "r") as f: - for line in f: - if string_to_search in line: - return line_number - line_number += 1 - return None - - def write_gisrc(kv, filename, append=False): # use append=True to avoid a race condition between write_gisrc() and # grass_prompt() on startup (PR #548) @@ -639,15 +633,6 @@ def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): write_gisrc(kv, gisrc) -def set_default_gisdbase_to_gisrc(gisrc, default_gisdbase): - if os.access(gisrc, os.R_OK): - kv = read_gisrc(gisrc) - else: - kv = {} - kv["DEFAULT_GISDBASE"] = default_gisdbase - write_gisrc(kv, gisrc) - - def set_last_mapset_to_gisrc(gisrc, last_mapset_path): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) @@ -885,6 +870,15 @@ def create_initial_gisrc(filename): writefile(filename, s) +def first_time_user(mapset_settings): + # Returns true if we are working with initial GISRC + return ( + mapset_settings.gisdbase == os.getcwd() + and mapset_settings.location == "" + and mapset_settings.mapset == "" + ) + + def check_gui(expected_gui): grass_gui = expected_gui # Check if we are running X windows by checking the DISPLAY variable @@ -2536,43 +2530,69 @@ def main(): ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: - - # Ensure default gisdbase import grass.app as ga + from grass.grassdb.checks import can_start_in_mapset - if "DEFAULT_GISDBASE" in read_gisrc(gisrc).keys(): - default_gisdbase = ga.ensure_default_gisdbase( - read_gisrc(gisrc).get("DEFAULT_GISDBASE") + # Set last used mapset to gisrc + set_last_mapset_to_gisrc( + gisrc, + os.path.join( + mapset_settings.gisdbase, + mapset_settings.location, + mapset_settings.mapset, + ), + ) + if first_time_user(mapset_settings): + # Ensure default data hiearchy + ( + default_gisdbase, + default_location, + default_mapset, + ) = ga.ensure_default_data_hierarchy() + + if default_mapset is None: + sys.exit("Failed to start GUI, GRASS GIS is not running.") + + default_mapset_path = os.path.join( + default_gisdbase, + default_location, + default_mapset, ) + # First session + if can_start_in_mapset( + mapset_path=default_mapset_path, ignore_lock=False + ): + # Write mapset info to gisrc file + set_mapset_to_gisrc( + gisrc=gisrc, + grassdb=default_gisdbase, + location=default_location, + mapset=default_mapset, + ) + # Second session without closing the first one + else: + # Set default path to gisrc + set_last_mapset_to_gisrc(gisrc, default_mapset_path) + + # Create temporary location + params.tmp_location = True + set_mapset( + gisrc=gisrc, + geofile="XY", + create_new=True, + tmp_location=params.tmp_location, + tmpdir=tmpdir, + ) else: - default_gisdbase = ga.ensure_default_gisdbase() - - # Ensure default location - default_location = ga.ensure_default_location(default_gisdbase) - - # Ensure usable mapset - mapset = ga.ensure_usable_mapset(default_gisdbase, default_location) - if mapset is None: - sys.exit("Failed to start GUI, GRASS GIS is not running.") - - # Write mapset info to gisrc file - set_mapset_to_gisrc( - gisrc=gisrc, - grassdb=default_gisdbase, - location=default_location, - mapset=mapset, - ) - # Write last mapset path to gisrc file - last_mapset_path = os.path.join( - mapset_settings.gisdbase, - mapset_settings.location, - mapset_settings.mapset, - ) - set_last_mapset_to_gisrc(gisrc=gisrc, last_mapset_path=last_mapset_path) - # Write default grass database to gisrc file - set_default_gisdbase_to_gisrc( - gisrc=gisrc, default_gisdbase=default_gisdbase - ) + # Create temporary location + params.tmp_location = True + set_mapset( + gisrc=gisrc, + geofile="XY", + create_new=True, + tmp_location=params.tmp_location, + tmpdir=tmpdir, + ) else: # Write mapset info to gisrc file set_mapset_to_gisrc( @@ -2708,7 +2728,9 @@ def main(): # here we are at the end of grass session clean_all() if not params.tmp_location: - writefile(gisrcrc, readfile(gisrc)) + writelines( + gisrcrc, readlines(path=gisrc, skipped_parameter="LAST_MAPSET_PATH") + ) # After this point no more grass modules may be called # done message at last: no atexit.register() # or register done_message() diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 2c457d0d3cf..1c7513a799b 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -17,8 +17,8 @@ import getpass import sys from shutil import copytree, ignore_patterns -from grass.grassdb.create import create_mapset, get_default_mapset_name -from grass.grassdb.checks import mapset_exists, can_start_in_mapset +from grass.grassdb.create import create_mapset +from grass.grassdb.checks import mapset_exists from grass.grassdb.checks import is_location_valid @@ -143,59 +143,27 @@ def create_startup_location_in_grassdb(grassdatabase, startup_location_name): return False -def ensure_default_gisdbase(default_gisdbase=None): - """Ensure that default gisdbase exists - Creates database directory either based on default gisdbase obtained from - gisrc file or on the default path determined according to OS. +def ensure_default_data_hierarchy(): + """Ensure that default gisdbase, location and mapset exist. + Creates database directory based on the default path determined + according to OS if needed. Creates location if needed. + Ensure the default mapset and can create the new one if needed. - Returns the db""" + Returns the db, loc, mapset""" - if default_gisdbase: - if not os.path.exists(default_gisdbase): - try: - os.mkdir(default_gisdbase) - return default_gisdbase - except OSError: - pass - return default_gisdbase - else: - default_gisdbase = get_possible_database_path() - # If nothing found, try to create GRASS directory - if not default_gisdbase: - default_gisdbase = create_database_directory() - return default_gisdbase - - -def ensure_default_location(default_gisdbase): - """Ensure that default location exists - Creates location if needed. + default_gisdbase = get_possible_database_path() + default_location = "world_latlong_wgs84" + default_mapset = "PERMANENT" - Returns the db and location name. - """ + # If nothing found, try to create GRASS directory + if not default_gisdbase: + default_gisdbase = create_database_directory() - default_location = "world_latlong_wgs84" if not is_location_valid(default_gisdbase, default_location): # If not valid, copy startup loc create_startup_location_in_grassdb(default_gisdbase, default_location) - return default_location + if not mapset_exists(default_gisdbase, default_location, default_mapset): + create_mapset(default_gisdbase, default_location, default_mapset) -def ensure_usable_mapset(grassdb, location): - """Ensure that usable mapset exists - - Finds the usable mapset. - It can create the new one named after user if needed. - """ - mapset_name = "PERMANENT" - mapset_path = os.path.join(grassdb, location, mapset_name) - index = 1 - while not can_start_in_mapset(mapset_path, ignore_lock=False): - if mapset_name == "PERMANENT": - mapset_name = get_default_mapset_name() - else: - mapset_name = get_default_mapset_name() + "_" + str(index) - index = index + 1 - if not mapset_exists(grassdb, location, mapset_name): - create_mapset(grassdb, location, mapset_name) - mapset_path = os.path.join(grassdb, location, mapset_name) - return mapset_name + return default_gisdbase, default_location, default_mapset diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 342a26569fd..bd60bab8a84 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -115,8 +115,11 @@ def get_mapset_owner(mapset_path): return None -def is_current_mapset_in_demolocation(): - return gisenv()["LOCATION_NAME"] == "world_latlong_wgs84" +def is_current_mapset_in_default_location(): + return ( + gisenv()["LOCATION_NAME"] == "world_latlong_wgs84" + and gisenv()["MAPSET"] == "PERMANENT" + ) def is_mapset_locked(mapset_path): From 42688a26ab3f7d4c6e8f9df321f7d137914db301 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Sun, 14 Mar 2021 05:18:42 -0500 Subject: [PATCH 11/45] some smaller edits, simplifying, saving last used mapset when switched from temporary location --- gui/wxpython/lmgr/frame.py | 2 +- gui/wxpython/startup/guiutils.py | 19 +++++++++++++------ lib/init/grass.py | 9 +++++++-- python/grass/grassdb/checks.py | 1 + python/grass/grassdb/manage.py | 3 +-- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 24bae782c7c..b3178ddeea4 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -458,7 +458,7 @@ def show_demo(): ) if first_time_user(): # Show only after everything is initialized for proper map alignment. - wx.CallLater(1500, show_demo) + wx.CallLater(1000, show_demo) def AddNvizTools(self, firstTime): """Add nviz notebook page diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index e41c09ff485..8bd69970d23 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -141,18 +141,25 @@ def read_gisrc(): def nonstandard_startup(): - if 'LAST_MAPSET_PATH' in read_gisrc().keys(): + """ + Check if a user encounters a nonstandard startup. + (Last mapset not usable and at the same time a user is in temporary location). + """ + if "LAST_MAPSET_PATH" in read_gisrc().keys(): return is_mapset_current(os.environ["TMPDIR"], "tmploc", "PERMANENT") return False def first_time_user(): + """ + Check if a user is a first-time user. + (User is in default location and gisrc file has initial settings.) + """ if "LAST_MAPSET_PATH" in read_gisrc().keys(): - if is_current_mapset_in_default_location: - initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), "", "" - ) - return initial_gisrc + initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( + os.getcwd(), "", "" + ) + return initial_gisrc and is_current_mapset_in_default_location() return False diff --git a/lib/init/grass.py b/lib/init/grass.py index 2325279118e..d5194cb834e 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -568,13 +568,15 @@ def create_gisrc(tmpdir, gisrcrc): # remove invalid GISRC file to avoid disturbing error messages: try: s = readfile(gisrcrc) + if "UNKNOWN" in s: + try_remove(gisrcrc) + s = None except: s = None # Copy the global grassrc file to the session grassrc file if s: writefile(gisrc, s) - return gisrc @@ -2727,7 +2729,10 @@ def main(): # here we are at the end of grass session clean_all() - if not params.tmp_location: + mapset_settings = load_gisrc(gisrc, gisrcrc=gisrcrc) + if not params.tmp_location or ( + params.tmp_location and mapset_settings.gisdbase != os.environ["TMPDIR"] + ): writelines( gisrcrc, readlines(path=gisrc, skipped_parameter="LAST_MAPSET_PATH") ) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index bd60bab8a84..890b75fe39f 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -116,6 +116,7 @@ def get_mapset_owner(mapset_path): def is_current_mapset_in_default_location(): + """Check if the mapset is in default location""" return ( gisenv()["LOCATION_NAME"] == "world_latlong_wgs84" and gisenv()["MAPSET"] == "PERMANENT" diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index 8aebabf03e5..5cd00bc7ffb 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -51,9 +51,8 @@ def rename_location(database, old_name, new_name): def split_mapset_path(mapset_path): """Split mapset path to three part - grassdb, location, mapset""" head_tail = os.path.split(mapset_path) - location_path = head_tail[0] mapset = head_tail[1] - head_tail = os.path.split(location_path) + head_tail = os.path.split(head_tail[0]) grassdb = head_tail[0] location = head_tail[1] return grassdb, location, mapset From 3079544aadce6f22a4fb5052e59f8b32797f34b4 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Sun, 14 Mar 2021 06:12:07 -0500 Subject: [PATCH 12/45] description edit --- lib/init/grass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index d5194cb834e..9d005507776 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2571,7 +2571,7 @@ def main(): location=default_location, mapset=default_mapset, ) - # Second session without closing the first one + # Another first-time session else: # Set default path to gisrc set_last_mapset_to_gisrc(gisrc, default_mapset_path) From b41468fc05f7a9332e57a6a59934c9609d68e0d4 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 25 Mar 2021 09:34:37 -0500 Subject: [PATCH 13/45] delay is the class attribute now --- gui/wxpython/datacatalog/catalog.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 42ca523cc89..5878462dcd4 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -46,11 +46,14 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.parent = parent self.baseTitle = title self.giface = giface + wx.Panel.__init__(self, parent=parent, id=id, **kwargs) self.SetName("DataCatalog") Debug.msg(1, "DataCatalog.__init__()") + delay = 2000 + # toolbar self.toolbar = DataCatalogToolbar(parent=self) @@ -65,13 +68,14 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.infoManager = DataCatalogInfoManager(infobar=self.infoBar, giface=self.giface) self.tree.showImportDataInfo.connect(self.showImportDataInfo) + # some layout self._layout() # show infobar for first-time user if applicable if first_time_user(): # show data structure infobar for first-time user - wx.CallLater(2500, self.showDataStructureInfo) + wx.CallLater(delay, self.showDataStructureInfo) # show infobar if last used mapset is not usable if nonstandard_startup(): @@ -80,13 +84,13 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, reason = get_reason_mapset_not_usable(last_mapset_path) if reason == "invalid": # show invalid mapset info - wx.CallLater(2000, self.infoManager.ShowInvalidMapsetInfo) + wx.CallLater(delay, self.infoManager.ShowInvalidMapsetInfo) elif reason == "owned by different user": # show different mapset owner info - wx.CallLater(2000, self.infoManager.ShowDifferentMapsetOwnerInfo) + wx.CallLater(delay, self.infoManager.ShowDifferentMapsetOwnerInfo) elif reason == "locked": # show info allowing to switch to locked mapset - wx.CallLater(2000, self.showLockedMapsetInfo) + wx.CallLater(delay, self.showLockedMapsetInfo) def _layout(self): """Do layout""" From b3add230907909a8e572618e50977f684fb3cdd5 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 25 Mar 2021 09:55:17 -0500 Subject: [PATCH 14/45] extra gap and black --- gui/wxpython/datacatalog/catalog.py | 1 - lib/init/grass.py | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 5878462dcd4..c0c5476d2d9 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -46,7 +46,6 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.parent = parent self.baseTitle = title self.giface = giface - wx.Panel.__init__(self, parent=parent, id=id, **kwargs) self.SetName("DataCatalog") diff --git a/lib/init/grass.py b/lib/init/grass.py index 9d005507776..bdddec36d08 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -874,10 +874,8 @@ def create_initial_gisrc(filename): def first_time_user(mapset_settings): # Returns true if we are working with initial GISRC - return ( - mapset_settings.gisdbase == os.getcwd() - and mapset_settings.location == "" - and mapset_settings.mapset == "" + return mapset_settings.full_mapset == os.path.join( + os.getcwd(), "", "" ) From 01fbea49f773d4164d822959ae671bfde4af23fb Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Mon, 29 Mar 2021 10:23:20 -0500 Subject: [PATCH 15/45] non_standard_startup and first_time_user moved to check.py. New file strings.py created. --- gui/wxpython/datacatalog/catalog.py | 20 +++--- gui/wxpython/datacatalog/infomanager.py | 18 +++--- gui/wxpython/datacatalog/tree.py | 17 ++--- gui/wxpython/lmgr/frame.py | 8 +-- gui/wxpython/startup/guiutils.py | 23 ------- python/grass/grassdb/Makefile | 2 +- python/grass/grassdb/checks.py | 83 +++++++++++++++++++++---- python/grass/grassdb/manage.py | 16 +++-- python/grass/grassdb/strings.py | 16 +++++ 9 files changed, 130 insertions(+), 73 deletions(-) create mode 100644 python/grass/grassdb/strings.py diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index c0c5476d2d9..fdb1edb9800 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -29,10 +29,10 @@ from grass.pydispatch.signal import Signal -from startup.guiutils import (read_gisrc, - nonstandard_startup, - first_time_user) -from grass.grassdb.checks import get_reason_mapset_not_usable +from grass.grassdb.checks import (read_gisrc, + get_reason_mapset_not_usable, + is_nonstandard_startup, + is_first_time_user) from grass.grassdb.manage import split_mapset_path @@ -72,22 +72,22 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self._layout() # show infobar for first-time user if applicable - if first_time_user(): + if is_first_time_user(): # show data structure infobar for first-time user wx.CallLater(delay, self.showDataStructureInfo) # show infobar if last used mapset is not usable - if nonstandard_startup(): + if is_nonstandard_startup(): # get reason why last used mapset is not usable last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - reason = get_reason_mapset_not_usable(last_mapset_path) - if reason == "invalid": + reason_id = get_reason_mapset_not_usable(last_mapset_path) + if reason_id == 1: # show invalid mapset info wx.CallLater(delay, self.infoManager.ShowInvalidMapsetInfo) - elif reason == "owned by different user": + elif reason_id == 2: # show different mapset owner info wx.CallLater(delay, self.infoManager.ShowDifferentMapsetOwnerInfo) - elif reason == "locked": + elif reason_id == 3: # show info allowing to switch to locked mapset wx.CallLater(delay, self.showLockedMapsetInfo) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index b76c12bb449..924856db551 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -66,13 +66,13 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) def ShowInvalidMapsetInfo(self): - """Show info when last used mapset is invalid""" + """Show info when last used mapset does not exist""" last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is invalid." - "GRASS GIS has started in the temporary Location {loc}. " - "To continue, find or create usable location through " + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' does not exist. " + "GRASS GIS has started in a temporary Location {loc}. " + "To continue, find or create another location through " "Data catalog below." ).format( lastdb=lastdb, @@ -89,8 +89,8 @@ def ShowDifferentMapsetOwnerInfo(self): owner = get_mapset_owner(last_used_mapset_path) message = _( "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is owned " - "by different user '{owner}'. GRASS GIS has started in the temporary " - "Location {loc}. To continue, find or create usable location through " + "by different user '{owner}'. GRASS GIS has started in a temporary " + "Location {loc}. To continue, find or create another location through " "Data catalog below." ).format( lastdb=lastdb, @@ -107,9 +107,9 @@ def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked." - "GRASS GIS has started in the temporary Location {loc}. " - "To continue, find or create usable location through " + "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked. " + "GRASS GIS has started in a temporary Location {loc}. " + "To continue, find or create another location through " "Data Catalog below, or remove .gislock and switch to last used mapset." ).format( lastdb=lastdb, diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 080971568e7..1a4513b5961 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -62,7 +62,6 @@ get_reasons_location_not_removable, get_mapset_name_invalid_reason, get_location_name_invalid_reason, - first_time_user ) from grass.grassdb.manage import ( rename_mapset, @@ -74,8 +73,10 @@ import grass.script as gscript from grass.script import gisenv from grass.grassdb.data import map_exists +from grass.grassdb.manage import delete_temporary_location from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, - is_different_mapset_owner) + is_different_mapset_owner, is_first_time_user, + is_nonstandard_startup) from grass.exceptions import CalledModuleError @@ -957,7 +958,7 @@ def CreateLocation(self, grassdb_node): """ Creates new location interactively and adds it to the tree and switch to its new PERMANENT mapset. - If a user was in Demolocation, it shows data import infobar. + If a user is a first-time user, it shows data import infobar. """ grassdatabase, location, mapset = ( create_location_interactively(self, grassdb_node.data['name']) @@ -968,14 +969,14 @@ def CreateLocation(self, grassdb_node): element='location', action='new') - # show data import infobar for first-time user with proper layout - if first_time_user(): - self.showImportDataInfo.emit() - # switch to PERMANENT mapset in newly created location self.SwitchMapset(grassdatabase, location, mapset, show_confirmation=True) + # show data import infobar for first-time user with proper layout + if is_first_time_user(): + self.showImportDataInfo.emit() + def OnCreateLocation(self, event): """Create new location""" self.CreateLocation(self.selected_grassdb[0]) @@ -1512,6 +1513,8 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): else: switch_mapset_interactively(self, self._giface, grassdb, location, mapset, show_confirmation) + if is_nonstandard_startup(): + delete_temporary_location() def OnSwitchMapset(self, event): """Switch to location and mapset""" diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index b3178ddeea4..53772e7b32d 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -42,9 +42,6 @@ from grass.script import core as grass from grass.script.utils import decode -from startup.guiutils import ( - can_switch_mapset_interactive -) from core.gcmd import RunCommand, GError, GMessage from core.settings import UserSettings, GetDisplayVectSettings @@ -69,11 +66,12 @@ from gui_core.forms import GUI from gui_core.wrap import Menu, TextEntryDialog from startup.guiutils import ( - first_time_user, + can_switch_mapset_interactive, switch_mapset_interactively, create_mapset_interactively, create_location_interactively ) +from grass.grassdb.checks import is_first_time_user class GMFrame(wx.Frame): @@ -456,7 +454,7 @@ def show_demo(): lchecked=True, lcmd=["d.vect", "map={}".format(layer_name)], ) - if first_time_user(): + if is_first_time_user(): # Show only after everything is initialized for proper map alignment. wx.CallLater(1000, show_demo) diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 8bd69970d23..44a223352ec 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -140,29 +140,6 @@ def read_gisrc(): return grassrc -def nonstandard_startup(): - """ - Check if a user encounters a nonstandard startup. - (Last mapset not usable and at the same time a user is in temporary location). - """ - if "LAST_MAPSET_PATH" in read_gisrc().keys(): - return is_mapset_current(os.environ["TMPDIR"], "tmploc", "PERMANENT") - return False - - -def first_time_user(): - """ - Check if a user is a first-time user. - (User is in default location and gisrc file has initial settings.) - """ - if "LAST_MAPSET_PATH" in read_gisrc().keys(): - initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), "", "" - ) - return initial_gisrc and is_current_mapset_in_default_location() - return False - - def GetVersion(): """Gets version and revision diff --git a/python/grass/grassdb/Makefile b/python/grass/grassdb/Makefile index 3b6fa9548c5..2f432879107 100644 --- a/python/grass/grassdb/Makefile +++ b/python/grass/grassdb/Makefile @@ -5,7 +5,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make DSTDIR = $(ETC)/python/grass/grassdb -MODULES = checks create data manage +MODULES = checks create data manage strings PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 890b75fe39f..d206e399acd 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -18,6 +18,39 @@ import grass.script as gs import glob +from grass.grassdb.strings import (default_location, temporary_location, + unknown_location, unknown_mapset) + + +def read_gisrc(): + """Read variables from a current GISRC file + + Returns a dictionary representation of the file content. + """ + grassrc = {} + + gisrc = os.getenv("GISRC") + + try: + rc = open(gisrc, "r") + except IOError: + return grassrc + + if gisrc and os.path.isfile(gisrc): + try: + rc = open(gisrc, "r") + for line in rc.readlines(): + try: + key, val = line.split(":", 1) + except ValueError as e: + sys.stderr.write( + _('Invalid line in GISRC file (%s):%s\n' % (e, line))) + grassrc[key.strip()] = val.strip() + finally: + rc.close() + + return grassrc + def mapset_exists(database, location, mapset): """Returns True whether mapset path exists.""" @@ -116,13 +149,39 @@ def get_mapset_owner(mapset_path): def is_current_mapset_in_default_location(): - """Check if the mapset is in default location""" + """Returns True if mapset is in a default location""" return ( - gisenv()["LOCATION_NAME"] == "world_latlong_wgs84" + gisenv()["LOCATION_NAME"] == default_location and gisenv()["MAPSET"] == "PERMANENT" ) +def is_nonstandard_startup(): + """ Checks if a user encounters a nonstandard startup. + + Returns True if a user encounters a nonstandard startup. + It occurs when a last mapset is not usable and at the same time + a user is in a temporary location. + """ + if "LAST_MAPSET_PATH" in read_gisrc().keys(): + return is_mapset_current(os.environ["TMPDIR"], temporary_location, "PERMANENT") + return False + + +def is_first_time_user(): + """ Check if a user is a first-time user. + + Returns True if a user is a first-time user. + It occurs when a gisrc file has initial settings. + """ + if "LAST_MAPSET_PATH" in read_gisrc().keys(): + initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( + os.getcwd(), unknown_location, unknown_mapset + ) + return initial_gisrc + return False + + def is_mapset_locked(mapset_path): """Check if the mapset is locked""" lock_name = ".gislock" @@ -174,27 +233,27 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): def get_reason_mapset_not_usable(mapset_path): - """It gets reasons when: - * Mapset is invalid. - * Mapset is owned by different user. - * Mapset is locked. + """It finds a reason why mapset is not usable. - Returns message as string if there was a reason, otherwise None. + Returns a reason id as number if there was a reason, otherwise None. + Returns 1 if mapset is invalid. + Returns 2 if mapset has a different owner. + Returns 3 if mapset is locked. """ if mapset_path is None: return - message = None + reason_id = None # Check whether mapset is valid if not is_mapset_valid(mapset_path): - message = _("invalid") + reason_id = 1 # Check whether mapset is owned by current user elif not is_current_user_mapset_owner(mapset_path): - message = _("owned by different user") + reason_id = 2 # Check whether mapset is locked elif is_mapset_locked(mapset_path): - message = _("locked") - return message + reason_id = 3 + return reason_id def dir_contains_location(path): diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index 5cd00bc7ffb..0ec1a5ec680 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -13,6 +13,8 @@ import os import shutil +from grass.grassdb.strings import temporary_location + def delete_mapset(database, location, mapset): """Deletes a specified mapset""" @@ -28,6 +30,11 @@ def delete_location(database, location): shutil.rmtree(os.path.join(database, location)) +def delete_temporary_location(): + """Deletes a temporary location""" + shutil.rmtree(os.path.join(os.environ["TMPDIR"], temporary_location)) + + def delete_grassdb(database): """Deletes a specified GRASS database""" shutil.rmtree(database) @@ -49,10 +56,7 @@ def rename_location(database, old_name, new_name): def split_mapset_path(mapset_path): - """Split mapset path to three part - grassdb, location, mapset""" - head_tail = os.path.split(mapset_path) - mapset = head_tail[1] - head_tail = os.path.split(head_tail[0]) - grassdb = head_tail[0] - location = head_tail[1] + """Split mapset path to three parts - grassdb, location, mapset""" + path, mapset = os.path.split(mapset_path) + grassdb, location = os.path.split(path) return grassdb, location, mapset diff --git a/python/grass/grassdb/strings.py b/python/grass/grassdb/strings.py new file mode 100644 index 00000000000..90971dd4d62 --- /dev/null +++ b/python/grass/grassdb/strings.py @@ -0,0 +1,16 @@ +""" +Set strings for objects in a GRASS GIS Spatial Database + +(C) 2020 by the GRASS Development Team +This program is free software under the GNU General Public +License (>=v2). Read the file COPYING that comes with GRASS +for details. + +.. sectionauthor:: Linda Kaldivova +""" + +# constant strings +default_location = "world_latlong_wgs84" +temporary_location = "tmploc" +unknown_location = "" +unknown_mapset = "" \ No newline at end of file From bc655f2a05f2fc7a41fe1b33993dfe5ece4404ac Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 02:12:18 -0500 Subject: [PATCH 16/45] new session file created, globalvars made as dictionary --- gui/wxpython/datacatalog/catalog.py | 6 ++-- gui/wxpython/datacatalog/infomanager.py | 2 +- gui/wxpython/startup/guiutils.py | 31 +---------------- python/grass/grassdb/Makefile | 2 +- python/grass/grassdb/checks.py | 41 +++-------------------- python/grass/grassdb/globals.py | 17 ++++++++++ python/grass/grassdb/session.py | 44 +++++++++++++++++++++++++ python/grass/grassdb/strings.py | 16 --------- 8 files changed, 72 insertions(+), 87 deletions(-) create mode 100644 python/grass/grassdb/globals.py create mode 100644 python/grass/grassdb/session.py delete mode 100644 python/grass/grassdb/strings.py diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index fdb1edb9800..0dc477b989f 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -29,11 +29,11 @@ from grass.pydispatch.signal import Signal -from grass.grassdb.checks import (read_gisrc, - get_reason_mapset_not_usable, +from grass.grassdb.session import read_gisrc +from grass.grassdb.manage import split_mapset_path +from grass.grassdb.checks import (get_reason_mapset_not_usable, is_nonstandard_startup, is_first_time_user) -from grass.grassdb.manage import split_mapset_path class DataCatalog(wx.Panel): diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index 924856db551..52006611ce8 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -20,7 +20,7 @@ import wx from grass.script import gisenv -from startup.guiutils import read_gisrc +from grass.grassdb.session import read_gisrc from grass.grassdb.manage import split_mapset_path from grass.grassdb.checks import get_mapset_owner diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 44a223352ec..62ee69ccc8d 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -16,14 +16,11 @@ import os -import sys import wx from grass.grassdb.checks import ( is_mapset_locked, get_mapset_lock_info, - is_current_mapset_in_default_location, - is_mapset_current, is_mapset_name_valid, is_location_name_valid, get_mapset_name_invalid_reason, @@ -47,7 +44,7 @@ from grass.script.utils import try_remove from core import globalvar -from core.gcmd import GError, GMessage, DecodeString, RunCommand +from core.gcmd import GError, GMessage, RunCommand from gui_core.dialogs import TextEntryDialog from location_wizard.dialogs import RegionDef from gui_core.widgets import GenericValidator @@ -114,32 +111,6 @@ def _isLocationNameValid(self, text): return is_location_name_valid(self.database, text) -# TODO: similar to (but not the same as) read_gisrc function in grass.py -def read_gisrc(): - """Read variables from a current GISRC file - - Returns a dictionary representation of the file content. - """ - grassrc = {} - - gisrc = os.getenv("GISRC") - - if gisrc and os.path.isfile(gisrc): - try: - rc = open(gisrc, "r") - for line in rc.readlines(): - try: - key, val = line.split(":", 1) - except ValueError as e: - sys.stderr.write( - _('Invalid line in GISRC file (%s):%s\n' % (e, line))) - grassrc[key.strip()] = DecodeString(val.strip()) - finally: - rc.close() - - return grassrc - - def GetVersion(): """Gets version and revision diff --git a/python/grass/grassdb/Makefile b/python/grass/grassdb/Makefile index 2f432879107..f95d584802c 100644 --- a/python/grass/grassdb/Makefile +++ b/python/grass/grassdb/Makefile @@ -5,7 +5,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make DSTDIR = $(ETC)/python/grass/grassdb -MODULES = checks create data manage strings +MODULES = checks create data manage globals session PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index d206e399acd..4ea6a1dc677 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -9,7 +9,6 @@ .. sectionauthor:: Vaclav Petras """ - import os import sys import datetime @@ -18,38 +17,8 @@ import grass.script as gs import glob -from grass.grassdb.strings import (default_location, temporary_location, - unknown_location, unknown_mapset) - - -def read_gisrc(): - """Read variables from a current GISRC file - - Returns a dictionary representation of the file content. - """ - grassrc = {} - - gisrc = os.getenv("GISRC") - - try: - rc = open(gisrc, "r") - except IOError: - return grassrc - - if gisrc and os.path.isfile(gisrc): - try: - rc = open(gisrc, "r") - for line in rc.readlines(): - try: - key, val = line.split(":", 1) - except ValueError as e: - sys.stderr.write( - _('Invalid line in GISRC file (%s):%s\n' % (e, line))) - grassrc[key.strip()] = val.strip() - finally: - rc.close() - - return grassrc +from grass.grassdb.globals import globalvars +from grass.grassdb.session import read_gisrc def mapset_exists(database, location, mapset): @@ -151,7 +120,7 @@ def get_mapset_owner(mapset_path): def is_current_mapset_in_default_location(): """Returns True if mapset is in a default location""" return ( - gisenv()["LOCATION_NAME"] == default_location + gisenv()["LOCATION_NAME"] == globalvars["DEFAULT_LOCATION"] and gisenv()["MAPSET"] == "PERMANENT" ) @@ -164,7 +133,7 @@ def is_nonstandard_startup(): a user is in a temporary location. """ if "LAST_MAPSET_PATH" in read_gisrc().keys(): - return is_mapset_current(os.environ["TMPDIR"], temporary_location, "PERMANENT") + return is_mapset_current(os.environ["TMPDIR"], globalvars["TEMPORARY_LOCATION"], "PERMANENT") return False @@ -176,7 +145,7 @@ def is_first_time_user(): """ if "LAST_MAPSET_PATH" in read_gisrc().keys(): initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), unknown_location, unknown_mapset + os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"] ) return initial_gisrc return False diff --git a/python/grass/grassdb/globals.py b/python/grass/grassdb/globals.py new file mode 100644 index 00000000000..9c169b4f57a --- /dev/null +++ b/python/grass/grassdb/globals.py @@ -0,0 +1,17 @@ +""" +Set global variables for objects in a GRASS GIS Spatial Database + +(C) 2020 by the GRASS Development Team +This program is free software under the GNU General Public +License (>=v2). Read the file COPYING that comes with GRASS +for details. + +.. sectionauthor:: Linda Kladivova +""" + +# global variables +globalvars = {} +globalvars["DEFAULT_LOCATION"] = "world_latlong_wgs84" +globalvars["TEMPORARY_LOCATION"] = "tmploc" +globalvars["UNKNOWN_LOCATION"] = "" +globalvars["UNKNOWN_MAPSET"] = "" diff --git a/python/grass/grassdb/session.py b/python/grass/grassdb/session.py new file mode 100644 index 00000000000..1b915c8c8d3 --- /dev/null +++ b/python/grass/grassdb/session.py @@ -0,0 +1,44 @@ +""" +Manage GRASS GIS session. + +(C) 2020 by the GRASS Development Team +This program is free software under the GNU General Public +License (>=v2). Read the file COPYING that comes with GRASS +for details. + +.. sectionauthor:: Linda Kladivova +""" + +import os +import sys + +### TODO move SetSessionMapset and GetVersion from guiutils here + +def read_gisrc(): + """Read variables from a current GISRC file + + Returns a dictionary representation of the file content. + """ + grassrc = {} + + gisrc = os.getenv("GISRC") + + try: + rc = open(gisrc, "r") + except IOError: + return grassrc + + if gisrc and os.path.isfile(gisrc): + try: + rc = open(gisrc, "r") + for line in rc.readlines(): + try: + key, val = line.split(":", 1) + except ValueError as e: + sys.stderr.write( + _('Invalid line in GISRC file (%s):%s\n' % (e, line))) + grassrc[key.strip()] = val.strip() + finally: + rc.close() + + return grassrc \ No newline at end of file diff --git a/python/grass/grassdb/strings.py b/python/grass/grassdb/strings.py deleted file mode 100644 index 90971dd4d62..00000000000 --- a/python/grass/grassdb/strings.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -Set strings for objects in a GRASS GIS Spatial Database - -(C) 2020 by the GRASS Development Team -This program is free software under the GNU General Public -License (>=v2). Read the file COPYING that comes with GRASS -for details. - -.. sectionauthor:: Linda Kaldivova -""" - -# constant strings -default_location = "world_latlong_wgs84" -temporary_location = "tmploc" -unknown_location = "" -unknown_mapset = "" \ No newline at end of file From 1dc932ec6c98a7d63609a6b2d5cf2388d23047f9 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 03:15:17 -0500 Subject: [PATCH 17/45] wxGUI: infomanager shortened and reason_id is now string variable --- gui/wxpython/datacatalog/catalog.py | 16 +++---- gui/wxpython/datacatalog/infomanager.py | 62 +++++++++++-------------- gui/wxpython/datacatalog/tree.py | 6 +-- python/grass/grassdb/checks.py | 16 +++---- 4 files changed, 46 insertions(+), 54 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 0dc477b989f..9f0a3d28bf6 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -80,14 +80,11 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, if is_nonstandard_startup(): # get reason why last used mapset is not usable last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - reason_id = get_reason_mapset_not_usable(last_mapset_path) - if reason_id == 1: - # show invalid mapset info - wx.CallLater(delay, self.infoManager.ShowInvalidMapsetInfo) - elif reason_id == 2: - # show different mapset owner info - wx.CallLater(delay, self.infoManager.ShowDifferentMapsetOwnerInfo) - elif reason_id == 3: + self.reason_id = get_reason_mapset_not_usable(last_mapset_path) + if self.reason_id == "non-existent" or self.reason_id == "invalid" or self.reason_id == "different-owner": + # show non-standard situation info + wx.CallLater(delay, self.showNonStandardSituationInfo) + elif self.reason_id == "locked": # show info allowing to switch to locked mapset wx.CallLater(delay, self.showLockedMapsetInfo) @@ -110,6 +107,9 @@ def showDataStructureInfo(self): def showLockedMapsetInfo(self): self.infoManager.ShowLockedMapsetInfo(self.OnSwitchToLastUsedMapset) + def showNonStandardSituationInfo(self): + self.infoManager.ShowNonStandardSituationInfo(self.reason_id) + def showImportDataInfo(self): self.infoManager.ShowImportDataInfo(self.OnImportOgrLayers, self.OnImportGdalLayers) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index 52006611ce8..de3fd8312ec 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -21,7 +21,6 @@ from grass.script import gisenv from grass.grassdb.session import read_gisrc -from grass.grassdb.manage import split_mapset_path from grass.grassdb.checks import get_mapset_owner @@ -65,38 +64,15 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler ).format(loc=gisenv()["LOCATION_NAME"]) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) - def ShowInvalidMapsetInfo(self): - """Show info when last used mapset does not exist""" - last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) + def ShowNonStandardSituationInfo(self, reason_id): + """Show info when last used mapset is not usable""" + string = self._getString(reason_id) message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' does not exist. " - "GRASS GIS has started in a temporary Location {loc}. " + "{string}. GRASS GIS has started in a temporary Location {loc}. " "To continue, find or create another location through " - "Data catalog below." + "Data Catalog below." ).format( - lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, - loc=gisenv()["LOCATION_NAME"], - ) - self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) - - def ShowDifferentMapsetOwnerInfo(self): - """Show info when last used mapset is owned by different user""" - last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) - owner = get_mapset_owner(last_used_mapset_path) - message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is owned " - "by different user '{owner}'. GRASS GIS has started in a temporary " - "Location {loc}. To continue, find or create another location through " - "Data catalog below." - ).format( - lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, - owner=owner, + string=string, loc=gisenv()["LOCATION_NAME"], ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) @@ -104,20 +80,36 @@ def ShowDifferentMapsetOwnerInfo(self): def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): """Show info when last used mapset is locked""" last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - lastdb, lastloc, lastmapset = split_mapset_path(last_used_mapset_path) buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( - "Last used mapset in path '{lastdb}/{lastloc}/{lastmapset}' is locked. " + "Last used mapset in path '{mapsetpath}' is locked. " "GRASS GIS has started in a temporary Location {loc}. " "To continue, find or create another location through " "Data Catalog below, or remove .gislock and switch to last used mapset." ).format( - lastdb=lastdb, - lastloc=lastloc, - lastmapset=lastmapset, + mapsetpath=last_used_mapset_path, loc=gisenv()["LOCATION_NAME"], ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) + def _getString(self, reason_id): + """ Get string for infobar message based on the reason.""" + last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] + string = None + if reason_id == "non-existent": + string = "Last used mapset in path '{mapsetpath}' does not exist".format( + mapsetpath=last_used_mapset_path) + elif reason_id == "invalid": + string = "Last used mapset in path '{mapsetpath}' is invalid".format( + mapsetpath=last_used_mapset_path) + elif reason_id == "different-owner": + owner = get_mapset_owner(last_used_mapset_path) + string = "Last used mapset in path '{mapsetpath}' has different owner {owner}".format( + owner=owner, + mapsetpath=last_used_mapset_path) + return string + def _onLearnMore(self, event): self._giface.Help(entry="grass_database") + + diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 1a4513b5961..263688383b2 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -61,11 +61,12 @@ get_reason_mapset_not_removable, get_reasons_location_not_removable, get_mapset_name_invalid_reason, - get_location_name_invalid_reason, + get_location_name_invalid_reason ) from grass.grassdb.manage import ( rename_mapset, - rename_location + rename_location, + delete_temporary_location ) from grass.pydispatch.signal import Signal @@ -73,7 +74,6 @@ import grass.script as gscript from grass.script import gisenv from grass.grassdb.data import map_exists -from grass.grassdb.manage import delete_temporary_location from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, is_different_mapset_owner, is_first_time_user, is_nonstandard_startup) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 4ea6a1dc677..e61d4a77bac 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -204,24 +204,24 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): def get_reason_mapset_not_usable(mapset_path): """It finds a reason why mapset is not usable. - Returns a reason id as number if there was a reason, otherwise None. - Returns 1 if mapset is invalid. - Returns 2 if mapset has a different owner. - Returns 3 if mapset is locked. + Returns a reason id as string if there was a reason, otherwise None. """ if mapset_path is None: return reason_id = None + # Check whether mapset exists + if not os.path.exists(mapset_path): + reason_id = "non-existent" # Check whether mapset is valid - if not is_mapset_valid(mapset_path): - reason_id = 1 + elif not is_mapset_valid(mapset_path): + reason_id = "invalid" # Check whether mapset is owned by current user elif not is_current_user_mapset_owner(mapset_path): - reason_id = 2 + reason_id = "different-owner" # Check whether mapset is locked elif is_mapset_locked(mapset_path): - reason_id = 3 + reason_id = "locked" return reason_id From 26f1fae2eb0a060685a4c0b51abece18f3c350fc Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 04:10:21 -0500 Subject: [PATCH 18/45] writing to gisrcrc simplified and only one function is-first-time-user created in checks.py --- gui/wxpython/datacatalog/infomanager.py | 2 - lib/init/grass.py | 49 +++++++++---------------- python/grass/grassdb/checks.py | 16 ++++---- python/grass/grassdb/session.py | 4 +- 4 files changed, 30 insertions(+), 41 deletions(-) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index de3fd8312ec..860cbaf9f39 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -111,5 +111,3 @@ def _getString(self, reason_id): def _onLearnMore(self, event): self._giface.Help(entry="grass_database") - - diff --git a/lib/init/grass.py b/lib/init/grass.py index bdddec36d08..2062fd6f9ce 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -229,25 +229,6 @@ def writefile(path, s): f.close() -def readlines(path, skipped_parameter=None): - debug("Reading %s" % path) - number = 0 - with open(path, "r") as f: - lines = f.readlines() - for line in lines: - if skipped_parameter in line: - del lines[number] - number += 1 - return lines - - -def writelines(path, lines): - debug("Writing %s" % path) - with open(path, "w") as f: - for line in lines: - f.write(line) - - def call(cmd, **kwargs): """Wrapper for subprocess.call to deal with platform-specific issues""" if WINDOWS: @@ -605,6 +586,21 @@ def read_gisrc(filename): return kv +def write_gisrcrc(gisrcrc, gisrc, skipped_parameter=None): + """Reads gisrc file and write to gisrcrc""" + debug("Reading %s" % gisrc) + number = 0 + with open(gisrc, "r") as f: + lines = f.readlines() + for line in lines: + if skipped_parameter in line: + del lines[number] + number += 1 + with open(gisrcrc, "w") as f: + for line in lines: + f.write(line) + + def read_env_file(path): kv = {} f = open(path, "r") @@ -872,13 +868,6 @@ def create_initial_gisrc(filename): writefile(filename, s) -def first_time_user(mapset_settings): - # Returns true if we are working with initial GISRC - return mapset_settings.full_mapset == os.path.join( - os.getcwd(), "", "" - ) - - def check_gui(expected_gui): grass_gui = expected_gui # Check if we are running X windows by checking the DISPLAY variable @@ -2531,7 +2520,7 @@ def main(): debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: import grass.app as ga - from grass.grassdb.checks import can_start_in_mapset + from grass.grassdb.checks import can_start_in_mapset, is_first_time_user # Set last used mapset to gisrc set_last_mapset_to_gisrc( @@ -2542,7 +2531,7 @@ def main(): mapset_settings.mapset, ), ) - if first_time_user(mapset_settings): + if is_first_time_user(): # Ensure default data hiearchy ( default_gisdbase, @@ -2731,9 +2720,7 @@ def main(): if not params.tmp_location or ( params.tmp_location and mapset_settings.gisdbase != os.environ["TMPDIR"] ): - writelines( - gisrcrc, readlines(path=gisrc, skipped_parameter="LAST_MAPSET_PATH") - ) + write_gisrcrc(gisrcrc, gisrc, skipped_parameter="LAST_MAPSET_PATH") # After this point no more grass modules may be called # done message at last: no atexit.register() # or register done_message() diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index e61d4a77bac..656256f3112 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -141,13 +141,15 @@ def is_first_time_user(): """ Check if a user is a first-time user. Returns True if a user is a first-time user. - It occurs when a gisrc file has initial settings. + It occurs when a gisrc file has initial settings either in last used mapset or in current mapset settings """ - if "LAST_MAPSET_PATH" in read_gisrc().keys(): - initial_gisrc = read_gisrc()["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"] - ) - return initial_gisrc + gisrc = read_gisrc() + if "LAST_MAPSET_PATH" in gisrc.keys(): + if gisrc["LAST_MAPSET_PATH"] == os.path.join( + os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"]): + return True + elif gisrc["GISDBASE"] == os.getcwd() and gisrc["LOCATION_NAME"] == globalvars["UNKNOWN_LOCATION"] and gisrc["MAPSET"] == globalvars["UNKNOWN_MAPSET"]: + return True return False @@ -204,7 +206,7 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): def get_reason_mapset_not_usable(mapset_path): """It finds a reason why mapset is not usable. - Returns a reason id as string if there was a reason, otherwise None. + Returns a reason id as string if there is a reason, otherwise None. """ if mapset_path is None: return diff --git a/python/grass/grassdb/session.py b/python/grass/grassdb/session.py index 1b915c8c8d3..62cd2be00fe 100644 --- a/python/grass/grassdb/session.py +++ b/python/grass/grassdb/session.py @@ -11,8 +11,10 @@ import os import sys +from grass.grassdb.globals import globalvars ### TODO move SetSessionMapset and GetVersion from guiutils here +### TODO add read_gisrc and write_gisrcrc and other functions from grass.py def read_gisrc(): """Read variables from a current GISRC file @@ -41,4 +43,4 @@ def read_gisrc(): finally: rc.close() - return grassrc \ No newline at end of file + return grassrc From 7b64859cdaeb5319832699650f2d5171bd7f0249 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 04:22:36 -0500 Subject: [PATCH 19/45] black, flake --- gui/wxpython/datacatalog/infomanager.py | 10 ++++++---- python/grass/grassdb/checks.py | 17 ++++++++++++----- python/grass/grassdb/session.py | 9 +++++---- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index 860cbaf9f39..a4089c39f6d 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -98,15 +98,17 @@ def _getString(self, reason_id): string = None if reason_id == "non-existent": string = "Last used mapset in path '{mapsetpath}' does not exist".format( - mapsetpath=last_used_mapset_path) + mapsetpath=last_used_mapset_path + ) elif reason_id == "invalid": string = "Last used mapset in path '{mapsetpath}' is invalid".format( - mapsetpath=last_used_mapset_path) + mapsetpath=last_used_mapset_path + ) elif reason_id == "different-owner": owner = get_mapset_owner(last_used_mapset_path) string = "Last used mapset in path '{mapsetpath}' has different owner {owner}".format( - owner=owner, - mapsetpath=last_used_mapset_path) + owner=owner, mapsetpath=last_used_mapset_path + ) return string def _onLearnMore(self, event): diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 656256f3112..46f6a0027ab 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -126,19 +126,21 @@ def is_current_mapset_in_default_location(): def is_nonstandard_startup(): - """ Checks if a user encounters a nonstandard startup. + """Checks if a user encounters a nonstandard startup. Returns True if a user encounters a nonstandard startup. It occurs when a last mapset is not usable and at the same time a user is in a temporary location. """ if "LAST_MAPSET_PATH" in read_gisrc().keys(): - return is_mapset_current(os.environ["TMPDIR"], globalvars["TEMPORARY_LOCATION"], "PERMANENT") + return is_mapset_current( + os.environ["TMPDIR"], globalvars["TEMPORARY_LOCATION"], "PERMANENT" + ) return False def is_first_time_user(): - """ Check if a user is a first-time user. + """Check if a user is a first-time user. Returns True if a user is a first-time user. It occurs when a gisrc file has initial settings either in last used mapset or in current mapset settings @@ -146,9 +148,14 @@ def is_first_time_user(): gisrc = read_gisrc() if "LAST_MAPSET_PATH" in gisrc.keys(): if gisrc["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"]): + os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"] + ): return True - elif gisrc["GISDBASE"] == os.getcwd() and gisrc["LOCATION_NAME"] == globalvars["UNKNOWN_LOCATION"] and gisrc["MAPSET"] == globalvars["UNKNOWN_MAPSET"]: + elif ( + gisrc["GISDBASE"] == os.getcwd() + and gisrc["LOCATION_NAME"] == globalvars["UNKNOWN_LOCATION"] + and gisrc["MAPSET"] == globalvars["UNKNOWN_MAPSET"] + ): return True return False diff --git a/python/grass/grassdb/session.py b/python/grass/grassdb/session.py index 62cd2be00fe..5ee279eded4 100644 --- a/python/grass/grassdb/session.py +++ b/python/grass/grassdb/session.py @@ -11,10 +11,10 @@ import os import sys -from grass.grassdb.globals import globalvars -### TODO move SetSessionMapset and GetVersion from guiutils here -### TODO add read_gisrc and write_gisrcrc and other functions from grass.py +# TODO move SetSessionMapset and GetVersion from guiutils here +# TODO add read_gisrc and write_gisrcrc and other functions from grass.py + def read_gisrc(): """Read variables from a current GISRC file @@ -38,7 +38,8 @@ def read_gisrc(): key, val = line.split(":", 1) except ValueError as e: sys.stderr.write( - _('Invalid line in GISRC file (%s):%s\n' % (e, line))) + _("Invalid line in GISRC file (%s):%s\n" % (e, line)) + ) grassrc[key.strip()] = val.strip() finally: rc.close() From 4a25e1ba896aee1055db4daa0ee08926c84ce49d Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 06:58:23 -0500 Subject: [PATCH 20/45] deleting and removing temporary location when switched from tmp in nonstandard startup --- gui/wxpython/datacatalog/tree.py | 19 +++++++++++++------ gui/wxpython/lmgr/frame.py | 19 ++++++++++++++++++- gui/wxpython/startup/guiutils.py | 13 +++++++++---- python/grass/grassdb/checks.py | 3 ++- python/grass/grassdb/manage.py | 5 ----- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 263688383b2..60966aafa5b 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -66,7 +66,6 @@ from grass.grassdb.manage import ( rename_mapset, rename_location, - delete_temporary_location ) from grass.pydispatch.signal import Signal @@ -1499,22 +1498,25 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): """ Switch to location and mapset interactively. """ + # Decide if a startup is nonstandard + nonstandard_startup = False + if is_nonstandard_startup(): + nonstandard_startup = True + if can_switch_mapset_interactive(self, grassdb, location, mapset): genv = gisenv() # Switch to mapset in the same location if (grassdb == genv['GISDBASE'] and location == genv['LOCATION_NAME']): switch_mapset_interactively(self, self._giface, None, None, mapset, - show_confirmation) + nonstandard_startup, show_confirmation) # Switch to mapset in the same grassdb elif grassdb == genv['GISDBASE']: switch_mapset_interactively(self, self._giface, None, location, mapset, - show_confirmation) + nonstandard_startup, show_confirmation) # Switch to mapset in a different grassdb else: switch_mapset_interactively(self, self._giface, grassdb, location, mapset, - show_confirmation) - if is_nonstandard_startup(): - delete_temporary_location() + nonstandard_startup, show_confirmation) def OnSwitchMapset(self, event): """Switch to location and mapset""" @@ -1563,6 +1565,11 @@ def _updateAfterGrassdbChanged(self, action, element, grassdb, location, mapset= location=location) if node: self._renameNode(node, newname) + elif element == 'grassdb': + if action == 'delete': + node = self.GetDbNode(grassdb=grassdb) + if node: + self.RemoveGrassDB(node) elif element in ('raster', 'vector', 'raster_3d'): # when watchdog is used, it watches current mapset, # so we don't process any signals here, diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 53772e7b32d..651bdc7183d 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -72,6 +72,8 @@ create_location_interactively ) from grass.grassdb.checks import is_first_time_user +from grass.grassdb.manage import delete_location +from grass.grassdb.globals import globalvars class GMFrame(wx.Frame): @@ -1130,9 +1132,10 @@ def OnChangeMapset(self, event): None, mapset) - def OnMapsetChanged(self, dbase, location, mapset): + def OnMapsetChanged(self, dbase, location, mapset, nonstandard_startup): """Current mapset changed. If location is None, mapset changed within location. + In addition, if nonstandard startup, it deletes temporary location. """ if not location: self._setTitle() @@ -1140,6 +1143,20 @@ def OnMapsetChanged(self, dbase, location, mapset): # close current workspace and create new one self.OnWorkspaceClose() self.OnWorkspaceNew() + if nonstandard_startup: + # Delete temporary location + self.DeleteTemporaryLocation() + + def DeleteTemporaryLocation(self): + """ Delete location in TMPDIR session dir""" + grassdb = os.environ["TMPDIR"] + location = globalvars["TEMPORARY_LOCATION"] + if os.path.exists(os.path.join(grassdb, location)): + delete_location(grassdb, location) + self._giface.grassdbChanged.emit(location=location, + grassdb=grassdb, + action='delete', + element='grassdb') def OnChangeCWD(self, event=None, cmd=None): """Change current working directory diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 62ee69ccc8d..c46cfd778df 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -688,7 +688,7 @@ def import_file(guiparent, filePath, env): def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, - show_confirmation=False): + nonstandard_startup=False, show_confirmation=False): """Switch current mapset. Emits giface.currentMapsetChanged signal.""" if dbase: if RunCommand('g.mapset', parent=guiparent, @@ -704,7 +704,8 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, {'dbase': dbase, 'loc': location, 'mapset': mapset}) giface.currentMapsetChanged.emit(dbase=dbase, location=location, - mapset=mapset) + mapset=mapset, + nonstandard_startup=nonstandard_startup) elif location: if RunCommand('g.mapset', parent=guiparent, location=location, @@ -716,7 +717,8 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, {'loc': location, 'mapset': mapset}) giface.currentMapsetChanged.emit(dbase=None, location=location, - mapset=mapset) + mapset=mapset, + nonstandard_startup=nonstandard_startup) else: if RunCommand('g.mapset', parent=guiparent, @@ -724,4 +726,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, if show_confirmation: GMessage(parent=guiparent, message=_("Current mapset is <%s>.") % mapset) - giface.currentMapsetChanged.emit(dbase=None, location=None, mapset=mapset) + giface.currentMapsetChanged.emit(dbase=None, + location=None, + mapset=mapset, + nonstandard_startup=nonstandard_startup) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 46f6a0027ab..076d98c79b0 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -143,7 +143,8 @@ def is_first_time_user(): """Check if a user is a first-time user. Returns True if a user is a first-time user. - It occurs when a gisrc file has initial settings either in last used mapset or in current mapset settings + It occurs when a gisrc file has initial settings either in last used mapset + or in current mapset settings. """ gisrc = read_gisrc() if "LAST_MAPSET_PATH" in gisrc.keys(): diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index 0ec1a5ec680..d5a4e8e7303 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -30,11 +30,6 @@ def delete_location(database, location): shutil.rmtree(os.path.join(database, location)) -def delete_temporary_location(): - """Deletes a temporary location""" - shutil.rmtree(os.path.join(os.environ["TMPDIR"], temporary_location)) - - def delete_grassdb(database): """Deletes a specified GRASS database""" shutil.rmtree(database) From 99a4404ec5a627bf07a9fa7257cdb5761e12b292 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 07:19:17 -0500 Subject: [PATCH 21/45] hide infobar --- gui/wxpython/lmgr/frame.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 651bdc7183d..145f7f3a074 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1146,6 +1146,9 @@ def OnMapsetChanged(self, dbase, location, mapset, nonstandard_startup): if nonstandard_startup: # Delete temporary location self.DeleteTemporaryLocation() + # Hide infobar + if self.datacatalog.infoBar.IsShown(): + self.datacatalog.infoBar.Dismiss() def DeleteTemporaryLocation(self): """ Delete location in TMPDIR session dir""" From bc4110b2bfe798c4fadcb1c54dcfd020a4bca97d Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 07:27:38 -0500 Subject: [PATCH 22/45] flake, black --- gui/wxpython/lmgr/frame.py | 7 +++---- python/grass/grassdb/manage.py | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 145f7f3a074..3d1322b7242 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1156,10 +1156,9 @@ def DeleteTemporaryLocation(self): location = globalvars["TEMPORARY_LOCATION"] if os.path.exists(os.path.join(grassdb, location)): delete_location(grassdb, location) - self._giface.grassdbChanged.emit(location=location, - grassdb=grassdb, - action='delete', - element='grassdb') + self._giface.grassdbChanged.emit( + location=location, grassdb=grassdb, action="delete", element="grassdb" + ) def OnChangeCWD(self, event=None, cmd=None): """Change current working directory diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index d5a4e8e7303..2f7de52a46e 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -13,8 +13,6 @@ import os import shutil -from grass.grassdb.strings import temporary_location - def delete_mapset(database, location, mapset): """Deletes a specified mapset""" From 28cfdba14e433297545f2b9a3a0d8f59a8b3b3ec Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 30 Mar 2021 07:40:15 -0500 Subject: [PATCH 23/45] this function not used anymore --- python/grass/grassdb/checks.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 076d98c79b0..4936e1cf6bb 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -117,14 +117,6 @@ def get_mapset_owner(mapset_path): return None -def is_current_mapset_in_default_location(): - """Returns True if mapset is in a default location""" - return ( - gisenv()["LOCATION_NAME"] == globalvars["DEFAULT_LOCATION"] - and gisenv()["MAPSET"] == "PERMANENT" - ) - - def is_nonstandard_startup(): """Checks if a user encounters a nonstandard startup. From b1ef3788565cf1981d0abfa26503ef69a398b1e7 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 31 Mar 2021 11:11:43 -0500 Subject: [PATCH 24/45] global variables not dict --- gui/wxpython/lmgr/frame.py | 4 ++-- python/grass/grassdb/checks.py | 10 +++++----- python/grass/grassdb/globals.py | 9 ++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 3d1322b7242..66f1afdbc1d 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -73,7 +73,7 @@ ) from grass.grassdb.checks import is_first_time_user from grass.grassdb.manage import delete_location -from grass.grassdb.globals import globalvars +import grass.grassdb.globals as gl class GMFrame(wx.Frame): @@ -1153,7 +1153,7 @@ def OnMapsetChanged(self, dbase, location, mapset, nonstandard_startup): def DeleteTemporaryLocation(self): """ Delete location in TMPDIR session dir""" grassdb = os.environ["TMPDIR"] - location = globalvars["TEMPORARY_LOCATION"] + location = gl.temporary_location if os.path.exists(os.path.join(grassdb, location)): delete_location(grassdb, location) self._giface.grassdbChanged.emit( diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 4936e1cf6bb..9137606c8d7 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -17,7 +17,7 @@ import grass.script as gs import glob -from grass.grassdb.globals import globalvars +import grass.grassdb.globals as gl from grass.grassdb.session import read_gisrc @@ -126,7 +126,7 @@ def is_nonstandard_startup(): """ if "LAST_MAPSET_PATH" in read_gisrc().keys(): return is_mapset_current( - os.environ["TMPDIR"], globalvars["TEMPORARY_LOCATION"], "PERMANENT" + os.environ["TMPDIR"], gl.temporary_location, "PERMANENT" ) return False @@ -141,13 +141,13 @@ def is_first_time_user(): gisrc = read_gisrc() if "LAST_MAPSET_PATH" in gisrc.keys(): if gisrc["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), globalvars["UNKNOWN_LOCATION"], globalvars["UNKNOWN_MAPSET"] + os.getcwd(), gl.unknown_location, gl.unknown_mapset ): return True elif ( gisrc["GISDBASE"] == os.getcwd() - and gisrc["LOCATION_NAME"] == globalvars["UNKNOWN_LOCATION"] - and gisrc["MAPSET"] == globalvars["UNKNOWN_MAPSET"] + and gisrc["LOCATION_NAME"] == gl.unknown_location + and gisrc["MAPSET"] == gl.unknown_mapset ): return True return False diff --git a/python/grass/grassdb/globals.py b/python/grass/grassdb/globals.py index 9c169b4f57a..753f77e4b5c 100644 --- a/python/grass/grassdb/globals.py +++ b/python/grass/grassdb/globals.py @@ -10,8 +10,7 @@ """ # global variables -globalvars = {} -globalvars["DEFAULT_LOCATION"] = "world_latlong_wgs84" -globalvars["TEMPORARY_LOCATION"] = "tmploc" -globalvars["UNKNOWN_LOCATION"] = "" -globalvars["UNKNOWN_MAPSET"] = "" +default_location = "world_latlong_wgs84" +temporary_location = "tmploc" +unknown_location = "" +unknown_mapset = "" From 74c6226f7f7d2f8523f6556dd8c73c1e4118d30a Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 31 Mar 2021 12:50:35 -0500 Subject: [PATCH 25/45] notes from Vashek for gui --- gui/wxpython/datacatalog/catalog.py | 18 +++++------ gui/wxpython/datacatalog/infomanager.py | 9 +++--- gui/wxpython/datacatalog/tree.py | 18 +++++------ gui/wxpython/lmgr/frame.py | 6 ++-- gui/wxpython/startup/guiutils.py | 41 +++---------------------- 5 files changed, 29 insertions(+), 63 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 9f0a3d28bf6..f847c3b87a5 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -26,14 +26,14 @@ from datacatalog.infomanager import DataCatalogInfoManager from gui_core.wrap import Menu from gui_core.forms import GUI +from grass.script import gisenv from grass.pydispatch.signal import Signal -from grass.grassdb.session import read_gisrc from grass.grassdb.manage import split_mapset_path -from grass.grassdb.checks import (get_reason_mapset_not_usable, - is_nonstandard_startup, - is_first_time_user) +from grass.grassdb.checks import (get_reason_id_mapset_not_usable, + is_backup_session, + is_first_time_user) class DataCatalog(wx.Panel): @@ -77,11 +77,11 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, wx.CallLater(delay, self.showDataStructureInfo) # show infobar if last used mapset is not usable - if is_nonstandard_startup(): + if is_backup_session(): # get reason why last used mapset is not usable - last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] - self.reason_id = get_reason_mapset_not_usable(last_mapset_path) - if self.reason_id == "non-existent" or self.reason_id == "invalid" or self.reason_id == "different-owner": + last_mapset_path = gisenv()["LAST_MAPSET_PATH"] + self.reason_id = get_reason_id_mapset_not_usable(last_mapset_path) + if self.reason_id in ("non-existent", "invalid", "different-owner"): # show non-standard situation info wx.CallLater(delay, self.showNonStandardSituationInfo) elif self.reason_id == "locked": @@ -162,7 +162,7 @@ def OnDownloadLocation(self, event): def OnSwitchToLastUsedMapset(self, event): """Switch to last used mapset""" - last_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] + last_mapset_path = gisenv()["LAST_MAPSET_PATH"] grassdb, location, mapset = split_mapset_path(last_mapset_path) self.tree.SwitchMapset(grassdb, location, mapset) event.Skip() diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index a4089c39f6d..a3fb2ffbbe9 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -20,7 +20,6 @@ import wx from grass.script import gisenv -from grass.grassdb.session import read_gisrc from grass.grassdb.checks import get_mapset_owner @@ -66,7 +65,7 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler def ShowNonStandardSituationInfo(self, reason_id): """Show info when last used mapset is not usable""" - string = self._getString(reason_id) + string = self._text_from_reason_id(reason_id) message = _( "{string}. GRASS GIS has started in a temporary Location {loc}. " "To continue, find or create another location through " @@ -79,7 +78,7 @@ def ShowNonStandardSituationInfo(self, reason_id): def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): """Show info when last used mapset is locked""" - last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] + last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( "Last used mapset in path '{mapsetpath}' is locked. " @@ -92,9 +91,9 @@ def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) - def _getString(self, reason_id): + def _text_from_reason_id(self, reason_id): """ Get string for infobar message based on the reason.""" - last_used_mapset_path = read_gisrc()["LAST_MAPSET_PATH"] + last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] string = None if reason_id == "non-existent": string = "Last used mapset in path '{mapsetpath}' does not exist".format( diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 60966aafa5b..0dc05d1f097 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -65,7 +65,7 @@ ) from grass.grassdb.manage import ( rename_mapset, - rename_location, + rename_location ) from grass.pydispatch.signal import Signal @@ -75,7 +75,7 @@ from grass.grassdb.data import map_exists from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, is_different_mapset_owner, is_first_time_user, - is_nonstandard_startup) + is_backup_session) from grass.exceptions import CalledModuleError @@ -1498,25 +1498,25 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): """ Switch to location and mapset interactively. """ - # Decide if a startup is nonstandard - nonstandard_startup = False - if is_nonstandard_startup(): - nonstandard_startup = True + # Decide if a user is in a backup session + backup_session = False + if is_backup_session(): + backup_session = True if can_switch_mapset_interactive(self, grassdb, location, mapset): genv = gisenv() # Switch to mapset in the same location if (grassdb == genv['GISDBASE'] and location == genv['LOCATION_NAME']): switch_mapset_interactively(self, self._giface, None, None, mapset, - nonstandard_startup, show_confirmation) + backup_session, show_confirmation) # Switch to mapset in the same grassdb elif grassdb == genv['GISDBASE']: switch_mapset_interactively(self, self._giface, None, location, mapset, - nonstandard_startup, show_confirmation) + backup_session, show_confirmation) # Switch to mapset in a different grassdb else: switch_mapset_interactively(self, self._giface, grassdb, location, mapset, - nonstandard_startup, show_confirmation) + backup_session, show_confirmation) def OnSwitchMapset(self, event): """Switch to location and mapset""" diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 66f1afdbc1d..c72288ed11d 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1132,10 +1132,10 @@ def OnChangeMapset(self, event): None, mapset) - def OnMapsetChanged(self, dbase, location, mapset, nonstandard_startup): + def OnMapsetChanged(self, dbase, location, mapset, backup_session): """Current mapset changed. If location is None, mapset changed within location. - In addition, if nonstandard startup, it deletes temporary location. + In addition, if backup session, it deletes temporary location. """ if not location: self._setTitle() @@ -1143,7 +1143,7 @@ def OnMapsetChanged(self, dbase, location, mapset, nonstandard_startup): # close current workspace and create new one self.OnWorkspaceClose() self.OnWorkspaceNew() - if nonstandard_startup: + if backup_session: # Delete temporary location self.DeleteTemporaryLocation() # Hide infobar diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index c46cfd778df..92ed31365c8 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -43,20 +43,12 @@ from grass.script.core import create_environment from grass.script.utils import try_remove -from core import globalvar from core.gcmd import GError, GMessage, RunCommand from gui_core.dialogs import TextEntryDialog from location_wizard.dialogs import RegionDef from gui_core.widgets import GenericValidator -def SetSessionMapset(database, location, mapset): - """Sets database, location and mapset for the current session""" - RunCommand("g.gisenv", set="GISDBASE=%s" % database) - RunCommand("g.gisenv", set="LOCATION_NAME=%s" % location) - RunCommand("g.gisenv", set="MAPSET=%s" % mapset) - - class MapsetDialog(TextEntryDialog): def __init__(self, parent=None, default=None, message=None, caption=None, database=None, location=None): @@ -111,31 +103,6 @@ def _isLocationNameValid(self, text): return is_location_name_valid(self.database, text) -def GetVersion(): - """Gets version and revision - - Returns tuple `(version, revision)`. For standard releases revision - is an empty string. - - Revision string is currently wrapped in parentheses with added - leading space. This is an implementation detail and legacy and may - change anytime. - """ - versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER")) - versionLine = versionFile.readline().rstrip('\n') - versionFile.close() - try: - grassVersion, grassRevision = versionLine.split(' ', 1) - if grassVersion.endswith('dev'): - grassRevisionStr = ' (%s)' % grassRevision - else: - grassRevisionStr = '' - except ValueError: - grassVersion = versionLine - grassRevisionStr = '' - return (grassVersion, grassRevisionStr) - - def create_mapset_interactively(guiparent, grassdb, location): """ Create new mapset @@ -688,7 +655,7 @@ def import_file(guiparent, filePath, env): def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, - nonstandard_startup=False, show_confirmation=False): + backup_session=False, show_confirmation=False): """Switch current mapset. Emits giface.currentMapsetChanged signal.""" if dbase: if RunCommand('g.mapset', parent=guiparent, @@ -705,7 +672,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=dbase, location=location, mapset=mapset, - nonstandard_startup=nonstandard_startup) + backup_session=backup_session) elif location: if RunCommand('g.mapset', parent=guiparent, location=location, @@ -718,7 +685,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=None, location=location, mapset=mapset, - nonstandard_startup=nonstandard_startup) + backup_session=backup_session) else: if RunCommand('g.mapset', parent=guiparent, @@ -729,4 +696,4 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=None, location=None, mapset=mapset, - nonstandard_startup=nonstandard_startup) + backup_session=backup_session) From dc10dad3f7d54269979e9c50d581894bf6a08c0b Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 31 Mar 2021 12:51:08 -0500 Subject: [PATCH 26/45] notes from Vashek for grassdb and app --- python/grass/app/data.py | 10 +++---- python/grass/grassdb/Makefile | 2 +- python/grass/grassdb/checks.py | 27 +++++++++---------- python/grass/grassdb/globals.py | 1 + python/grass/grassdb/session.py | 47 --------------------------------- 5 files changed, 18 insertions(+), 69 deletions(-) delete mode 100644 python/grass/grassdb/session.py diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 1c7513a799b..8dc7ee9a267 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -17,8 +17,7 @@ import getpass import sys from shutil import copytree, ignore_patterns -from grass.grassdb.create import create_mapset -from grass.grassdb.checks import mapset_exists +import grass.grassdb.globals as gl from grass.grassdb.checks import is_location_valid @@ -152,8 +151,8 @@ def ensure_default_data_hierarchy(): Returns the db, loc, mapset""" default_gisdbase = get_possible_database_path() - default_location = "world_latlong_wgs84" - default_mapset = "PERMANENT" + default_location = gl.default_location + default_mapset = gl.permanent_mapset # If nothing found, try to create GRASS directory if not default_gisdbase: @@ -163,7 +162,4 @@ def ensure_default_data_hierarchy(): # If not valid, copy startup loc create_startup_location_in_grassdb(default_gisdbase, default_location) - if not mapset_exists(default_gisdbase, default_location, default_mapset): - create_mapset(default_gisdbase, default_location, default_mapset) - return default_gisdbase, default_location, default_mapset diff --git a/python/grass/grassdb/Makefile b/python/grass/grassdb/Makefile index f95d584802c..83cef11b3b8 100644 --- a/python/grass/grassdb/Makefile +++ b/python/grass/grassdb/Makefile @@ -5,7 +5,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make DSTDIR = $(ETC)/python/grass/grassdb -MODULES = checks create data manage globals session +MODULES = checks create data manage globals PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 9137606c8d7..0d86367646e 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -18,7 +18,6 @@ import glob import grass.grassdb.globals as gl -from grass.grassdb.session import read_gisrc def mapset_exists(database, location, mapset): @@ -117,16 +116,16 @@ def get_mapset_owner(mapset_path): return None -def is_nonstandard_startup(): - """Checks if a user encounters a nonstandard startup. +def is_backup_session(): + """Checks if a user encounters a backup GRASS session. - Returns True if a user encounters a nonstandard startup. + Returns True if a user encounters a backup session. It occurs when a last mapset is not usable and at the same time a user is in a temporary location. """ - if "LAST_MAPSET_PATH" in read_gisrc().keys(): + if "LAST_MAPSET_PATH" in gisenv().keys(): return is_mapset_current( - os.environ["TMPDIR"], gl.temporary_location, "PERMANENT" + os.environ["TMPDIR"], gl.temporary_location, gl.permanent_mapset ) return False @@ -138,16 +137,16 @@ def is_first_time_user(): It occurs when a gisrc file has initial settings either in last used mapset or in current mapset settings. """ - gisrc = read_gisrc() - if "LAST_MAPSET_PATH" in gisrc.keys(): - if gisrc["LAST_MAPSET_PATH"] == os.path.join( + genv = gisenv() + if "LAST_MAPSET_PATH" in genv.keys(): + if genv["LAST_MAPSET_PATH"] == os.path.join( os.getcwd(), gl.unknown_location, gl.unknown_mapset ): return True elif ( - gisrc["GISDBASE"] == os.getcwd() - and gisrc["LOCATION_NAME"] == gl.unknown_location - and gisrc["MAPSET"] == gl.unknown_mapset + genv["GISDBASE"] == os.getcwd() + and genv["LOCATION_NAME"] == gl.unknown_location + and genv["MAPSET"] == gl.unknown_mapset ): return True return False @@ -203,10 +202,10 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): return True -def get_reason_mapset_not_usable(mapset_path): +def get_reason_id_mapset_not_usable(mapset_path): """It finds a reason why mapset is not usable. - Returns a reason id as string if there is a reason, otherwise None. + Returns a reason id as string. """ if mapset_path is None: return diff --git a/python/grass/grassdb/globals.py b/python/grass/grassdb/globals.py index 753f77e4b5c..8e1a83e8996 100644 --- a/python/grass/grassdb/globals.py +++ b/python/grass/grassdb/globals.py @@ -14,3 +14,4 @@ temporary_location = "tmploc" unknown_location = "" unknown_mapset = "" +permanent_mapset = "PERMANENT" diff --git a/python/grass/grassdb/session.py b/python/grass/grassdb/session.py deleted file mode 100644 index 5ee279eded4..00000000000 --- a/python/grass/grassdb/session.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Manage GRASS GIS session. - -(C) 2020 by the GRASS Development Team -This program is free software under the GNU General Public -License (>=v2). Read the file COPYING that comes with GRASS -for details. - -.. sectionauthor:: Linda Kladivova -""" - -import os -import sys - -# TODO move SetSessionMapset and GetVersion from guiutils here -# TODO add read_gisrc and write_gisrcrc and other functions from grass.py - - -def read_gisrc(): - """Read variables from a current GISRC file - - Returns a dictionary representation of the file content. - """ - grassrc = {} - - gisrc = os.getenv("GISRC") - - try: - rc = open(gisrc, "r") - except IOError: - return grassrc - - if gisrc and os.path.isfile(gisrc): - try: - rc = open(gisrc, "r") - for line in rc.readlines(): - try: - key, val = line.split(":", 1) - except ValueError as e: - sys.stderr.write( - _("Invalid line in GISRC file (%s):%s\n" % (e, line)) - ) - grassrc[key.strip()] = val.strip() - finally: - rc.close() - - return grassrc From 277c9075f6c8f46cc3287c47f3b42a37df708030 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 1 Apr 2021 04:18:47 -0500 Subject: [PATCH 27/45] mainly renaming variables and some simplyfing --- gui/wxpython/lmgr/frame.py | 4 +-- lib/init/grass.py | 18 ++++++------ python/grass/app/data.py | 7 ++--- python/grass/grassdb/Makefile | 2 +- python/grass/grassdb/checks.py | 28 +++++++++---------- .../grass/grassdb/{globals.py => config.py} | 0 6 files changed, 29 insertions(+), 30 deletions(-) rename python/grass/grassdb/{globals.py => config.py} (100%) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index c72288ed11d..444e3c3bb9b 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -73,7 +73,7 @@ ) from grass.grassdb.checks import is_first_time_user from grass.grassdb.manage import delete_location -import grass.grassdb.globals as gl +import grass.grassdb.config as cfg class GMFrame(wx.Frame): @@ -1153,7 +1153,7 @@ def OnMapsetChanged(self, dbase, location, mapset, backup_session): def DeleteTemporaryLocation(self): """ Delete location in TMPDIR session dir""" grassdb = os.environ["TMPDIR"] - location = gl.temporary_location + location = cfg.temporary_location if os.path.exists(os.path.join(grassdb, location)): delete_location(grassdb, location) self._giface.grassdbChanged.emit( diff --git a/lib/init/grass.py b/lib/init/grass.py index 2062fd6f9ce..23d14963a9f 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -620,7 +620,7 @@ def write_gisrc(kv, filename, append=False): f.close() -def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): +def add_mapset_to_gisrc(gisrc, grassdb, location, mapset): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) else: @@ -631,7 +631,7 @@ def set_mapset_to_gisrc(gisrc, grassdb, location, mapset): write_gisrc(kv, gisrc) -def set_last_mapset_to_gisrc(gisrc, last_mapset_path): +def add_last_mapset_to_gisrc(gisrc, last_mapset_path): if os.access(gisrc, os.R_OK): kv = read_gisrc(gisrc) else: @@ -1189,7 +1189,7 @@ def set_mapset( ) ) writefile(os.path.join(path, "WIND"), s) - set_mapset_to_gisrc(gisrc, gisdbase, location_name, mapset) + add_mapset_to_gisrc(gisrc, gisdbase, location_name, mapset) else: fatal( _( @@ -2522,8 +2522,8 @@ def main(): import grass.app as ga from grass.grassdb.checks import can_start_in_mapset, is_first_time_user - # Set last used mapset to gisrc - set_last_mapset_to_gisrc( + # Add last used mapset to gisrc + add_last_mapset_to_gisrc( gisrc, os.path.join( mapset_settings.gisdbase, @@ -2552,7 +2552,7 @@ def main(): mapset_path=default_mapset_path, ignore_lock=False ): # Write mapset info to gisrc file - set_mapset_to_gisrc( + add_mapset_to_gisrc( gisrc=gisrc, grassdb=default_gisdbase, location=default_location, @@ -2560,8 +2560,8 @@ def main(): ) # Another first-time session else: - # Set default path to gisrc - set_last_mapset_to_gisrc(gisrc, default_mapset_path) + # Add last used mapset to gisrc + add_last_mapset_to_gisrc(gisrc, default_mapset_path) # Create temporary location params.tmp_location = True @@ -2584,7 +2584,7 @@ def main(): ) else: # Write mapset info to gisrc file - set_mapset_to_gisrc( + add_mapset_to_gisrc( gisrc=gisrc, grassdb=mapset_settings.gisdbase, location=mapset_settings.location, diff --git a/python/grass/app/data.py b/python/grass/app/data.py index 8dc7ee9a267..f7c573e8cc8 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -17,7 +17,7 @@ import getpass import sys from shutil import copytree, ignore_patterns -import grass.grassdb.globals as gl +import grass.grassdb.config as cfg from grass.grassdb.checks import is_location_valid @@ -146,13 +146,12 @@ def ensure_default_data_hierarchy(): """Ensure that default gisdbase, location and mapset exist. Creates database directory based on the default path determined according to OS if needed. Creates location if needed. - Ensure the default mapset and can create the new one if needed. Returns the db, loc, mapset""" default_gisdbase = get_possible_database_path() - default_location = gl.default_location - default_mapset = gl.permanent_mapset + default_location = cfg.default_location + default_mapset = cfg.permanent_mapset # If nothing found, try to create GRASS directory if not default_gisdbase: diff --git a/python/grass/grassdb/Makefile b/python/grass/grassdb/Makefile index 83cef11b3b8..ce3d6fb3d01 100644 --- a/python/grass/grassdb/Makefile +++ b/python/grass/grassdb/Makefile @@ -5,7 +5,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make DSTDIR = $(ETC)/python/grass/grassdb -MODULES = checks create data manage globals +MODULES = checks create data manage config PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__) PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 0d86367646e..2e1a590afad 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -17,7 +17,7 @@ import grass.script as gs import glob -import grass.grassdb.globals as gl +import grass.grassdb.config as cfg def mapset_exists(database, location, mapset): @@ -125,7 +125,7 @@ def is_backup_session(): """ if "LAST_MAPSET_PATH" in gisenv().keys(): return is_mapset_current( - os.environ["TMPDIR"], gl.temporary_location, gl.permanent_mapset + os.environ["TMPDIR"], cfg.temporary_location, cfg.permanent_mapset ) return False @@ -140,13 +140,13 @@ def is_first_time_user(): genv = gisenv() if "LAST_MAPSET_PATH" in genv.keys(): if genv["LAST_MAPSET_PATH"] == os.path.join( - os.getcwd(), gl.unknown_location, gl.unknown_mapset + os.getcwd(), cfg.unknown_location, cfg.unknown_mapset ): return True elif ( genv["GISDBASE"] == os.getcwd() - and genv["LOCATION_NAME"] == gl.unknown_location - and genv["MAPSET"] == gl.unknown_mapset + and genv["LOCATION_NAME"] == cfg.unknown_location + and genv["MAPSET"] == cfg.unknown_mapset ): return True return False @@ -205,25 +205,25 @@ def can_start_in_mapset(mapset_path, ignore_lock=False): def get_reason_id_mapset_not_usable(mapset_path): """It finds a reason why mapset is not usable. - Returns a reason id as string. + Returns a reason id as a string. + If mapset path is None or no reason found, returns None. """ - if mapset_path is None: - return - reason_id = None + if not mapset_path: + return None # Check whether mapset exists if not os.path.exists(mapset_path): - reason_id = "non-existent" + return "non-existent" # Check whether mapset is valid elif not is_mapset_valid(mapset_path): - reason_id = "invalid" + return "invalid" # Check whether mapset is owned by current user elif not is_current_user_mapset_owner(mapset_path): - reason_id = "different-owner" + return "different-owner" # Check whether mapset is locked elif is_mapset_locked(mapset_path): - reason_id = "locked" - return reason_id + return "locked" + return None def dir_contains_location(path): diff --git a/python/grass/grassdb/globals.py b/python/grass/grassdb/config.py similarity index 100% rename from python/grass/grassdb/globals.py rename to python/grass/grassdb/config.py From 391c1d3057d04ac400415e6fd4a55ed57d84530e Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 1 Apr 2021 05:02:19 -0500 Subject: [PATCH 28/45] wxGUI: temporary location deleted only when not current --- gui/wxpython/lmgr/frame.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 444e3c3bb9b..dcbf7c45e25 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -71,7 +71,7 @@ create_mapset_interactively, create_location_interactively ) -from grass.grassdb.checks import is_first_time_user +from grass.grassdb.checks import is_first_time_user, is_location_current from grass.grassdb.manage import delete_location import grass.grassdb.config as cfg @@ -1144,22 +1144,20 @@ def OnMapsetChanged(self, dbase, location, mapset, backup_session): self.OnWorkspaceClose() self.OnWorkspaceNew() if backup_session: - # Delete temporary location - self.DeleteTemporaryLocation() + grassdb = os.environ["TMPDIR"] + location = cfg.temporary_location + if os.path.exists(os.path.join(grassdb, location)) and not is_location_current( + grassdb, location + ): + # Delete temporary location + delete_location(grassdb, location) + self._giface.grassdbChanged.emit( + location=location, grassdb=grassdb, action="delete", element="grassdb" + ) # Hide infobar if self.datacatalog.infoBar.IsShown(): self.datacatalog.infoBar.Dismiss() - def DeleteTemporaryLocation(self): - """ Delete location in TMPDIR session dir""" - grassdb = os.environ["TMPDIR"] - location = cfg.temporary_location - if os.path.exists(os.path.join(grassdb, location)): - delete_location(grassdb, location) - self._giface.grassdbChanged.emit( - location=location, grassdb=grassdb, action="delete", element="grassdb" - ) - def OnChangeCWD(self, event=None, cmd=None): """Change current working directory From 91aa7005fef548f675875db543edcf3cee4725c8 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 1 Apr 2021 05:49:50 -0500 Subject: [PATCH 29/45] temporary location deleted only when switched to another db (a user could also create new location in temporary db) --- gui/wxpython/lmgr/frame.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index dcbf7c45e25..1bf44a0484c 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1135,7 +1135,7 @@ def OnChangeMapset(self, event): def OnMapsetChanged(self, dbase, location, mapset, backup_session): """Current mapset changed. If location is None, mapset changed within location. - In addition, if backup session, it deletes temporary location. + In addition, if temporary db is not current, it deletes temporary location. """ if not location: self._setTitle() @@ -1144,11 +1144,10 @@ def OnMapsetChanged(self, dbase, location, mapset, backup_session): self.OnWorkspaceClose() self.OnWorkspaceNew() if backup_session: + gisenv = grass.gisenv() grassdb = os.environ["TMPDIR"] location = cfg.temporary_location - if os.path.exists(os.path.join(grassdb, location)) and not is_location_current( - grassdb, location - ): + if not grassdb == gisenv["GISDBASE"]: # Delete temporary location delete_location(grassdb, location) self._giface.grassdbChanged.emit( From 44b7bca0f35b4a910675893bd012af25a8dbca86 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 1 Apr 2021 05:57:17 -0500 Subject: [PATCH 30/45] flake --- gui/wxpython/lmgr/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 1bf44a0484c..7a58e161a42 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -71,7 +71,7 @@ create_mapset_interactively, create_location_interactively ) -from grass.grassdb.checks import is_first_time_user, is_location_current +from grass.grassdb.checks import is_first_time_user from grass.grassdb.manage import delete_location import grass.grassdb.config as cfg From a85e73177a2ee645981bb04e2950aabd232cc6bc Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 1 Apr 2021 06:18:09 -0500 Subject: [PATCH 31/45] is_backup_session --> is_fallback_session --- gui/wxpython/datacatalog/catalog.py | 4 ++-- gui/wxpython/datacatalog/tree.py | 16 ++++++++-------- gui/wxpython/lmgr/frame.py | 4 ++-- gui/wxpython/startup/guiutils.py | 8 ++++---- python/grass/grassdb/checks.py | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index f847c3b87a5..a243afa6eca 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -32,7 +32,7 @@ from grass.grassdb.manage import split_mapset_path from grass.grassdb.checks import (get_reason_id_mapset_not_usable, - is_backup_session, + is_fallback_session, is_first_time_user) @@ -77,7 +77,7 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, wx.CallLater(delay, self.showDataStructureInfo) # show infobar if last used mapset is not usable - if is_backup_session(): + if is_fallback_session(): # get reason why last used mapset is not usable last_mapset_path = gisenv()["LAST_MAPSET_PATH"] self.reason_id = get_reason_id_mapset_not_usable(last_mapset_path) diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 0dc05d1f097..42f699ac6c7 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -75,7 +75,7 @@ from grass.grassdb.data import map_exists from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, is_different_mapset_owner, is_first_time_user, - is_backup_session) + is_fallback_session) from grass.exceptions import CalledModuleError @@ -1498,25 +1498,25 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): """ Switch to location and mapset interactively. """ - # Decide if a user is in a backup session - backup_session = False - if is_backup_session(): - backup_session = True + # Decide if a user is in a fallback session + fallback_session = False + if is_fallback_session(): + fallback_session = True if can_switch_mapset_interactive(self, grassdb, location, mapset): genv = gisenv() # Switch to mapset in the same location if (grassdb == genv['GISDBASE'] and location == genv['LOCATION_NAME']): switch_mapset_interactively(self, self._giface, None, None, mapset, - backup_session, show_confirmation) + fallback_session, show_confirmation) # Switch to mapset in the same grassdb elif grassdb == genv['GISDBASE']: switch_mapset_interactively(self, self._giface, None, location, mapset, - backup_session, show_confirmation) + fallback_session, show_confirmation) # Switch to mapset in a different grassdb else: switch_mapset_interactively(self, self._giface, grassdb, location, mapset, - backup_session, show_confirmation) + fallback_session, show_confirmation) def OnSwitchMapset(self, event): """Switch to location and mapset""" diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 7a58e161a42..43a0be61d6f 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -1132,7 +1132,7 @@ def OnChangeMapset(self, event): None, mapset) - def OnMapsetChanged(self, dbase, location, mapset, backup_session): + def OnMapsetChanged(self, dbase, location, mapset, fallback_session): """Current mapset changed. If location is None, mapset changed within location. In addition, if temporary db is not current, it deletes temporary location. @@ -1143,7 +1143,7 @@ def OnMapsetChanged(self, dbase, location, mapset, backup_session): # close current workspace and create new one self.OnWorkspaceClose() self.OnWorkspaceNew() - if backup_session: + if fallback_session: gisenv = grass.gisenv() grassdb = os.environ["TMPDIR"] location = cfg.temporary_location diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 92ed31365c8..08bcb3d94e2 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -655,7 +655,7 @@ def import_file(guiparent, filePath, env): def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, - backup_session=False, show_confirmation=False): + fallback_session=False, show_confirmation=False): """Switch current mapset. Emits giface.currentMapsetChanged signal.""" if dbase: if RunCommand('g.mapset', parent=guiparent, @@ -672,7 +672,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=dbase, location=location, mapset=mapset, - backup_session=backup_session) + fallback_session=fallback_session) elif location: if RunCommand('g.mapset', parent=guiparent, location=location, @@ -685,7 +685,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=None, location=location, mapset=mapset, - backup_session=backup_session) + fallback_session=fallback_session) else: if RunCommand('g.mapset', parent=guiparent, @@ -696,4 +696,4 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=None, location=None, mapset=mapset, - backup_session=backup_session) + fallback_session=fallback_session) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 2e1a590afad..d3d4a7321ba 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -116,10 +116,10 @@ def get_mapset_owner(mapset_path): return None -def is_backup_session(): - """Checks if a user encounters a backup GRASS session. +def is_fallback_session(): + """Checks if a user encounters a fallback GRASS session. - Returns True if a user encounters a backup session. + Returns True if a user encounters a fallback session. It occurs when a last mapset is not usable and at the same time a user is in a temporary location. """ From 8f7dc464d890a2fd64d7d3b727372a4818847916 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 01:54:41 -0500 Subject: [PATCH 32/45] small edits in grass.py --- lib/init/grass.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 23d14963a9f..4f49d9d8b86 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -586,14 +586,14 @@ def read_gisrc(filename): return kv -def write_gisrcrc(gisrcrc, gisrc, skipped_parameter=None): +def write_gisrcrc(gisrcrc, gisrc, skip_variable=None): """Reads gisrc file and write to gisrcrc""" debug("Reading %s" % gisrc) number = 0 with open(gisrc, "r") as f: lines = f.readlines() for line in lines: - if skipped_parameter in line: + if skip_variable in line: del lines[number] number += 1 with open(gisrcrc, "w") as f: @@ -1229,7 +1229,7 @@ def is_valid(self): return self.gisdbase and self.location and self.mapset -def getMapsetSettings(gisrc): +def get_mapset_settings(gisrc): """Get the settings of Location and Mapset from the gisrc file""" mapset_settings = MapsetSettings() kv = read_gisrc(gisrc) @@ -1249,8 +1249,8 @@ def load_gisrc(gisrc, gisrcrc): :returns: MapsetSettings object """ - mapset_settings = getMapsetSettings(gisrc) - if not mapset_settings.is_valid(): + mapset_settings = get_mapset_settings(gisrc) + if not mapset_settings: fatal( _( "Error reading data path information from g.gisenv.\n" @@ -1268,15 +1268,6 @@ def load_gisrc(gisrc, gisrcrc): return mapset_settings -def can_start_in_gisrc_mapset(mapset_settings, ignore_lock=False): - """Check if a mapset from a gisrc file is usable for a new session""" - from grass.grassdb.checks import can_start_in_mapset - - return can_start_in_mapset( - mapset_path=mapset_settings.full_mapset, ignore_lock=ignore_lock - ) - - # load environmental variables from grass_env_file def load_env(grass_env_file): if not os.access(grass_env_file, os.R_OK): @@ -2512,15 +2503,16 @@ def main(): # Mapset is not specified in command line arguments if not params.mapset and not params.tmp_location: # Get mapset parameters from gisrc file - mapset_settings = getMapsetSettings(gisrc) + mapset_settings = get_mapset_settings(gisrc) # Check if mapset from gisrc is usable - last_mapset_usable = can_start_in_gisrc_mapset( - mapset_settings=mapset_settings, ignore_lock=params.force_gislock_removal + from grass.grassdb.checks import can_start_in_mapset + last_mapset_usable = can_start_in_mapset( + mapset_path=mapset_settings.full_mapset, ignore_lock=params.force_gislock_removal ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: import grass.app as ga - from grass.grassdb.checks import can_start_in_mapset, is_first_time_user + from grass.grassdb.checks import is_first_time_user # Add last used mapset to gisrc add_last_mapset_to_gisrc( @@ -2539,8 +2531,10 @@ def main(): default_mapset, ) = ga.ensure_default_data_hierarchy() - if default_mapset is None: - sys.exit("Failed to start GUI, GRASS GIS is not running.") + if default_gisdbase is None: + sys.exit("Failed to start GRASS GUI, no grassdata directory found.") + elif default_location is None: + sys.exit("Failed to start GRASS GUI, no default location to copy in the installation or copying failed.") default_mapset_path = os.path.join( default_gisdbase, @@ -2720,7 +2714,7 @@ def main(): if not params.tmp_location or ( params.tmp_location and mapset_settings.gisdbase != os.environ["TMPDIR"] ): - write_gisrcrc(gisrcrc, gisrc, skipped_parameter="LAST_MAPSET_PATH") + write_gisrcrc(gisrcrc, gisrc, skip_variable="LAST_MAPSET_PATH") # After this point no more grass modules may be called # done message at last: no atexit.register() # or register done_message() From 76e32a181b9e3dc54f4d301069286d32ff546143 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 01:57:27 -0500 Subject: [PATCH 33/45] small edits in checks.py --- python/grass/grassdb/checks.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index d3d4a7321ba..a464dc31f3a 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -123,7 +123,7 @@ def is_fallback_session(): It occurs when a last mapset is not usable and at the same time a user is in a temporary location. """ - if "LAST_MAPSET_PATH" in gisenv().keys(): + if "LAST_MAPSET_PATH" in gisenv(): return is_mapset_current( os.environ["TMPDIR"], cfg.temporary_location, cfg.permanent_mapset ) @@ -138,7 +138,7 @@ def is_first_time_user(): or in current mapset settings. """ genv = gisenv() - if "LAST_MAPSET_PATH" in genv.keys(): + if "LAST_MAPSET_PATH" in genv(): if genv["LAST_MAPSET_PATH"] == os.path.join( os.getcwd(), cfg.unknown_location, cfg.unknown_mapset ): @@ -208,9 +208,6 @@ def get_reason_id_mapset_not_usable(mapset_path): Returns a reason id as a string. If mapset path is None or no reason found, returns None. """ - if not mapset_path: - return None - # Check whether mapset exists if not os.path.exists(mapset_path): return "non-existent" From 2cff0bc0d3491ce1d6ac32309b3f4ed3637ec9bc Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 02:20:38 -0500 Subject: [PATCH 34/45] wxGUI: edits in info messages --- gui/wxpython/datacatalog/catalog.py | 6 +++--- gui/wxpython/datacatalog/infomanager.py | 25 +++++++++++-------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index a243afa6eca..23d18e3f88d 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -83,7 +83,7 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.reason_id = get_reason_id_mapset_not_usable(last_mapset_path) if self.reason_id in ("non-existent", "invalid", "different-owner"): # show non-standard situation info - wx.CallLater(delay, self.showNonStandardSituationInfo) + wx.CallLater(delay, self.showFallbackSessionInfo) elif self.reason_id == "locked": # show info allowing to switch to locked mapset wx.CallLater(delay, self.showLockedMapsetInfo) @@ -107,8 +107,8 @@ def showDataStructureInfo(self): def showLockedMapsetInfo(self): self.infoManager.ShowLockedMapsetInfo(self.OnSwitchToLastUsedMapset) - def showNonStandardSituationInfo(self): - self.infoManager.ShowNonStandardSituationInfo(self.reason_id) + def showFallbackSessionInfo(self): + self.infoManager.ShowFallbackSessionInfo(self.reason_id) def showImportDataInfo(self): self.infoManager.ShowImportDataInfo(self.OnImportOgrLayers, self.OnImportGdalLayers) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index a3fb2ffbbe9..dba256a3eda 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -63,16 +63,14 @@ def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler ).format(loc=gisenv()["LOCATION_NAME"]) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) - def ShowNonStandardSituationInfo(self, reason_id): + def ShowFallbackSessionInfo(self, reason_id): """Show info when last used mapset is not usable""" string = self._text_from_reason_id(reason_id) message = _( - "{string}. GRASS GIS has started in a temporary Location {loc}. " - "To continue, find or create another location through " - "Data Catalog below." + "{string} GRASS GIS has started in a temporary Location. " + "To continue, use Data Catalog below to switch to a different Location." ).format( string=string, - loc=gisenv()["LOCATION_NAME"], ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION) @@ -81,13 +79,12 @@ def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] message = _( - "Last used mapset in path '{mapsetpath}' is locked. " - "GRASS GIS has started in a temporary Location {loc}. " - "To continue, find or create another location through " - "Data Catalog below, or remove .gislock and switch to last used mapset." + "Last used mapset in path '{mapsetpath}' is currently in use. " + "GRASS GIS has started in a temporary Location. " + "To continue, use Data Catalog below to switch to a different Location " + "or remove lock file and switch to the last used mapset." ).format( - mapsetpath=last_used_mapset_path, - loc=gisenv()["LOCATION_NAME"], + mapsetpath=last_used_mapset_path ) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) @@ -96,16 +93,16 @@ def _text_from_reason_id(self, reason_id): last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] string = None if reason_id == "non-existent": - string = "Last used mapset in path '{mapsetpath}' does not exist".format( + string = _("Last used mapset in path '{mapsetpath}' does not exist.").format( mapsetpath=last_used_mapset_path ) elif reason_id == "invalid": - string = "Last used mapset in path '{mapsetpath}' is invalid".format( + string = _("Last used mapset in path '{mapsetpath}' is invalid.").format( mapsetpath=last_used_mapset_path ) elif reason_id == "different-owner": owner = get_mapset_owner(last_used_mapset_path) - string = "Last used mapset in path '{mapsetpath}' has different owner {owner}".format( + string = _("Last used mapset in path '{mapsetpath}' has different owner {owner}.").format( owner=owner, mapsetpath=last_used_mapset_path ) return string From 7e5bb36962545049aa4e2cec2ee5e3210c4229c6 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 02:29:04 -0500 Subject: [PATCH 35/45] black applied and keys() kept in gisenv --- gui/wxpython/datacatalog/infomanager.py | 16 +++++++--------- lib/init/grass.py | 8 ++++++-- python/grass/grassdb/checks.py | 4 ++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index dba256a3eda..fdbb5532230 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -83,9 +83,7 @@ def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): "GRASS GIS has started in a temporary Location. " "To continue, use Data Catalog below to switch to a different Location " "or remove lock file and switch to the last used mapset." - ).format( - mapsetpath=last_used_mapset_path - ) + ).format(mapsetpath=last_used_mapset_path) self.infoBar.ShowMessage(message, wx.ICON_INFORMATION, buttons) def _text_from_reason_id(self, reason_id): @@ -93,18 +91,18 @@ def _text_from_reason_id(self, reason_id): last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] string = None if reason_id == "non-existent": - string = _("Last used mapset in path '{mapsetpath}' does not exist.").format( - mapsetpath=last_used_mapset_path - ) + string = _( + "Last used mapset in path '{mapsetpath}' does not exist." + ).format(mapsetpath=last_used_mapset_path) elif reason_id == "invalid": string = _("Last used mapset in path '{mapsetpath}' is invalid.").format( mapsetpath=last_used_mapset_path ) elif reason_id == "different-owner": owner = get_mapset_owner(last_used_mapset_path) - string = _("Last used mapset in path '{mapsetpath}' has different owner {owner}.").format( - owner=owner, mapsetpath=last_used_mapset_path - ) + string = _( + "Last used mapset in path '{mapsetpath}' has different owner {owner}." + ).format(owner=owner, mapsetpath=last_used_mapset_path) return string def _onLearnMore(self, event): diff --git a/lib/init/grass.py b/lib/init/grass.py index 4f49d9d8b86..f94b6d6d792 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2506,8 +2506,10 @@ def main(): mapset_settings = get_mapset_settings(gisrc) # Check if mapset from gisrc is usable from grass.grassdb.checks import can_start_in_mapset + last_mapset_usable = can_start_in_mapset( - mapset_path=mapset_settings.full_mapset, ignore_lock=params.force_gislock_removal + mapset_path=mapset_settings.full_mapset, + ignore_lock=params.force_gislock_removal, ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: @@ -2534,7 +2536,9 @@ def main(): if default_gisdbase is None: sys.exit("Failed to start GRASS GUI, no grassdata directory found.") elif default_location is None: - sys.exit("Failed to start GRASS GUI, no default location to copy in the installation or copying failed.") + sys.exit( + "Failed to start GRASS GUI, no default location to copy in the installation or copying failed." + ) default_mapset_path = os.path.join( default_gisdbase, diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index a464dc31f3a..39f66512e95 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -123,7 +123,7 @@ def is_fallback_session(): It occurs when a last mapset is not usable and at the same time a user is in a temporary location. """ - if "LAST_MAPSET_PATH" in gisenv(): + if "LAST_MAPSET_PATH" in gisenv().keys(): return is_mapset_current( os.environ["TMPDIR"], cfg.temporary_location, cfg.permanent_mapset ) @@ -138,7 +138,7 @@ def is_first_time_user(): or in current mapset settings. """ genv = gisenv() - if "LAST_MAPSET_PATH" in genv(): + if "LAST_MAPSET_PATH" in genv.keys(): if genv["LAST_MAPSET_PATH"] == os.path.join( os.getcwd(), cfg.unknown_location, cfg.unknown_mapset ): From c46803c609a6db0d5be226f5a2ffbe813843a7c5 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 05:11:20 -0500 Subject: [PATCH 36/45] The logics in grass.py was a bit simplified. --- lib/init/grass.py | 72 ++++++++++++++-------------------- python/grass/app/data.py | 20 +++++----- python/grass/grassdb/checks.py | 11 +----- 3 files changed, 43 insertions(+), 60 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index f94b6d6d792..fbf1fed5643 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -640,6 +640,18 @@ def add_last_mapset_to_gisrc(gisrc, last_mapset_path): write_gisrc(kv, gisrc) +def create_fallback_session(gisrc, tmpdir): + """Creates fallback temporary session""" + # Create temporary location + set_mapset( + gisrc=gisrc, + geofile="XY", + create_new=True, + tmp_location=True, + tmpdir=tmpdir, + ) + + def read_gui(gisrc, default_gui): grass_gui = None # At this point the GRASS user interface variable has been set from the @@ -2504,48 +2516,38 @@ def main(): if not params.mapset and not params.tmp_location: # Get mapset parameters from gisrc file mapset_settings = get_mapset_settings(gisrc) + last_mapset_path = mapset_settings.full_mapset # Check if mapset from gisrc is usable from grass.grassdb.checks import can_start_in_mapset - last_mapset_usable = can_start_in_mapset( - mapset_path=mapset_settings.full_mapset, + mapset_path=last_mapset_path, ignore_lock=params.force_gislock_removal, ) debug(f"last_mapset_usable: {last_mapset_usable}") if not last_mapset_usable: - import grass.app as ga + from grass.app import ensure_default_data_hierarchy from grass.grassdb.checks import is_first_time_user + fallback_session = False + # Add last used mapset to gisrc - add_last_mapset_to_gisrc( - gisrc, - os.path.join( - mapset_settings.gisdbase, - mapset_settings.location, - mapset_settings.mapset, - ), - ) + add_last_mapset_to_gisrc(gisrc, last_mapset_path) + if is_first_time_user(): - # Ensure default data hiearchy + # Ensure default data hierarchy ( default_gisdbase, default_location, default_mapset, - ) = ga.ensure_default_data_hierarchy() + default_mapset_path, + ) = ensure_default_data_hierarchy() - if default_gisdbase is None: + if not default_gisdbase: sys.exit("Failed to start GRASS GUI, no grassdata directory found.") - elif default_location is None: + elif not default_location: sys.exit( "Failed to start GRASS GUI, no default location to copy in the installation or copying failed." ) - - default_mapset_path = os.path.join( - default_gisdbase, - default_location, - default_mapset, - ) - # First session if can_start_in_mapset( mapset_path=default_mapset_path, ignore_lock=False ): @@ -2556,30 +2558,16 @@ def main(): location=default_location, mapset=default_mapset, ) - # Another first-time session else: - # Add last used mapset to gisrc + fallback_session = True add_last_mapset_to_gisrc(gisrc, default_mapset_path) - - # Create temporary location - params.tmp_location = True - set_mapset( - gisrc=gisrc, - geofile="XY", - create_new=True, - tmp_location=params.tmp_location, - tmpdir=tmpdir, - ) else: - # Create temporary location + fallback_session = True + + if fallback_session: + # Create fallback temporary session + create_fallback_session(gisrc, tmpdir) params.tmp_location = True - set_mapset( - gisrc=gisrc, - geofile="XY", - create_new=True, - tmp_location=params.tmp_location, - tmpdir=tmpdir, - ) else: # Write mapset info to gisrc file add_mapset_to_gisrc( diff --git a/python/grass/app/data.py b/python/grass/app/data.py index f7c573e8cc8..5f504497ce4 100644 --- a/python/grass/app/data.py +++ b/python/grass/app/data.py @@ -147,18 +147,20 @@ def ensure_default_data_hierarchy(): Creates database directory based on the default path determined according to OS if needed. Creates location if needed. - Returns the db, loc, mapset""" + Returns the db, loc, mapset, mapset_path""" - default_gisdbase = get_possible_database_path() - default_location = cfg.default_location - default_mapset = cfg.permanent_mapset + gisdbase = get_possible_database_path() + location = cfg.default_location + mapset = cfg.permanent_mapset # If nothing found, try to create GRASS directory - if not default_gisdbase: - default_gisdbase = create_database_directory() + if not gisdbase: + gisdbase = create_database_directory() - if not is_location_valid(default_gisdbase, default_location): + if not is_location_valid(gisdbase, location): # If not valid, copy startup loc - create_startup_location_in_grassdb(default_gisdbase, default_location) + create_startup_location_in_grassdb(gisdbase, location) - return default_gisdbase, default_location, default_mapset + mapset_path = os.path.join(gisdbase, location, mapset) + + return gisdbase, location, mapset, mapset_path diff --git a/python/grass/grassdb/checks.py b/python/grass/grassdb/checks.py index 39f66512e95..9b233c91bdc 100644 --- a/python/grass/grassdb/checks.py +++ b/python/grass/grassdb/checks.py @@ -139,16 +139,9 @@ def is_first_time_user(): """ genv = gisenv() if "LAST_MAPSET_PATH" in genv.keys(): - if genv["LAST_MAPSET_PATH"] == os.path.join( + return genv["LAST_MAPSET_PATH"] == os.path.join( os.getcwd(), cfg.unknown_location, cfg.unknown_mapset - ): - return True - elif ( - genv["GISDBASE"] == os.getcwd() - and genv["LOCATION_NAME"] == cfg.unknown_location - and genv["MAPSET"] == cfg.unknown_mapset - ): - return True + ) return False From 174ac9de92e4a0bf6d9787d26c727e74152acbbe Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 07:18:38 -0500 Subject: [PATCH 37/45] wxGUI: deleting tmp loc handled in switch_mapset_interactively, currentMapsetChanged connects infobar dismissing --- gui/wxpython/datacatalog/catalog.py | 6 +++++- gui/wxpython/lmgr/frame.py | 18 +----------------- gui/wxpython/startup/guiutils.py | 20 ++++++++++++++------ lib/init/grass.py | 1 + 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index 23d18e3f88d..cfb898ca51b 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -62,6 +62,7 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, # infobar for data catalog self.infoBar = InfoBar(self) + self.giface.currentMapsetChanged.connect(self.dismissInfobar) # infobar manager for data catalog self.infoManager = DataCatalogInfoManager(infobar=self.infoBar, @@ -116,6 +117,10 @@ def showImportDataInfo(self): def LoadItems(self): self.tree.ReloadTreeItems() + def dismissInfobar(self): + if self.infoBar.IsShown(): + self.infoBar.Dismiss() + def OnReloadTree(self, event): """Reload whole tree""" self.LoadItems() @@ -165,7 +170,6 @@ def OnSwitchToLastUsedMapset(self, event): last_mapset_path = gisenv()["LAST_MAPSET_PATH"] grassdb, location, mapset = split_mapset_path(last_mapset_path) self.tree.SwitchMapset(grassdb, location, mapset) - event.Skip() def OnImportGdalLayers(self, event): """Convert multiple GDAL layers to GRASS raster map layers""" diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 43a0be61d6f..53772e7b32d 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -72,8 +72,6 @@ create_location_interactively ) from grass.grassdb.checks import is_first_time_user -from grass.grassdb.manage import delete_location -import grass.grassdb.config as cfg class GMFrame(wx.Frame): @@ -1132,10 +1130,9 @@ def OnChangeMapset(self, event): None, mapset) - def OnMapsetChanged(self, dbase, location, mapset, fallback_session): + def OnMapsetChanged(self, dbase, location, mapset): """Current mapset changed. If location is None, mapset changed within location. - In addition, if temporary db is not current, it deletes temporary location. """ if not location: self._setTitle() @@ -1143,19 +1140,6 @@ def OnMapsetChanged(self, dbase, location, mapset, fallback_session): # close current workspace and create new one self.OnWorkspaceClose() self.OnWorkspaceNew() - if fallback_session: - gisenv = grass.gisenv() - grassdb = os.environ["TMPDIR"] - location = cfg.temporary_location - if not grassdb == gisenv["GISDBASE"]: - # Delete temporary location - delete_location(grassdb, location) - self._giface.grassdbChanged.emit( - location=location, grassdb=grassdb, action="delete", element="grassdb" - ) - # Hide infobar - if self.datacatalog.infoBar.IsShown(): - self.datacatalog.infoBar.Dismiss() def OnChangeCWD(self, event=None, cmd=None): """Change current working directory diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 08bcb3d94e2..4df20dd0e2c 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -31,6 +31,7 @@ get_reasons_locations_not_removable, get_reasons_grassdb_not_removable ) +import grass.grassdb.config as cfg from grass.grassdb.create import create_mapset, get_default_mapset_name from grass.grassdb.manage import ( @@ -42,6 +43,7 @@ ) from grass.script.core import create_environment from grass.script.utils import try_remove +from grass.script import gisenv from core.gcmd import GError, GMessage, RunCommand from gui_core.dialogs import TextEntryDialog @@ -671,8 +673,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, {'dbase': dbase, 'loc': location, 'mapset': mapset}) giface.currentMapsetChanged.emit(dbase=dbase, location=location, - mapset=mapset, - fallback_session=fallback_session) + mapset=mapset) elif location: if RunCommand('g.mapset', parent=guiparent, location=location, @@ -684,8 +685,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, {'loc': location, 'mapset': mapset}) giface.currentMapsetChanged.emit(dbase=None, location=location, - mapset=mapset, - fallback_session=fallback_session) + mapset=mapset) else: if RunCommand('g.mapset', parent=guiparent, @@ -695,5 +695,13 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, message=_("Current mapset is <%s>.") % mapset) giface.currentMapsetChanged.emit(dbase=None, location=None, - mapset=mapset, - fallback_session=fallback_session) + mapset=mapset) + if fallback_session: + tmp_dbase = os.environ["TMPDIR"] + tmp_loc = cfg.temporary_location + if tmp_dbase != gisenv()["GISDBASE"]: + # Delete temporary location + delete_location(tmp_dbase, tmp_loc) + giface.grassdbChanged.emit( + location=location, grassdb=tmp_dbase, action="delete", element="grassdb" + ) diff --git a/lib/init/grass.py b/lib/init/grass.py index fbf1fed5643..8d412ddd338 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2519,6 +2519,7 @@ def main(): last_mapset_path = mapset_settings.full_mapset # Check if mapset from gisrc is usable from grass.grassdb.checks import can_start_in_mapset + last_mapset_usable = can_start_in_mapset( mapset_path=last_mapset_path, ignore_lock=params.force_gislock_removal, From a8e7e11a4ff0f8de1c104ed70845b00eb53c986c Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 09:35:14 -0500 Subject: [PATCH 38/45] wxGUI: is_fallback_session moved to switch_mapset_interactively --- gui/wxpython/datacatalog/tree.py | 13 ++++--------- gui/wxpython/startup/guiutils.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 42f699ac6c7..b7726017468 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -74,8 +74,7 @@ from grass.script import gisenv from grass.grassdb.data import map_exists from grass.grassdb.checks import (get_mapset_owner, is_mapset_locked, - is_different_mapset_owner, is_first_time_user, - is_fallback_session) + is_different_mapset_owner, is_first_time_user) from grass.exceptions import CalledModuleError @@ -1498,25 +1497,21 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): """ Switch to location and mapset interactively. """ - # Decide if a user is in a fallback session - fallback_session = False - if is_fallback_session(): - fallback_session = True if can_switch_mapset_interactive(self, grassdb, location, mapset): genv = gisenv() # Switch to mapset in the same location if (grassdb == genv['GISDBASE'] and location == genv['LOCATION_NAME']): switch_mapset_interactively(self, self._giface, None, None, mapset, - fallback_session, show_confirmation) + show_confirmation) # Switch to mapset in the same grassdb elif grassdb == genv['GISDBASE']: switch_mapset_interactively(self, self._giface, None, location, mapset, - fallback_session, show_confirmation) + show_confirmation) # Switch to mapset in a different grassdb else: switch_mapset_interactively(self, self._giface, grassdb, location, mapset, - fallback_session, show_confirmation) + show_confirmation) def OnSwitchMapset(self, event): """Switch to location and mapset""" diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 4df20dd0e2c..de12b40b6aa 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -29,7 +29,8 @@ get_reasons_mapsets_not_removable, get_reasons_location_not_removable, get_reasons_locations_not_removable, - get_reasons_grassdb_not_removable + get_reasons_grassdb_not_removable, + is_fallback_session ) import grass.grassdb.config as cfg @@ -657,8 +658,13 @@ def import_file(guiparent, filePath, env): def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, - fallback_session=False, show_confirmation=False): + show_confirmation=False): """Switch current mapset. Emits giface.currentMapsetChanged signal.""" + # Decide if a user is in a fallback session + fallback_session = False + if is_fallback_session(): + fallback_session = True + if dbase: if RunCommand('g.mapset', parent=guiparent, location=location, @@ -696,6 +702,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, giface.currentMapsetChanged.emit(dbase=None, location=None, mapset=mapset) + if fallback_session: tmp_dbase = os.environ["TMPDIR"] tmp_loc = cfg.temporary_location From c320c9a8b5561ed9c93963818e6a70534164a223 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 6 Apr 2021 09:42:40 -0500 Subject: [PATCH 39/45] simplified --- gui/wxpython/startup/guiutils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index de12b40b6aa..0d3afcdc57f 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -661,9 +661,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, show_confirmation=False): """Switch current mapset. Emits giface.currentMapsetChanged signal.""" # Decide if a user is in a fallback session - fallback_session = False - if is_fallback_session(): - fallback_session = True + fallback_session = is_fallback_session() if dbase: if RunCommand('g.mapset', parent=guiparent, From 07702b06f473560855b333be90f2e435c185dad7 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 8 Apr 2021 04:34:20 -0500 Subject: [PATCH 40/45] minor edits --- gui/wxpython/datacatalog/catalog.py | 3 +-- gui/wxpython/datacatalog/infomanager.py | 10 +++++----- gui/wxpython/datacatalog/tree.py | 1 - lib/init/grass.py | 12 +++++++++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/gui/wxpython/datacatalog/catalog.py b/gui/wxpython/datacatalog/catalog.py index cfb898ca51b..ab85860f913 100644 --- a/gui/wxpython/datacatalog/catalog.py +++ b/gui/wxpython/datacatalog/catalog.py @@ -51,8 +51,6 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, Debug.msg(1, "DataCatalog.__init__()") - delay = 2000 - # toolbar self.toolbar = DataCatalogToolbar(parent=self) @@ -61,6 +59,7 @@ def __init__(self, parent, giface=None, id=wx.ID_ANY, self.tree.showNotification.connect(self.showNotification) # infobar for data catalog + delay = 2000 self.infoBar = InfoBar(self) self.giface.currentMapsetChanged.connect(self.dismissInfobar) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index fdbb5532230..115eacfacd1 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -89,21 +89,21 @@ def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): def _text_from_reason_id(self, reason_id): """ Get string for infobar message based on the reason.""" last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] - string = None + reason = None if reason_id == "non-existent": - string = _( + reason = _( "Last used mapset in path '{mapsetpath}' does not exist." ).format(mapsetpath=last_used_mapset_path) elif reason_id == "invalid": - string = _("Last used mapset in path '{mapsetpath}' is invalid.").format( + reason = _("Last used mapset in path '{mapsetpath}' is invalid.").format( mapsetpath=last_used_mapset_path ) elif reason_id == "different-owner": owner = get_mapset_owner(last_used_mapset_path) - string = _( + reason = _( "Last used mapset in path '{mapsetpath}' has different owner {owner}." ).format(owner=owner, mapsetpath=last_used_mapset_path) - return string + return reason def _onLearnMore(self, event): self._giface.Help(entry="grass_database") diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index b7726017468..2192364d3e1 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -1497,7 +1497,6 @@ def SwitchMapset(self, grassdb, location, mapset, show_confirmation=False): """ Switch to location and mapset interactively. """ - if can_switch_mapset_interactive(self, grassdb, location, mapset): genv = gisenv() # Switch to mapset in the same location diff --git a/lib/init/grass.py b/lib/init/grass.py index 8d412ddd338..c8ec258569f 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -2544,10 +2544,16 @@ def main(): ) = ensure_default_data_hierarchy() if not default_gisdbase: - sys.exit("Failed to start GRASS GUI, no grassdata directory found.") + fatal( + _( + "Failed to start GRASS GIS, grassdata directory could not be found or created." + ) + ) elif not default_location: - sys.exit( - "Failed to start GRASS GUI, no default location to copy in the installation or copying failed." + fatal( + _( + "Failed to start GRASS GIS, no default location to copy in the installation or copying failed." + ) ) if can_start_in_mapset( mapset_path=default_mapset_path, ignore_lock=False From f79f26367e3771133d4e06296b85d53ef9953f13 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 8 Apr 2021 04:41:46 -0500 Subject: [PATCH 41/45] Anna's edits --- python/grass/grassdb/manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index 2f7de52a46e..ef92c109e3e 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -50,6 +50,6 @@ def rename_location(database, old_name, new_name): def split_mapset_path(mapset_path): """Split mapset path to three parts - grassdb, location, mapset""" - path, mapset = os.path.split(mapset_path) + path, mapset = os.path.split(mapset_path.rstrip(os.sep)) grassdb, location = os.path.split(path) return grassdb, location, mapset From a80868c4dbd64bd2989cc747b881496f6d23525c Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 8 Apr 2021 05:03:17 -0500 Subject: [PATCH 42/45] wxGUI: buttons in infobars translatable --- gui/wxpython/datacatalog/infomanager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gui/wxpython/datacatalog/infomanager.py b/gui/wxpython/datacatalog/infomanager.py index 115eacfacd1..56cad9d3601 100644 --- a/gui/wxpython/datacatalog/infomanager.py +++ b/gui/wxpython/datacatalog/infomanager.py @@ -33,8 +33,8 @@ def __init__(self, infobar, giface): def ShowDataStructureInfo(self, onCreateLocationHandler): """Show info about the data hierarchy focused on the first-time user""" buttons = [ - ("Create new Location", onCreateLocationHandler), - ("Learn More", self._onLearnMore), + (_("Create new Location"), onCreateLocationHandler), + (_("Learn more"), self._onLearnMore), ] message = _( "GRASS GIS helps you organize your data using Locations (projects) " @@ -50,8 +50,8 @@ def ShowDataStructureInfo(self, onCreateLocationHandler): def ShowImportDataInfo(self, OnImportOgrLayersHandler, OnImportGdalLayersHandler): """Show info about the data import focused on the first-time user""" buttons = [ - ("Import vector data", OnImportOgrLayersHandler), - ("Import raster data", OnImportGdalLayersHandler), + (_("Import vector data"), OnImportOgrLayersHandler), + (_("Import raster data"), OnImportGdalLayersHandler), ] message = _( "You have successfully created a new Location {loc}. " @@ -77,7 +77,7 @@ def ShowFallbackSessionInfo(self, reason_id): def ShowLockedMapsetInfo(self, OnSwitchMapsetHandler): """Show info when last used mapset is locked""" last_used_mapset_path = gisenv()["LAST_MAPSET_PATH"] - buttons = [("Switch to last used mapset", OnSwitchMapsetHandler)] + buttons = [(_("Switch to last used mapset"), OnSwitchMapsetHandler)] message = _( "Last used mapset in path '{mapsetpath}' is currently in use. " "GRASS GIS has started in a temporary Location. " From 71cf651cbd462bd9d5f6e9c8fc6a80eed59d5d7b Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Mon, 12 Apr 2021 07:00:25 -0500 Subject: [PATCH 43/45] comment for removing useless grassdb node added --- gui/wxpython/startup/guiutils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index 0d3afcdc57f..f0433e33894 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -707,6 +707,7 @@ def switch_mapset_interactively(guiparent, giface, dbase, location, mapset, if tmp_dbase != gisenv()["GISDBASE"]: # Delete temporary location delete_location(tmp_dbase, tmp_loc) + # Remove useless temporary grassdb node giface.grassdbChanged.emit( location=location, grassdb=tmp_dbase, action="delete", element="grassdb" ) From e8c68077185619711bab7d6b703bb226b2038b54 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Mon, 12 Apr 2021 08:51:55 -0500 Subject: [PATCH 44/45] grass.py: not create tmp loc when --text flag, locked_mapset function now controls if mapset is valid. --- lib/init/grass.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index c8ec258569f..35c3d0ed056 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1563,8 +1563,12 @@ def lock_mapset(mapset_path, force_gislock_removal, user): Behavior on error must be changed somehow; now it fatals but GUI case is unresolved. """ + from grass.grassdb.checks import is_mapset_valid + if not os.path.exists(mapset_path): fatal(_("Path '%s' doesn't exist") % mapset_path) + if not is_mapset_valid(mapset_path): + fatal(_("Mapset in path '%s' is not valid") % mapset_path) if not os.access(mapset_path, os.W_OK): error = _("Path '%s' not accessible.") % mapset_path stat_info = os.stat(mapset_path) @@ -2572,9 +2576,12 @@ def main(): fallback_session = True if fallback_session: - # Create fallback temporary session - create_fallback_session(gisrc, tmpdir) - params.tmp_location = True + if grass_gui == "text": + pass + else: + # Create fallback temporary session + create_fallback_session(gisrc, tmpdir) + params.tmp_location = True else: # Write mapset info to gisrc file add_mapset_to_gisrc( @@ -2622,12 +2629,8 @@ def main(): force_gislock_removal=params.force_gislock_removal, ) except Exception as e: - msg = e.args[0] - if grass_gui == "wxpython": - call([os.getenv("GRASS_PYTHON"), wxpath("gis_set_error.py"), msg]) - sys.exit(_("Exiting...")) - else: - fatal(msg) + fatal(e.args[0]) + sys.exit(_("Exiting...")) # unlock the mapset which is current at the time of turning off # in case mapset was changed From 7592c4d39e363c346663d4c2278af96d0470d74d Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Mon, 12 Apr 2021 23:43:52 -0400 Subject: [PATCH 45/45] Call set_mapset in every branch (all paths should lead to the same series of checks and setup). Do not rely on some later function to do the checking, i.e., remove the additional check in lock_mapset. --- lib/init/grass.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/lib/init/grass.py b/lib/init/grass.py index 35c3d0ed056..c36788ea896 100755 --- a/lib/init/grass.py +++ b/lib/init/grass.py @@ -1567,8 +1567,6 @@ def lock_mapset(mapset_path, force_gislock_removal, user): if not os.path.exists(mapset_path): fatal(_("Path '%s' doesn't exist") % mapset_path) - if not is_mapset_valid(mapset_path): - fatal(_("Mapset in path '%s' is not valid") % mapset_path) if not os.access(mapset_path, os.W_OK): error = _("Path '%s' not accessible.") % mapset_path stat_info = os.stat(mapset_path) @@ -2543,7 +2541,7 @@ def main(): ( default_gisdbase, default_location, - default_mapset, + unused_default_mapset, default_mapset_path, ) = ensure_default_data_hierarchy() @@ -2562,13 +2560,8 @@ def main(): if can_start_in_mapset( mapset_path=default_mapset_path, ignore_lock=False ): - # Write mapset info to gisrc file - add_mapset_to_gisrc( - gisrc=gisrc, - grassdb=default_gisdbase, - location=default_location, - mapset=default_mapset, - ) + # Use the default location/mapset. + set_mapset(gisrc=gisrc, arg=default_mapset_path) else: fallback_session = True add_last_mapset_to_gisrc(gisrc, default_mapset_path) @@ -2577,19 +2570,15 @@ def main(): if fallback_session: if grass_gui == "text": - pass + # Fallback in command line is just failing in a standard way. + set_mapset(gisrc=gisrc, arg=last_mapset_path) else: # Create fallback temporary session create_fallback_session(gisrc, tmpdir) params.tmp_location = True else: - # Write mapset info to gisrc file - add_mapset_to_gisrc( - gisrc=gisrc, - grassdb=mapset_settings.gisdbase, - location=mapset_settings.location, - mapset=mapset_settings.mapset, - ) + # Use the last used mapset. + set_mapset(gisrc=gisrc, arg=last_mapset_path) else: # Mapset was specified in command line parameters. if params.tmp_location: