diff --git a/.github/workflows/dev.build.yml b/.github/workflows/dev.build.yml index e773ccf089..6edc4beec0 100644 --- a/.github/workflows/dev.build.yml +++ b/.github/workflows/dev.build.yml @@ -7,6 +7,7 @@ on: env: GMC_ENABLE_ON_PUBLISH: true + GMC_DEV_URL: 'https://auronen.cokoliv.eu/gmc/' jobs: deploy: @@ -24,22 +25,30 @@ jobs: with: python-version: 3.11 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements uses: actions/cache@v3 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate python -m unittest discover tests/ -v + - name: Process MkDocs Plugins & Hooks Cache + uses: actions/cache@v3 + with: + path: .cache + key: mkdocs-${{ github.sha }} + restore-keys: | + mkdocs- - name: Build and deploy site run: | source venv/bin/activate diff --git a/.github/workflows/master.build.yml b/.github/workflows/master.build.yml index eb96c37fd4..7ab67db47c 100644 --- a/.github/workflows/master.build.yml +++ b/.github/workflows/master.build.yml @@ -24,22 +24,30 @@ jobs: with: python-version: 3.11 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements uses: actions/cache@v3 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate python -m unittest discover tests/ -v + - name: Process MkDocs Plugins & Hooks Cache + uses: actions/cache@v3 + with: + path: .cache + key: mkdocs-${{ github.sha }} + restore-keys: | + mkdocs- - name: Build and deploy site run: | source venv/bin/activate diff --git a/.github/workflows/pull.request.yml b/.github/workflows/pull.request.yml index 7817fee2ff..33e67a00e4 100644 --- a/.github/workflows/pull.request.yml +++ b/.github/workflows/pull.request.yml @@ -24,18 +24,19 @@ jobs: with: python-version: 3.11 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements uses: actions/cache@v3 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate diff --git a/mkdocs.yml b/mkdocs.yml index dc889387b6..7cfaf9b3b8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,6 @@ site_name: Gothic Modding Community -site_url: https://gothic-modding-community.github.io/gmc/ +site_url: !ENV [GMC_DEV_URL, 'https://gothic-modding-community.github.io/gmc/'] +site_description: 'Gothic Modding Community is a collection of helpful resources for modding Gothic and Risen games.' repo_name: Gothic-Modding-Community/gmc repo_url: https://github.com/Gothic-Modding-Community/gmc/ @@ -11,6 +12,7 @@ watch: hooks: - overrides/.hooks/language_flags.py - overrides/.hooks/git_redirects.py + - overrides/.hooks/social_patch.py theme: name: material @@ -58,10 +60,10 @@ extra: social: - icon: fontawesome/brands/discord link: https://discord.gg/mCpS5b5SUY - name: Gothic Modding Comunity Discord Server + name: Gothic Modding Community Discord Server - icon: fontawesome/brands/github link: https://github.com/Gothic-Modding-Community/gmc - name: Gothic Modding Comunity Github repository + name: Gothic Modding Community GitHub repository @@ -135,9 +137,11 @@ plugins: pl: name: pl - Polski build: true + site_description: 'Gothic Modding Community to zbiór pomocnych materiałów do modowania gier Gothic i Risen.' cs: name: cs - Čeština build: true + site_description: 'Dokumentace, návody a články zaměřené na modování her Gothic a Risen.' material_alternate: true # Only 1 global scope, if 2 nav elements are named the same, input translation only once. # Translate only the section/directory titles, page titles should be in the meta header of the `.md` file. @@ -184,4 +188,6 @@ plugins: - zengin/index*.md - redirects: # Empty dict to fill with the `meta_redirects.py` hook. - redirect_maps: {} \ No newline at end of file + redirect_maps: {} + - social: + cards: !ENV [GMC_ENABLE_ON_PUBLISH, False] \ No newline at end of file diff --git a/overrides/.hooks/git_redirects.py b/overrides/.hooks/git_redirects.py index 82d80a7e74..3a014b979b 100644 --- a/overrides/.hooks/git_redirects.py +++ b/overrides/.hooks/git_redirects.py @@ -7,7 +7,9 @@ MIT Licence 2023 Kamil Krzyśków """ import datetime +import json import logging +import os from pathlib import Path from typing import Dict, Optional, Set @@ -26,6 +28,10 @@ def on_config(config: MkDocsConfig) -> Optional[Config]: """Main function. Check the `redirects` plugin is present and fill the redirects mapping.""" + if not os.getenv(HOOK_VAR, False): + LOG.info(f"{HOOK_NAME}: {HOOK_VAR} is not set to True in the environment") + return None + if not GIT_MODULE: LOG.warning(f"{HOOK_NAME}: The `GitPython` module is not installed") return None @@ -38,25 +44,47 @@ def on_config(config: MkDocsConfig) -> Optional[Config]: LOG.warning(f"{HOOK_NAME}: The `redirects` plugin is not configured correctly") return None - _add_redirects_based_on_git_history(config=config) + if os.getenv(CACHE_VAR, False): + CacheHelper.setup(config=config) + commit_hash = _add_redirects_based_on_git_history(config=config, cache_enabled=True) + if commit_hash is not None and commit_hash != CacheHelper.cache_obj["commit_hash"]: + CacheHelper.cache_obj["commit_hash"] = commit_hash + CacheHelper.save(config=config) + else: + _add_redirects_based_on_git_history(config=config) return None -def _add_redirects_based_on_git_history(*, config: MkDocsConfig) -> None: +def _add_redirects_based_on_git_history( + *, config: MkDocsConfig, cache_enabled: bool = False +) -> Optional[str]: """Process the Git history looking for rename actions.""" docs_dir: Path = Path(config.get("docs_dir")) - file_paths: Set[str] = {str(path) for path in docs_dir.glob("**/*.md")} docs_prefix: str = docs_dir.name + "/" project_root: Path = docs_dir.parent + repo = Repo(project_root) + + if MAX_HASH and len(repo.commit(MAX_HASH).parents) > 1: + LOG.warning(f"{HOOK_NAME}: Using a Merge commit revision for 'MAX_HASH' is not supported") + return None + + if cache_enabled and repo.head.commit.hexsha == CacheHelper.cache_obj["commit_hash"]: + LOG.info(f"{HOOK_NAME}: HEAD commit already cached") + return None + file_paths: Set[str] = {str(path) for path in docs_dir.glob("**/*.md")} redirects: Dict[str, str] = config["plugins"]["redirects"].config["redirect_maps"] + + if cache_enabled: + redirects.update(CacheHelper.cache_obj["redirects"]) + initial_len: int = len(redirects) - LOG.info(f"{HOOK_NAME}: Processing Git history...") + LOG.info(f"{HOOK_NAME}: Processing Git history with{'' if cache_enabled else 'out'} cache...") - for commit in Repo(project_root).iter_commits(since=MAX_DATE, max_parents=1): + for commit in repo.iter_commits(since=MAX_DATE, max_parents=1): if not commit.parents: break @@ -67,7 +95,9 @@ def _add_redirects_based_on_git_history(*, config: MkDocsConfig) -> None: old_parts_len: int = len(old.split("/")[-1].split(".")) new_parts_len: int = len(new.split("/")[-1].split(".")) old_exists: bool = str(project_root / old) in file_paths - old_index_exists: bool = str(project_root / old.replace(".md", "/index.md")) in file_paths + old_index_exists: bool = ( + str(project_root / old.replace(".md", "/index.md")) in file_paths + ) type_md: bool = old.endswith(".md") and new.endswith(".md") inside_docs: bool = old.startswith(docs_prefix) and new.startswith(docs_prefix) @@ -91,24 +121,74 @@ def _add_redirects_based_on_git_history(*, config: MkDocsConfig) -> None: if old_inner not in redirects: redirects[old_inner] = new_inner else: - LOG.info(f"{HOOK_NAME}: '{old_inner}' already in redirects, keeping more recent one") + LOG.info( + f"{HOOK_NAME}: '{old_inner}' already in redirects, keeping more recent one" + ) if commit.hexsha == MAX_HASH: break + if cache_enabled and commit.parents[0].hexsha == CacheHelper.cache_obj["commit_hash"]: + LOG.info(f"{HOOK_NAME}: Reached cached commits") + break + len_diff: int = len(redirects) - initial_len if len_diff > 0: LOG.info(f"{HOOK_NAME}: Created {len_diff} redirects") + if cache_enabled: + return repo.head.commit.hexsha + + +class CacheHelper: + """Class contains variables related to caching""" + + cache_dir: Optional[Path] = None + """Directory path to the plugin cache directory""" + + cache_file: Optional[Path] = None + """File path where the cached redirects will be saved""" + + cache_obj: Optional[Dict] = None + """Object, which will be saved to cache""" + + @classmethod + def setup(cls, *, config: MkDocsConfig) -> None: + cls.cache_dir = Path(config.get("docs_dir")).parent / CACHE_PATH + formatted_date: str = ( + MAX_DATE.isoformat().replace(":", "") if isinstance(MAX_DATE, datetime.datetime) else "" + ) + cls.cache_file = cls.cache_dir / f"{formatted_date}-{MAX_HASH}.json" + + if cls.cache_file.exists(): + cls.cache_obj = json.loads(cls.cache_file.read_text(encoding="utf8")) + else: + cls.cache_obj: Dict = {"commit_hash": "", "redirects": {}} + cls.cache_dir.mkdir(parents=True, exist_ok=True) + cls.cache_file.write_text(json.dumps(cls.cache_obj), encoding="utf8") + + @classmethod + def save(cls, *, config: MkDocsConfig) -> None: + cls.cache_obj["redirects"] = config["plugins"]["redirects"].config["redirect_maps"] + cls.cache_file.write_text(json.dumps(cls.cache_obj, indent=2), encoding="utf8") + # endregion # region Constants +CACHE_VAR: str = "GMC_ENABLE_ON_PUBLISH" +"""Name of the environmental variable to enable caching.""" HOOK_NAME: str = "git_redirects" """Name of this hook. Used in logging.""" +CACHE_PATH: str = f".cache/hooks/{HOOK_NAME}" +"""A relative path to the cache directory, based from the `config.docs_dir` parent directory.""" + +HOOK_VAR: str = "GMC_ENABLE_ON_PUBLISH" +"""Name of the environmental variable to enable the hook.""" + LOG: logging.Logger = logging.getLogger(f"mkdocs.hooks.{HOOK_NAME}") """Logger instance for this hook.""" diff --git a/overrides/.hooks/social_patch.py b/overrides/.hooks/social_patch.py new file mode 100644 index 0000000000..cdf5f683f2 --- /dev/null +++ b/overrides/.hooks/social_patch.py @@ -0,0 +1,66 @@ +"""MkDocs hook, which patches the Social plugin of the Material theme. + +The hook fixes a crash when using theme.font.code without theme.font.text. +The hook overrides the `theme.logo` file lookup to use the custom_dir instead of the docs_dir. +The hook does not override `theme.logo.icon` file lookup. + +MIT Licence 2023 Kamil Krzyśków +""" +from copy import deepcopy +from pathlib import Path +from typing import Optional + +from mkdocs import plugins +from mkdocs.config import Config +from mkdocs.config.defaults import MkDocsConfig + + +@plugins.event_priority(100) +def on_config(config: MkDocsConfig) -> Optional[Config]: + for name in {"social", "material/social"}: + plugin = config.plugins.get(name) + if plugin: + break + else: + print("Social-Plugin-Patch: Did not find plugin!?!?!") + return None + + plugin._load_font = patch_font_crash(plugin._load_font) + plugin._load_logo = patch_custom_dir(plugin._load_logo) + + return None + + +class Mock: + ... + + +def patch_font_crash(func): + """Patch the theme["font"]["text"] crash""" + + def wrap_load_font(config): + theme = config.theme + if "font" in theme and "text" not in theme["font"]: + mock_config = Mock() + mock_config.theme = deepcopy(config.theme) + mock_config.theme["font"]["text"] = "Roboto" + return func(mock_config) + return func(config) + + return wrap_load_font + + +def patch_custom_dir(func): + """Patch support for paths in `custom_dir`""" + + def wrap_load_logo(config): + mock_config = Mock() + mock_config.theme = config.theme + mock_config.docs_dir = str(Path(config.docs_dir).parent / CUSTOM_DIR_PATH) + return func(mock_config) + + return wrap_load_logo + + +CUSTOM_DIR_PATH = "overrides" +"""A relative path to the custom directory based from the `docs_dir` parent directory.""" diff --git a/overrides/assets/stylesheets/constants.css b/overrides/assets/stylesheets/constants.css index 0fa956a1b4..ced88015c7 100644 --- a/overrides/assets/stylesheets/constants.css +++ b/overrides/assets/stylesheets/constants.css @@ -8,4 +8,9 @@ --gmc-external-svg: url('data:image/svg+xml;charset=utf-8,'); /* SVG to CSS inline data converter: https://yoksel.github.io/url-encoder/ - output edited */ --md-admonition-icon--trivia: url('data:image/svg+xml;charset=utf-8,'); +} + +/* Color */ +:root { + --gmc-blue-tint: #00aafc; } \ No newline at end of file diff --git a/overrides/assets/stylesheets/extra.css b/overrides/assets/stylesheets/extra.css index b74857b6eb..4876fe9162 100644 --- a/overrides/assets/stylesheets/extra.css +++ b/overrides/assets/stylesheets/extra.css @@ -23,6 +23,11 @@ max-width: 75rem; } +/* Add left padding indent to the content */ +article > div > :is(:not(h1, h2, h3, h4)) { + padding-left: 1em !important; +} + /* Shrink header and footer to the content size*/ .md-grid { /* Default 61rem */ @@ -96,7 +101,7 @@ div.md-nav__link--index { --md-accent-fg-color: #0b65b0; } [data-md-color-scheme=slate] { - --md-accent-fg-color: #00aafc; + --md-accent-fg-color: var(--gmc-blue-tint); } } @@ -110,6 +115,7 @@ div.md-nav__link--index { .md-typeset :is(h1, h2, h3, h4, h5, h6) { font-weight: 700; color: var(--md-default-fg-color--light); + text-shadow: 0 0 0 var(--md-default-fg-color--light); } .md-typeset :is(h3, h4, h5, h6) { @@ -169,8 +175,9 @@ div.md-nav__link--index { /* override main header */ /* override tabs navigation */ @media { + /* Use a darker color than the --gmc-blue-tint since it is too bright */ [data-md-color-scheme="slate"] .md-header { - border-bottom: 0.10rem solid var(--md-accent-fg-color); + border-bottom: .10rem solid #0084c4; } [data-md-color-scheme="slate"] .md-tabs__link--active { color: var(--md-accent-fg-color); diff --git a/requirements-deploy.txt b/requirements-deploy.txt new file mode 100644 index 0000000000..da56ab564f --- /dev/null +++ b/requirements-deploy.txt @@ -0,0 +1,3 @@ +# Deployment Requirements +Pillow==9.5.0 +CairoSVG==2.7.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a4b4283cb1..0f36f762ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -mkdocs-material==9.1.5 +# Core Requirements +mkdocs-material==9.1.8 mkdocs-git-revision-date-localized-plugin==1.2.0 mkdocs-video==1.5.0 mkdocs-redirects==1.2.0 mkdocs-minify-plugin==0.6.4 # mkdocs-static-i18n==0.53 -git+https://github.com/kamilkrzyskow/i18n.git@920d38313b60812e8e03dba88a856bfdd41527dc#egg=mkdocs_static_i18n +git+https://github.com/kamilkrzyskow/i18n.git@5e286be68ad6fafed7affd44cd57d3625c0a02cc#egg=mkdocs_static_i18n git+https://github.com/kamilkrzyskow/gothic-lexer.git@b5ee7868a7e7397cd129ff1f847daa7d39c0e416#egg=gothic_lexer -# mkdocs-awesome-pages-plugin==2.8.0 -git+https://github.com/kamilkrzyskow/awesome-pages.git@b0c544a92733977e09ac23c7f9238d13012f4fd9#egg=mkdocs_awesome_pages_plugin \ No newline at end of file +mkdocs-awesome-pages-plugin==2.9.0 \ No newline at end of file