Skip to content

Commit

Permalink
DEV - Update conda-store build hook (#872)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: gabalafou <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Sep 11, 2024
1 parent 97dccd4 commit 13c7b79
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
license that can be found in the LICENSE file.
-->

<!-- Note we do not modify the main.js file directly anymore. Instead we leverage
the use of runtime configuration through condaStoreConfig per
https://conda.store/conda-store-ui/how-tos/configure-ui -->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>conda-store</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
var GLOBAL_CONDA_STORE_STATE = {
var condaStoreConfig = {
NODE_DEBUG: null,
REACT_APP_CONTEXT: "single-page-app", // not a true setting
REACT_APP_AUTH_METHOD: "cookie",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-2" role="navigation">
<a class="navbar-brand" href="{{ url_for('ui_list_environments') }}">
{% if logo is defined %}
<img height="30" src="{{ logo }}"/>
<img height="60" src="{{ logo }}"/>
{% else %}
conda-store
{% endif %}
Expand Down
136 changes: 96 additions & 40 deletions conda-store-server/hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,93 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

import pathlib
import re
# Custom hook to build conda-store-server with a local or released version of conda-store-ui.
# To build with a released version of conda-store-ui: make sure to set the CONDA_STORE_UI_VERSION to a valid release
# version in npm.
# Then run `hatch build` to build conda-store-server with the specified version of conda-store-ui.
# To build with a local version of conda-store-ui: set the LOCAL_UI environment variable to the path of the local conda-store-ui directory.
# For example: export LOCAL_UI=<local path for conda-store-ui> && hatch build --clean

import os
import shutil
import tarfile
import tempfile
import urllib.request

from pathlib import Path
from typing import Any, Dict, List

from hatchling.builders.hooks.plugin.interface import BuildHookInterface


CONDA_STORE_UI_VERSION = "2024.6.1"
CONDA_STORE_UI_VERSION = "2024.3.1"
CONDA_STORE_UI_URL = f"https://registry.npmjs.org/@conda-store/conda-store-ui/-/conda-store-ui-{CONDA_STORE_UI_VERSION}.tgz"
CONDA_STORE_UI_FILES = [
"main.js",
"main.css",
"main.css.map",
"main.js.map",
"index.html",
]

UI_FILES_EXTENSIONS = ["*.js", "*.css", "*.js.map", "*.css.map", "*.html"]

SERVER_DIR = Path("conda_store_server/_internal/server")
SERVER_UI_ASSETS = SERVER_DIR / "static/conda-store-ui"
# FastAPI templates directory
SERVER_UI_TEMPLATES = SERVER_DIR / "templates"


# Note we do not modify the main.js file directly anymore. Instead we leverage
# the use of runtime configuration through condaStoreConfig per
# https://conda.store/conda-store-ui/how-tos/configure-ui
# which is set up in conda-store-server/conda_store_server/_internal/server/templates/conda-store-ui.html
class DownloadCondaStoreUIHook(BuildHookInterface):
def clean(self, versions: List[str]) -> None:
"""Delete previously vendored UI files. This is called from:
`hatch clean` and `hatch build --clean`
Args:
versions (List[str]): a list of published versions in npm
"""
super().clean(versions)
destination_directory = (
pathlib.Path(self.root)
/ "conda_store_server/_internal/server/static/conda-store-ui"
)
shutil.rmtree(destination_directory, ignore_errors=True)
server_build_static_assets = Path(self.root) / SERVER_UI_ASSETS
shutil.rmtree(server_build_static_assets, ignore_errors=True)

def initialize(self, version: str, build_data: Dict[str, Any]) -> None:
"""UI vendoring within conda-store-server. This can be used to build conda-store-server with a local or
released version of conda-store-ui (should be available in npm).
This hook ensures we have the UI files in the correct location for the server to serve them and updates the
HTML templates to point to the right paths for the UI assets.
Args:
version (str): ui version to vendor
"""
super().initialize(version, build_data)

if "LOCAL_UI" in os.environ:
print(
f"Building with a local version of conda-store-ui located in {os.getenv('LOCAL_UI')}"
)

if Path(os.getenv("LOCAL_UI")).exists():
local_ui_path = os.getenv("LOCAL_UI")
source_directory = Path(local_ui_path) / "dist"
self.copy_ui_files(source_directory)

else:
raise FileNotFoundError(
f"Local UI directory {os.getenv('LOCAL_UI')} does not exist"
)
# build with a released version of conda-store-ui - this is what we do for conda-store-server releases
else:
print(f"Building with conda-store-ui version {CONDA_STORE_UI_VERSION}")
self.get_ui_release(CONDA_STORE_UI_VERSION)

def get_ui_release(self, ui_version: str) -> None:
"""Download a released version of conda-store-ui and add it to the
server's static assets directory.
Args:
ui_version (str): conda-store-ui version to download, must be a
valid npm release
"""

with tempfile.TemporaryDirectory() as tmp_dir:
tmp_dir = pathlib.Path(tmp_dir)
tmp_dir = Path(tmp_dir)
tmp_filename = tmp_dir / "conda-store-ui.tgz"

print(f"Downloading @conda-store/conda-store-ui={CONDA_STORE_UI_VERSION}")
Expand All @@ -51,29 +101,35 @@ def initialize(self, version: str, build_data: Dict[str, Any]) -> None:
tar.extractall(path=tmp_dir)

source_directory = tmp_dir / "package/dist"
destination_directory = (
pathlib.Path(self.root)
/ "conda_store_server/_internal/server/static/conda-store-ui"
)
destination_directory.mkdir(parents=True, exist_ok=True)

print(f"Copying files {CONDA_STORE_UI_FILES}")
for filename in CONDA_STORE_UI_FILES:
shutil.copy(
source_directory / filename,
destination_directory / filename,
)
self.copy_ui_files(source_directory)

# dirty modifications (bound to break eventually!) to
# main.js to enable easy configuration see
# conda_store_server/_internal/server/templates/conda-store-ui.html
# for global variable set
with (source_directory / "main.js").open("r", encoding="utf-8") as source_f:
content = source_f.read()
content = re.sub(
'"MISSING_ENV_VAR"', "GLOBAL_CONDA_STORE_STATE", content
)
with (destination_directory / "main.js").open(
"w", encoding="utf-8"
) as dest_f:
dest_f.write(content)
def copy_ui_files(self, source_directory: str) -> None:
"""Copy conda-store-ui files to the conda-server static assets
directory (SERVER_UI_ASSETS).
Args:
source_directory (str): path to the directory containing the UI files
"""

server_build_static_assets = Path(self.root) / SERVER_UI_ASSETS
server_build_static_assets.mkdir(parents=True, exist_ok=True)

print(f"Copying conda-store-ui files from {source_directory} \n")

try:
for extension in UI_FILES_EXTENSIONS:
for file_path in source_directory.glob(extension):
target_path = server_build_static_assets / file_path.name
# in case the file already exists, remove it
if target_path.exists():
target_path.unlink()
shutil.copy(file_path, target_path)

print(
f"Copied files: {[p.name for p in server_build_static_assets.glob('*')]}"
)

except (IOError, OSError) as e:
print(f"Error copying files: {e}")
raise
4 changes: 2 additions & 2 deletions conda-store-server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ license = "BSD-3-Clause"
requires-python = ">=3.8"
keywords = ["conda"]
authors = [
{ name = "Christopher Ostrouchov", email = "crhsi[email protected]" },
{ name = "Christopher Ostrouchov", email = "chris[email protected]" },
]
maintainers = [
{ name = "Tania Allard", email = "[email protected]" },
Expand Down Expand Up @@ -110,6 +110,7 @@ playwright-test = [
integration-test = ["pytest ../tests/test_api.py ../tests/test_metrics.py"]
user-journey-test = ["pytest -m user_journey"]

# custom conda-store build hook, used to bundle ui artefacts
[tool.hatch.build.hooks.custom]

[tool.hatch.build.targets.sdist.hooks.custom]
Expand All @@ -120,7 +121,6 @@ conda-store-worker = "conda_store_server._internal.worker.__main__:main"

[tool.black]
line-length = 88
target-version = ['py37', 'py38', 'py39']

[tool.isort]
lines_between_types = 1
Expand Down
1 change: 0 additions & 1 deletion conda-store/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ conda-store = "conda_store.__main__:main"

[tool.black]
line-length = 88
target-version = ['py38', 'py39', 'py310']

[tool.ruff]
line-length = 88
Expand Down
2 changes: 1 addition & 1 deletion docusaurus-docs/static/openapi.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/assets/conda_store_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
c.CondaStoreServer.authentication_class = DummyAuthentication
c.CondaStoreServer.template_vars = {
"banner": '<div class="alert alert-danger" role="alert">This is a localhost server</div>',
"logo": "https://quansight.com/_next/image?url=https%3A%2F%2Fa.storyblok.com%2Ff%2F147759%2F1076x520%2Fe6cd6af012%2Fquansight-logo-no-tagline.png&w=3840&q=75",
"logo": "https://raw.githubusercontent.com/conda-incubator/conda-store/main/docusaurus-docs/community/assets/logos/conda-store-logo-horizontal-lockup.svg",
}

# ==================================
Expand Down

0 comments on commit 13c7b79

Please sign in to comment.