Merge pull request #20516 from natefoo/web-client-static-fixes

[25.0] Fixes for static handling and the web_client package
This commit is contained in:
Marius van den Beek
2025-06-19 11:18:23 +02:00
committed by GitHub
6 changed files with 137 additions and 122 deletions
+30 -33
View File
@@ -2502,9 +2502,9 @@
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
it via a proxy server. You can use these paths (or ones in the
proxy server) to point to your own styles. The static_* options
that refer to paths are relative to the current working directory.
:Default: ``true``
:Type: bool
@@ -2514,10 +2514,8 @@
~~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
Value of cache time for static content served by Galaxy. Ignored
if static_enabled is false.
:Default: ``360``
:Type: int
@@ -2527,24 +2525,32 @@
~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
Path to the static content dir. Ignored if static_enabled is
false.
:Default: ``static/``
:Type: str
~~~~~~~~~~~~~~~~~~~
``static_dist_dir``
~~~~~~~~~~~~~~~~~~~
:Description:
Path to the built Galaxy client application, static/dist/ in the
Galaxy source code after the build is complete. Ignored if
static_enabled is false.
:Default: ``static/dist/``
:Type: str
~~~~~~~~~~~~~~~~~~~~~
``static_images_dir``
~~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
:Default: ``static/images``
Path to the static images directory. Ignored if static_enabled is
false.
:Default: ``static/images/``
:Type: str
@@ -2553,10 +2559,8 @@
~~~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
Path to favicon.ico, not the directory that contains it (the name
is a misnomer). Ignored if static_enabled is false.
:Default: ``static/favicon.ico``
:Type: str
@@ -2566,10 +2570,8 @@
~~~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
Path to the static scripts directory. Ignored if static_enabled is
false.
:Default: ``static/scripts/``
:Type: str
@@ -2579,11 +2581,9 @@
~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
:Default: ``static/style``
Path to the static style directory. Ignored if static_enabled is
false.
:Default: ``static/style/``
:Type: str
@@ -2592,10 +2592,7 @@
~~~~~~~~~~~~~~~~~~~~~
:Description:
Serve static content, which must be enabled if you're not serving
it via a proxy server. These options should be self explanatory
and so are not documented individually. You can use these paths
(or ones in the proxy server) to point to your own styles.
Path to robots.txt. Ignored if static_enabled is false.
:Default: ``static/robots.txt``
:Type: str
+22 -33
View File
@@ -1533,51 +1533,40 @@ galaxy:
#terms_url: null
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# via a proxy server. You can use these paths (or ones in the proxy
# server) to point to your own styles. The static_* options that refer
# to paths are relative to the current working directory.
#static_enabled: true
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# Value of cache time for static content served by Galaxy. Ignored if
# static_enabled is false.
#static_cache_time: 360
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# Path to the static content dir. Ignored if static_enabled is false.
#static_dir: static/
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
#static_images_dir: static/images
# Path to the built Galaxy client application, static/dist/ in the
# Galaxy source code after the build is complete. Ignored if
# static_enabled is false.
#static_dist_dir: static/dist/
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# Path to the static images directory. Ignored if static_enabled is
# false.
#static_images_dir: static/images/
# Path to favicon.ico, not the directory that contains it (the name is
# a misnomer). Ignored if static_enabled is false.
#static_favicon_dir: static/favicon.ico
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# Path to the static scripts directory. Ignored if static_enabled is
# false.
#static_scripts_dir: static/scripts/
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
#static_style_dir: static/style
# Path to the static style directory. Ignored if static_enabled is
# false.
#static_style_dir: static/style/
# Serve static content, which must be enabled if you're not serving it
# via a proxy server. These options should be self explanatory and so
# are not documented individually. You can use these paths (or ones
# in the proxy server) to point to your own styles.
# Path to robots.txt. Ignored if static_enabled is false.
#static_robots_txt: static/robots.txt
# Incremental Display Options
+24 -34
View File
@@ -1866,19 +1866,17 @@ mapping:
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
proxy server. You can use these paths (or ones in the proxy server) to point to
your own styles. The static_* options that refer to paths are relative to the
current working directory.
static_cache_time:
type: int
default: 360
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Value of cache time for static content served by Galaxy. Ignored if
static_enabled is false.
static_dir:
type: str
@@ -1886,21 +1884,24 @@ mapping:
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to the static content dir. Ignored if static_enabled is false.
static_images_dir:
static_dist_dir:
type: str
default: static/images
default: static/dist/
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to the built Galaxy client application, static/dist/ in the Galaxy source
code after the build is complete. Ignored if static_enabled is false.
static_images_dir:
type: str
default: static/images/
per_host: true
required: false
desc: |
Path to the static images directory. Ignored if static_enabled is false.
static_favicon_dir:
type: str
@@ -1908,10 +1909,8 @@ mapping:
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to favicon.ico, not the directory that contains it (the name is a
misnomer). Ignored if static_enabled is false.
static_scripts_dir:
type: str
@@ -1919,21 +1918,15 @@ mapping:
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to the static scripts directory. Ignored if static_enabled is false.
static_style_dir:
type: str
default: static/style
default: static/style/
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to the static style directory. Ignored if static_enabled is false.
static_robots_txt:
type: str
@@ -1941,10 +1934,7 @@ mapping:
per_host: true
required: false
desc: |
Serve static content, which must be enabled if you're not serving it via a
proxy server. These options should be self explanatory and so are not
documented individually. You can use these paths (or ones in the proxy
server) to point to your own styles.
Path to robots.txt. Ignored if static_enabled is false.
display_chunk_size:
type: int
+7 -5
View File
@@ -66,9 +66,9 @@ from galaxy.web.framework.middleware.static import CacheableStaticURLParser as S
try:
import galaxy.web_client
default_static_dir = os.path.dirname(galaxy.web_client.__file__)
default_static_dist_dir = os.path.join(os.path.dirname(galaxy.web_client.__file__), "dist")
except ImportError:
default_static_dir = "static/"
default_static_dist_dir = None # type: ignore[assignment]
log = logging.getLogger(__name__)
@@ -1160,17 +1160,19 @@ def build_url_map(app, global_conf, **local_conf):
return Static(config_val, cache_time, directory_per_host=per_host_config)
# Define static mappings from config
static_dir = get_static_from_config("static_dir", default_static_dir)
static_dir = get_static_from_config("static_dir", "static/")
static_dir_bare = static_dir.directory.rstrip("/")
static_dist_dir = get_static_from_config("static_dist_dir", default_static_dist_dir or f"{static_dir_bare}/dist/")
urlmap["/static"] = static_dir
urlmap["/static/dist"] = static_dist_dir
urlmap["/images"] = get_static_from_config("static_images_dir", f"{static_dir_bare}/images")
urlmap["/static/scripts"] = get_static_from_config("static_scripts_dir", f"{static_dir_bare}/scripts/")
urlmap["/static/welcome.html"] = get_static_from_config(
"static_welcome_html", f"{static_dir_bare}/welcome.html", sample=default_url_path("static/welcome.sample.html")
)
urlmap["/static/favicon.svg"] = get_static_from_config(
"static_favicon_dir", f"{static_dir_bare}/favicon.svg", sample=default_url_path("static/favicon.svg")
urlmap["/favicon.ico"] = get_static_from_config(
"static_favicon_dir", f"{static_dir_bare}/favicon.ico", sample=default_url_path("static/favicon.ico")
)
urlmap["/robots.txt"] = get_static_from_config(
"static_robots_txt", f"{static_dir_bare}/robots.txt", sample=default_url_path("static/robots.txt")
@@ -24,7 +24,24 @@ The --mode option specifies how the web client is installed:
Copy the Galaxy web client to DEST
"""
CLIENT = os.path.join(os.path.dirname(__file__))
TARGETS = {
"dist": os.path.join(os.path.dirname(__file__), "dist"),
}
try:
import galaxy.webapps.base
STATIC = os.path.join(os.path.dirname(galaxy.webapps.base.__file__), "static")
TARGETS.update({
"style": os.path.join(STATIC, "style"),
"favicon.ico": os.path.join(STATIC, "favicon.ico"),
"favicon.svg": os.path.join(STATIC, "favicon.svg"),
"robots.txt": os.path.join(STATIC, "robots.txt"),
"welcome.sample.html": os.path.join(STATIC, "welcome.sample.html"),
})
except ImportError:
# Consider this a soft fail, this package depends on nothing but is probably installed with galaxy-web-apps
pass
def main(argv=None):
@@ -32,12 +49,15 @@ def main(argv=None):
argv = sys.argv[1:]
args = _arg_parser().parse_args(argv)
dist = os.path.join(CLIENT, "dist")
assert os.path.exists(dist), f"ERROR: Cannot find web client at expected path: {dist}"
if args.mode in ("absolute", "relative"):
_symlink(args.dest, args.mode == "absolute", args.force_overwrite)
elif args.mode == "copy":
_copy(args.dest, args.force_overwrite)
assert os.path.exists(TARGETS["dist"]), f"ERROR: Cannot find web client at expected path: {TARGETS['dist']}"
_try(functools.partial(os.makedirs, args.dest), args.dest, args.force_overwrite, dir_ok=True)
for dest, target in TARGETS.items():
dest = os.path.join(args.dest, dest)
if args.mode in ("absolute", "relative"):
_symlink(dest, target, args.mode == "absolute", args.force_overwrite)
elif args.mode == "copy":
_copy(dest, target, args.force_overwrite)
def _arg_parser():
@@ -51,30 +71,47 @@ def _arg_parser():
return parser
def _symlink(dest, absolute, force):
def _symlink(dest, target, absolute, force):
if absolute:
target = os.path.abspath(CLIENT)
target = os.path.abspath(target)
else:
target = os.path.relpath(CLIENT, start=dest)
_try(functools.partial(os.symlink, target, dest), dest, force)
target = os.path.relpath(target, start=os.path.dirname(dest))
if _try(functools.partial(os.symlink, target, dest), dest, force, target=target):
print(f"link: {dest} -> {target}")
def _copy(dest, force):
_try(functools.partial(shutil.copytree, CLIENT, dest, dirs_exist_ok=False), dest, force)
def _copy(dest, target, force):
if os.path.isdir(target):
f = functools.partial(shutil.copytree, target, dest, dirs_exist_ok=False)
else:
f = functools.partial(_copy2, target, dest)
if _try(f, dest, force):
print(f"copy: {target} -> {dest}")
def _try(f, dest, force):
def _copy2(target, dest):
if os.path.exists(dest):
raise FileExistsError(dest)
shutil.copy2(target, dest)
def _try(f, dest, force, target=None, dir_ok=False):
try:
f()
except FileExistsError:
except (FileExistsError, shutil.SameFileError):
if dir_ok and os.path.isdir(dest) and not os.path.islink(dest):
return True
if target and os.path.islink(dest) and os.readlink(dest) == target:
return True
if not force:
print(f"ERROR: File exists, use --force-overwrite to overwrite: {dest}")
sys.exit(1)
return False
if os.path.isdir(dest) and not os.path.islink(dest):
shutil.rmtree(dest)
else:
os.unlink(dest)
f()
return True
if __name__ == "__main__":
+1 -1
View File
@@ -27,7 +27,7 @@ long_description = file: README.rst, HISTORY.rst
long_description_content_type = text/x-rst
name = galaxy-web-client
url = https://github.com/galaxyproject/galaxy
version = 25.0.dev0
version = 25.0.1.dev0
[options]
include_package_data = True