Skip to content

build: refactor grass.py in preparation for FHS #5933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ else()
endif()
endif()

# For install tree (first do install tree)
set(LD_LIBRARY_PATH_VAR "LD_LIBRARY_PATH")
if(APPLE)
set(LD_LIBRARY_PATH_VAR "LD_RUN_PATH")
elseif(WIN32)
set(LD_LIBRARY_PATH_VAR "PATH")
endif()

# Graphics options
option(WITH_X11 "Build with X11 support" ${x11_default_option_enabled})
option(WITH_OPENGL "Build with OpenGL support" ON)
Expand Down Expand Up @@ -188,9 +196,6 @@ if(WITH_FHS)
${RUNTIME_GISBASE}/etc/renamed_options SYMBOLIC)
file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_ETCDIR}/VERSIONNUMBER
${RUNTIME_GISBASE}/etc/VERSIONNUMBER SYMBOLIC)
file(MAKE_DIRECTORY "${GISBASE}/gui/wxpython")
file(CREATE_LINK ${OUTDIR}/${GRASS_INSTALL_GUIDIR}/wxpython/xml
${RUNTIME_GISBASE}/gui/wxpython/xml SYMBOLIC)
endif()

include(set_compiler_flags)
Expand Down
14 changes: 12 additions & 2 deletions cmake/modules/GRASSInstallDirs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ set(GISBASE ${CMAKE_INSTALL_PREFIX}/${GISBASE_DIR})
set(RUNTIME_GISBASE "${OUTDIR}/${GISBASE_DIR}")
set(GISRC_NAME ".grassrc${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}")

if(WITH_FHS)
file(TO_NATIVE_PATH "${GRASS_INSTALL_PYDIR}" GRASS_INSTALL_PYDIR_PATH)
file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_PYDIR}" GRASS_INSTALL_PYDIR_RUNTIME_PATH)
else()
file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}/${GRASS_INSTALL_PYDIR}" GRASS_INSTALL_PYDIR_PATH)
file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_PYDIR}" GRASS_INSTALL_PYDIR_RUNTIME_PATH)
endif()
message(STATUS "GRASS_INSTALL_PYDIR_PATH ${GRASS_INSTALL_PYDIR_PATH}")
message(STATUS "GRASS_INSTALL_PYDIR_RUNTIME_PATH ${GRASS_INSTALL_PYDIR_RUNTIME_PATH}")

file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}" MODULE_TOPDIR)
file(TO_NATIVE_PATH "${RUNTIME_GISBASE}" RUN_GISBASE_NATIVE)
file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_BINDIR}" BIN_DIR)
Expand All @@ -93,8 +103,8 @@ file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_DEMODIR}/${GISRC_NAME}" GISRC)
file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_PYDIR}" ETC_PYTHON_DIR)
file(TO_NATIVE_PATH "${OUTDIR}/${GRASS_INSTALL_GUIDIR}/wxpython"
GUI_WXPYTHON_DIR)
message("GISBASE ${GISBASE}")
message("GISBASE_NATIVE ${RUN_GISBASE_NATIVE}")
message(STATUS "GISBASE ${GISBASE}")
message(STATUS "GISBASE_NATIVE ${RUN_GISBASE_NATIVE}")

message("Creating directories in ${GISBASE}")
file(MAKE_DIRECTORY "${OUTDIR}/${GRASS_INSTALL_BINDIR}")
Expand Down
5 changes: 4 additions & 1 deletion cmake/modules/copy_python_files_in_subdir.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ SPDX-License-Identifier: GPL-2.0-or-later
#]]

function(copy_python_files_in_subdir dir_name dst_prefix)
cmake_parse_arguments(G "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET" "" ${ARGN})
cmake_parse_arguments(G "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET" "EXCLUDE" ${ARGN})

file(GLOB PY_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${dir_name}/*.py")
foreach(exclude_file ${G_EXCLUDE})
list(FILTER PY_FILES EXCLUDE REGEX ".*/${exclude_file}")
endforeach()

if(DEFINED G_TARGET)
if(${G_PRE_BUILD})
Expand Down
23 changes: 20 additions & 3 deletions include/Make/Install.make
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,18 @@ FONTCAP = etc/fontcap
TMPGISRC = demolocation/.grassrc$(GRASS_VERSION_MAJOR)$(GRASS_VERSION_MINOR)
PLATMAKE = include/Make/Platform.make
GRASSMAKE = include/Make/Grass.make
RESOURCE_PATHS = etc/python/grass/app/resource_paths.py

real-install: | $(DESTDIR) $(DESTDIR)$(INST_DIR) $(DESTDIR)$(UNIX_BIN)
-tar cBCf $(GISBASE) - . | tar xBCf $(DESTDIR)$(INST_DIR) - 2>/dev/null
-rm $(DESTDIR)$(INST_DIR)/$(GRASS_NAME).tmp
-rm $(DESTDIR)$(INST_DIR)/$(RESOURCE_PATHS)
$(MAKE) $(STARTUP)

-rm $(DESTDIR)$(INST_DIR)/resource_paths.py
-rm $(DESTDIR)$(INST_DIR)/$(RESOURCE_PATHS)
$(MAKE) $(DESTDIR)$(INST_DIR)/$(RESOURCE_PATHS)

-rm $(DESTDIR)$(INST_DIR)/$(FONTCAP)
$(MAKE) $(DESTDIR)$(INST_DIR)/$(FONTCAP)

Expand All @@ -122,12 +128,23 @@ $(DESTDIR)$(INST_DIR) $(DESTDIR)$(UNIX_BIN):
$(MAKE_DIR_CMD) $@

$(STARTUP): $(ARCH_DISTDIR)/$(GRASS_NAME).tmp
sed -e 's#'@GISBASE_INSTALL_PATH@'#'$(INST_DIR)'#g' \
-e 's#'@LD_LIBRARY_PATH_VAR@'#'$(LD_LIBRARY_PATH_VAR)'#g' \
-e 's#'@CONFIG_PROJSHARE@'#'$(PROJSHARE)'#g' \
sed -e 's#'@GRASS_PYDIR@'#'$(INST_DIR)/etc/python'#g' \
$< > $@
-$(CHMOD) a+x $@

$(DESTDIR)$(INST_DIR)/$(RESOURCE_PATHS): $(ARCH_DISTDIR)/resource_paths.py
sed \
-e 's#'@CONFIG_PROJSHARE@'#$(PROJSHARE)#' \
-e 's#'@GISBASE_INSTALL_PATH@'##' \
-e 's#'@GRASS_PREFIX@'#$(INST_DIR)#' \
-e 's#'@GRASS_VERSION_GIT@'#$(GRASS_VERSION_GIT)#' \
-e 's#'@GRASS_VERSION_MAJOR@'#$(GRASS_VERSION_MAJOR)#' \
-e 's#'@GRASS_VERSION_MINOR@'#$(GRASS_VERSION_MINOR)#' \
-e 's#'@GRASS_VERSION_NUMBER@'#$(GRASS_VERSION_NUMBER)#' \
-e 's#'@LD_LIBRARY_PATH_VAR@'#$(LD_LIBRARY_PATH_VAR)#' \
-e 's#'@START_UP@'#$(GRASS_NAME)#' \
$< > $@

define fix_gisbase
sed -e 's#$(GISBASE)#$(INST_DIR)#g' $< > $@
endef
Expand Down
32 changes: 4 additions & 28 deletions lib/init/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if(WITH_DOCS)
endif()

# START_UP is the variable used in grass.py, grass.sh.in and grass.bat.in
set(START_UP "grass")
set(START_UP ${PROJECT_NAME_LOWER})
if(WIN32)
set(START_UP "${START_UP}.py")
set(script_file_name "grass.bat")
Expand All @@ -21,21 +21,6 @@ else()
set(script_input_file_name ${script_file_name}.sh.in)
endif()

file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR}/bin BINARY_DIR)
set(CONFIG_PROJSHARE)
get_filename_component(PROJ_INSTALL_PREFIX ${PROJ_INCLUDE_DIRS} PATH)
if(DEFINED ENV{PROJSHARE})
message(WARNING "External PROJ directory not specified; default will be used")
set(CONFIG_PROJSHARE "$ENV{PROJSHARE}")
else()
set(CONFIG_PROJSHARE "${PROJ_INSTALL_PREFIX}/share/proj")
if(EXISTS ${CONFIG_PROJSHARE}/epsg)
message(STATUS "PROJ directory ${CONFIG_PROJSHARE}")
endif()
endif()
file(TO_NATIVE_PATH "${PROJ_INSTALL_PREFIX}/share/proj" PROJ_LIB)
file(TO_NATIVE_PATH ${CONFIG_PROJSHARE} GRASS_PROJSHARE)

find_path(gdal_share_dir "gdal" PATH_SUFFIXES share)
if(NOT gdal_share_dir)
message(FATAL_ERROR "Cannot find share/gdal")
Expand All @@ -49,22 +34,13 @@ get_filename_component(GDAL_DIR ${GDAL_DIR} PATH)
file(TO_NATIVE_PATH ${GDAL_DIR}/bin DEPS_DLL_PATH)
list(APPEND DLL_PATH_LIST ${DEPS_DLL_PATH})

# For install tree (first do install tree)
set(LD_LIBRARY_PATH_VAR "LD_LIBRARY_PATH")

if(APPLE)
set(LD_LIBRARY_PATH_VAR "LD_RUN_PATH")
elseif(WIN32)
set(LD_LIBRARY_PATH_VAR "PATH")
endif()

# configure and install grass.py
set(GISBASE_INSTALL_PATH ${RUNTIME_GISBASE})
set(GRASS_PYDIR ${GRASS_INSTALL_PYDIR_RUNTIME_PATH})
configure_file(grass.py ${OUTDIR}/${CMAKE_INSTALL_BINDIR}/${START_UP} @ONLY)

set(GISBASE_INSTALL_PATH ${GISBASE})
set(GRASS_PYDIR ${GRASS_INSTALL_PYDIR_PATH})
configure_file(grass.py ${CMAKE_CURRENT_BINARY_DIR}/${START_UP} @ONLY)
unset(GISBASE_INSTALL_PATH)
unset(GRASS_PYDIR)

install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${START_UP}
DESTINATION ${CMAKE_INSTALL_BINDIR})
Expand Down
11 changes: 2 additions & 9 deletions lib/init/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ include $(MODULE_TOPDIR)/include/Make/Compile.make
#for i18N support
PACKAGE ="grasslibs"

START_UP=grass
START_UP=$(GRASS_NAME)

EXTRA_CFLAGS = \
-DD_LOCATION_NAME=\"$(DEFAULT_LOCATION)\" \
Expand Down Expand Up @@ -69,14 +69,7 @@ $(ARCH_BINDIR)/$(START_UP): grass.py
endif
rm -f $@
sed \
-e 's#@GISBASE_INSTALL_PATH@#$(RUN_GISBASE)#' \
-e 's#@GRASS_VERSION_NUMBER@#$(GRASS_VERSION_NUMBER)#' \
-e 's#@GRASS_VERSION_MAJOR@#$(GRASS_VERSION_MAJOR)#' \
-e 's#@GRASS_VERSION_MINOR@#$(GRASS_VERSION_MINOR)#' \
-e 's#@GRASS_VERSION_GIT@#$(GRASS_VERSION_GIT)#' \
-e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \
-e 's#@START_UP@#$(START_UP)#' \
-e 's#@CONFIG_PROJSHARE@#$(PROJSHARE)#' \
-e 's#@GRASS_PYDIR@#$(RUN_GISBASE)/etc/python#' \
$< > $@
chmod +x $@

Expand Down
73 changes: 43 additions & 30 deletions lib/init/grass.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
# for wxpath
_WXPYTHON_BASE = None

GISBASE = None

try:
# Python >= 3.11
ENCODING = locale.getencoding()
Expand All @@ -80,32 +82,13 @@
ENCODING = "UTF-8"
print("Default locale not found, using UTF-8") # intentionally not translatable

# The "@...@" variables are being substituted during build process
#
# TODO: should GISBASE be renamed to something like GRASS_PATH?
# GISBASE marks complete runtime, so no need to get it here when
# setting it up, possible scenario: existing runtime and starting
# GRASS in that, we want to overwrite the settings, not to take it
# possibly same for GRASS_PROJSHARE and others but maybe not
#
# We need to simultaneously make sure that:
# - we get GISBASE from os.environ if it is defined (doesn't this mean that we are
# already inside a GRASS session? If we are, why do we need to run this script
# again???).
# - GISBASE exists as an ENV variable
#
# pmav99: Ugly as hell, but that's what the code before the refactoring was doing.
if "GISBASE" in os.environ and len(os.getenv("GISBASE")) > 0:
GISBASE = os.path.normpath(os.environ["GISBASE"])
else:
GISBASE = os.path.normpath("@GISBASE_INSTALL_PATH@")
os.environ["GISBASE"] = GISBASE
CMD_NAME = "@START_UP@"
GRASS_VERSION = "@GRASS_VERSION_NUMBER@"
GRASS_VERSION_MAJOR = "@GRASS_VERSION_MAJOR@"
GRASS_VERSION_MINOR = "@GRASS_VERSION_MINOR@"
LD_LIBRARY_PATH_VAR = "@LD_LIBRARY_PATH_VAR@"
CONFIG_PROJSHARE = os.environ.get("GRASS_PROJSHARE", "@CONFIG_PROJSHARE@")
CMD_NAME = None
GRASS_VERSION = None
GRASS_VERSION_MAJOR = None
GRASS_VERSION_MINOR = None
LD_LIBRARY_PATH_VAR = None
CONFIG_PROJSHARE = None
GRASS_VERSION_GIT = None

# Get the system name
WINDOWS = sys.platform.startswith("win")
Expand Down Expand Up @@ -1842,7 +1825,7 @@ def print_params(params) -> None:
val = grep("CC", linesplat)
sys.stdout.write("%s\n" % val[0].split("=")[1].strip())
elif arg == "revision":
sys.stdout.write("@GRASS_VERSION_GIT@\n")
sys.stdout.write(f"{GRASS_VERSION_GIT}\n")
elif arg == "svn_revision":
with open(gpath("etc", "VERSIONNUMBER")) as filerev:
linerev = filerev.readline().rstrip("\n")
Expand Down Expand Up @@ -2103,9 +2086,16 @@ def validate_cmdline(params: Parameters) -> None:

def find_grass_python_package() -> None:
"""Find path to grass package and add it to path"""
if os.path.exists(gpath("etc", "python")):
path_to_package = gpath("etc", "python")
sys.path.append(path_to_package)

# The "@...@" variables are being substituted during build process

if "GRASS_PYDIR" in os.environ and len(os.getenv("GRASS_PYDIR")) > 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure when len(os.getenv("GRASS_PYDIR")) > 0 is different from os.getenv("GRASS_PYDIR"), but if it is the same, Ruff or something will tell us.

GRASS_PYDIR = os.path.normpath(os.environ["GRASS_PYDIR"])
else:
GRASS_PYDIR = os.path.normpath("@GRASS_PYDIR@")

if os.path.exists(GRASS_PYDIR):
sys.path.append(GRASS_PYDIR)
# now we can import stuff from grass package
else:
# Not translatable because we don't have translations loaded.
Expand All @@ -2126,6 +2116,29 @@ def main() -> None:
# Subsequent functions are using _() calls and
# thus must be called only after Language has been set.
find_grass_python_package()

from grass.app.runtime import RuntimePaths

global \
CMD_NAME, \
GRASS_VERSION, \
GRASS_VERSION_MAJOR, \
GRASS_VERSION_MINOR, \
LD_LIBRARY_PATH_VAR, \
GRASS_VERSION_GIT, \
GISBASE, \
CONFIG_PROJSHARE

runtime_paths = RuntimePaths()
CMD_NAME = runtime_paths.grass_exe_name
GRASS_VERSION = runtime_paths.version
GRASS_VERSION_MAJOR = runtime_paths.version_major
GRASS_VERSION_MINOR = runtime_paths.version_minor
LD_LIBRARY_PATH_VAR = runtime_paths.ld_library_path_var
GRASS_VERSION_GIT = runtime_paths.grass_version_git
GISBASE = runtime_paths.gisbase
CONFIG_PROJSHARE = runtime_paths.config_projshare

grass_config_dir = create_grass_config_dir()
set_language(grass_config_dir)

Expand Down
37 changes: 34 additions & 3 deletions python/grass/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
set(PYDIRS
app
benchmark
exceptions
grassdb
Expand Down Expand Up @@ -28,12 +27,41 @@ set(PYDIR_GRASS ${GRASS_INSTALL_PYDIR}/grass)
foreach(pydir ${PYDIRS})
copy_python_files_in_subdir(${pydir} ${PYDIR_GRASS})
endforeach()
copy_python_files_in_subdir(app ${PYDIR_GRASS} EXCLUDE resource_paths.py)

configure_file(__init__.py ${OUTDIR}/${PYDIR_GRASS}/ COPYONLY)
configure_file(script/setup.py ${OUTDIR}/${PYDIR_GRASS}/script/setup.py
COPYONLY)

set(pydir_targets ${PYDIRS})

file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR}/bin BINARY_DIR)
set(CONFIG_PROJSHARE)
get_filename_component(PROJ_INSTALL_PREFIX ${PROJ_INCLUDE_DIRS} PATH)
if(DEFINED ENV{PROJSHARE})
message(WARNING "External PROJ directory not specified; default will be used")
set(CONFIG_PROJSHARE "$ENV{PROJSHARE}")
else()
set(CONFIG_PROJSHARE "${PROJ_INSTALL_PREFIX}/share/proj")
if(EXISTS ${CONFIG_PROJSHARE}/epsg)
message(STATUS "PROJ directory ${CONFIG_PROJSHARE}")
endif()
endif()
file(TO_NATIVE_PATH "${PROJ_INSTALL_PREFIX}/share/proj" PROJ_LIB)
file(TO_NATIVE_PATH ${CONFIG_PROJSHARE} GRASS_PROJSHARE)

# configure and install resource_paths.py
set(GRASS_PREFIX ${OUTDIR})
set(GISBASE_INSTALL_PATH ${GISBASE_DIR})
set(START_UP ${PROJECT_NAME_LOWER})
configure_file(app/resource_paths.py ${OUTDIR}/${PYDIR_GRASS}/app/resource_paths.py @ONLY)

set(GRASS_PREFIX ${CMAKE_INSTALL_PREFIX})
configure_file(app/resource_paths.py ${CMAKE_CURRENT_BINARY_DIR}/resource_paths.py @ONLY)
unset(GISBASE_INSTALL_PATH)
unset(GRASS_PREFIX)
unset(START_UP)

set(pydir_targets ${PYDIRS} app)
list(TRANSFORM pydir_targets REPLACE "/" "_")
list(TRANSFORM pydir_targets PREPEND "python_")

Expand All @@ -44,4 +72,7 @@ add_custom_target(

set_target_properties(LIB_PYTHON PROPERTIES FOLDER lib)

install(DIRECTORY ${OUTDIR}/${PYDIR_GRASS} DESTINATION ${GRASS_INSTALL_PYDIR})
install(DIRECTORY ${OUTDIR}/${PYDIR_GRASS} DESTINATION ${GRASS_INSTALL_PYDIR}
PATTERN "*/resource_paths.py" EXCLUDE)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/resource_paths.py
DESTINATION ${GRASS_INSTALL_PYDIR}/grass/app)
21 changes: 20 additions & 1 deletion python/grass/app/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,26 @@ MODULES = \
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)

default: $(PYFILES) $(PYCFILES)
PYFILES := $(filter-out resource_paths.py,$(PYFILES))

default: $(PYFILES) $(PYCFILES) $(DSTDIR)/resource_paths.py $(ARCH_DISTDIR)/resource_paths.py

$(DSTDIR)/resource_paths.py: resource_paths.py
rm -f $@
sed \
-e 's#@CONFIG_PROJSHARE@#$(PROJSHARE)#' \
-e 's#@GISBASE_INSTALL_PATH@##' \
-e 's#@GRASS_PREFIX@#$(RUN_GISBASE)#' \
-e 's#@GRASS_VERSION_GIT@#$(GRASS_VERSION_GIT)#' \
-e 's#@GRASS_VERSION_MAJOR@#$(GRASS_VERSION_MAJOR)#' \
-e 's#@GRASS_VERSION_MINOR@#$(GRASS_VERSION_MINOR)#' \
-e 's#@GRASS_VERSION_NUMBER@#$(GRASS_VERSION_NUMBER)#' \
-e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \
-e 's#@START_UP@#$(GRASS_NAME)#' \
$< > $@

$(ARCH_DISTDIR)/resource_paths.py:
cp resource_paths.py $@

$(DSTDIR):
$(MKDIR) $@
Expand Down
Loading
Loading