diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 32767cc5aa..5f0d8ce2dc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -65,7 +65,6 @@ jobs: - name: Build static website run: | geotribu --help > content/toc_nav_ignored/snippets/code/geotribu_cli_help.txt - python scripts/050_mkdocs_populate_latest.py -c mkdocs.yml python scripts/100_mkdocs_config_merger.py -c mkdocs.yml mkdocs build --clean --config-file mkdocs.yml --verbose --strict env: diff --git a/.github/workflows/links_checker.yml b/.github/workflows/links_checker.yml index eb37a1265a..6585c0901d 100644 --- a/.github/workflows/links_checker.yml +++ b/.github/workflows/links_checker.yml @@ -35,7 +35,6 @@ jobs: - name: Build static website run: | - python scripts/050_mkdocs_populate_latest.py python scripts/100_mkdocs_config_merger.py -c mkdocs.yml mkdocs build --clean --config-file mkdocs.yml --quiet --strict env: diff --git a/.github/workflows/pr_checker_build.yml b/.github/workflows/pr_checker_build.yml index 26528c6df8..84f64127c6 100644 --- a/.github/workflows/pr_checker_build.yml +++ b/.github/workflows/pr_checker_build.yml @@ -77,7 +77,6 @@ jobs: export MKDOCS_SITE_URL="https://${NETLIFY_SITE_PREFIX}--${NETLIFY_SITE_NAME}.netlify.app/" # merge different configs - python scripts/050_mkdocs_populate_latest.py -c ${{ env.MKDOCS_CONFIG_FILENAME }} python scripts/100_mkdocs_config_merger.py -c ${{ env.MKDOCS_CONFIG_FILENAME }} # build diff --git a/.gitignore b/.gitignore index bf36f4221c..6b1e3681a1 100644 --- a/.gitignore +++ b/.gitignore @@ -233,3 +233,4 @@ linkchecker_report.html # fichiers liés aux vidéos Gource gource.ini avatars/ +mkdocs-generated-configuration.yml diff --git a/config/extra_latest.yml b/config/extra_latest.yml deleted file mode 100644 index 2cd6edfc0f..0000000000 --- a/config/extra_latest.yml +++ /dev/null @@ -1,5 +0,0 @@ -# DO NOT MANUALLY EDIT THIS FILE, IT'S FILLD BY SCRIPT: scripts/mkdocs_populate_latest.py - -latest: - articles: [] - rdp: [] diff --git a/hooks/mkdocs/G000_load_subconfigs.py b/hooks/mkdocs/G000_load_subconfigs.py new file mode 100644 index 0000000000..e5d748a3ea --- /dev/null +++ b/hooks/mkdocs/G000_load_subconfigs.py @@ -0,0 +1,140 @@ +#! python3 # noqa: E265 + +# ############################################################################ +# ########## Libraries ############# +# ################################## + +# standard library +import logging +from pathlib import Path +from typing import Literal, Optional + +# 3rd party +import mkdocs.plugins +from material import __version__ as material_version +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.pages import Page +from mkdocs.utils.meta import get_data + +# ########################################################################### +# ########## Global ################ +# ################################## + + +logger = logging.getLogger("mkdocs") +log_prefix = f"[{__name__}] " + +# ########################################################################### +# ########## Functions ############# +# ################################## + + +def get_latest_content( + content_type: Literal["articles", "rdp"], + count: int = 10, + social_card_image_base: str = "https://geotribu.fr/assets/images/social/", +): + output_contents_list: list[Page] = [] + + if content_type == "articles": + glob_pattern = "202*/202*.md" + elif content_type == "rdp": + glob_pattern = "202*/rdp_202*.md" + + for content in sorted( + Path(f"content/{content_type}/").glob(glob_pattern), reverse=True + )[:count]: + with content.open(encoding="utf-8-sig", errors="strict") as f: + source = f.read() + + page_meta = get_data(source)[1] + + page_rel = str(content.relative_to("content/"))[:-3] + + if page_meta.get("image") is None or page_meta.get("image") == "": + social_card_url = f"{social_card_image_base}{page_rel}.png" + output_contents_list.append( + get_data(source)[1] | {"url_rel": page_rel} | {"image": social_card_url} + ) + else: + output_contents_list.append(get_data(source)[1] | {"url_rel": page_rel}) + + return output_contents_list + + +def is_mkdocs_theme_material_insiders() -> Optional[bool]: + """Check if the material theme is community or insiders edition. + + Returns: + bool: True if the theme is Insiders edition. False if community. + """ + if material_version is not None and "insiders" in material_version: + logger.debug(log_prefix + "Material theme edition INSIDERS") + return True + else: + logger.debug(log_prefix + "Material theme edition COMMUNITY") + return False + + +# ########################################################################### +# ########## Hooks ################# +# ################################## + + +@mkdocs.plugins.event_priority(10) +def on_config(config: MkDocsConfig) -> MkDocsConfig: + """The config event is the first event called on build and + is run immediately after the user configuration is loaded and validated. + Any alterations to the config should be made here. + + See: https://www.mkdocs.org/user-guide/plugins/#on_config + + Args: + config (config_options.Config): global configuration object + + Returns: + MkDocsConfig: global configuration object + """ + # determine the website flavor + config_filename = Path(config.get("config_file_path")).name + if config_filename == "mkdocs.yml": + config["extra"]["website_flavor"] = "insiders" + elif config_filename == "mkdocs-free.yml": + config["extra"]["website_flavor"] = "community" + else: + config["extra"]["website_flavor"] = "minimal" + + # check if insiders version is installed + if ( + config["extra"]["website_flavor"] == "insiders" + and not is_mkdocs_theme_material_insiders() + ): + logger.warning( + log_prefix + + f"Le fichier {config.get('config_file_path')} contient des paramètres ou " + "plugins uniquement disponibles dans la version Insiders (payante) du thème " + "Material. Or c'est la version community (gratuite) qui est installée " + f"({material_version}). La génération va probablement échouer. Deux solutions :" + "A. Installer la version Insiders (requiert un jeton GitHub). " + "B. Utiliser la configuration basée sur la version communautaire (gratuite), " + "par exemple : 'mkdocs build -f mkdocs-free.yml'" + ) + config["extra"]["website_flavor"] = "community" + + logger.info( + log_prefix + f"Génération du site {config.get('site_name')} " + f"en version {config.get('extra').get('website_flavor').upper()}" + ) + + # latest contents + latest_contents: dict = {"articles": [], "rdp": []} + for k in latest_contents: + latest_contents[k] = get_latest_content( + content_type=k, + social_card_image_base=f"{config.get('site_url')}assets/images/social/", + ) + + config["extra"]["latest"] = latest_contents + logger.info( + log_prefix + "Contenus récents ajoutés à la configuration globale du site." + ) diff --git a/mkdocs-free.yml b/mkdocs-free.yml index 58762b13ce..73f06ef0fa 100644 --- a/mkdocs-free.yml +++ b/mkdocs-free.yml @@ -21,6 +21,7 @@ site_dir: !ENV [MKDOCS_OUTPUT_DIR, "./build/mkdocs/site"] # Scripts pendant le build hooks: + - hooks/mkdocs/G000_load_subconfigs.py - hooks/mkdocs/G003_social_cards_adapter.py - hooks/mkdocs/G005_jinja_filters.py - hooks/mkdocs/G006_authors_block.py diff --git a/mkdocs-minimal.yml b/mkdocs-minimal.yml index e42da98320..5942af4271 100644 --- a/mkdocs-minimal.yml +++ b/mkdocs-minimal.yml @@ -16,6 +16,7 @@ site_dir: !ENV [MKDOCS_OUTPUT_DIR, "./build/mkdocs/site"] # Scripts pendant le build hooks: + - hooks/mkdocs/G000_load_subconfigs.py - hooks/mkdocs/G005_jinja_filters.py - hooks/mkdocs/G006_authors_block.py diff --git a/mkdocs.yml b/mkdocs.yml index 774540bef2..30c70bfae2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,7 @@ site_dir: !ENV [MKDOCS_OUTPUT_DIR, "./build/mkdocs/site"] # Scripts pendant le build hooks: + - hooks/mkdocs/G000_load_subconfigs.py # - hooks/mkdocs/G002_check_images_size.py - hooks/mkdocs/G003_social_cards_adapter.py - hooks/mkdocs/G005_jinja_filters.py diff --git a/scripts/050_mkdocs_populate_latest.py b/scripts/050_mkdocs_populate_latest.py deleted file mode 100644 index bf5003c26b..0000000000 --- a/scripts/050_mkdocs_populate_latest.py +++ /dev/null @@ -1,124 +0,0 @@ -#! python3 # noqa: E265 - -# ############################################################################ -# ########## Libraries ############# -# ################################## - -# standard lib -import argparse -import logging -from pathlib import Path -from typing import Literal - -# 3rd party -import yaml -from mkdocs.structure.pages import Page -from mkdocs.utils import yaml_load -from mkdocs.utils.meta import get_data - -# ########################################################################### -# ########## Global ################ -# ################################## - - -logger = logging.getLogger("mkdocs") - - -# -- CLI -- -parser = argparse.ArgumentParser( - prog="MkDocsConfigMerger", description="Merge configuration files.", add_help=True -) -parser.add_argument( - "-c", - "--config-file", - dest="output_config_file", - type=Path, - help="Path to the configuration file to complete. Must exist.", - default="mkdocs.yml", -) -parser.add_argument( - "-i", - "--input-folder", - dest="input_config_folder", - type=Path, - help="Path to the folder where to load configurations files to merge. Must exist.", - default="./config", -) - -args = parser.parse_args() - -output_config_file = args.output_config_file -input_config_folder = args.input_config_folder - -# -- CHECKS -- - -if not output_config_file.is_file(): - raise FileNotFoundError(output_config_file) -if not input_config_folder.is_dir(): - raise FileNotFoundError(input_config_folder) - - -# ########################################################################### -# ########## Functions ############# -# ################################## - - -def get_latest_content( - content_type: Literal["articles", "rdp"], - count: int = 10, - social_card_image_base: str = "https://geotribu.fr/assets/images/social/", -): - output_contents_list: list[Page] = [] - - if content_type == "articles": - glob_pattern = "202*/202*.md" - elif content_type == "rdp": - glob_pattern = "202*/rdp_202*.md" - - for content in sorted( - Path(f"content/{content_type}/").glob(glob_pattern), reverse=True - )[:count]: - with content.open(encoding="utf-8-sig", errors="strict") as f: - source = f.read() - - page_meta = get_data(source)[1] - - page_rel = str(content.relative_to("content/"))[:-3] - - if page_meta.get("image") is None or page_meta.get("image") == "": - social_card_url = f"{social_card_image_base}{page_rel}.png" - output_contents_list.append( - get_data(source)[1] | {"url_rel": page_rel} | {"image": social_card_url} - ) - else: - output_contents_list.append(get_data(source)[1] | {"url_rel": page_rel}) - - return output_contents_list - - -# charge la configuration -with output_config_file.open(mode="r", encoding="UTF8") as in_yaml: - mkdocs_config = yaml_load(in_yaml) - -output_dict = {"latest": {"articles": [], "rdp": []}} - -# print(get_latest_content(content_type="articles")) - -for k in output_dict.get("latest"): - output_dict["latest"][k] = get_latest_content( - content_type=k, - social_card_image_base=f"{mkdocs_config.get('site_url')}assets/images/social/", - ) - -with input_config_folder.joinpath("extra_latest.yml").open( - "w", encoding="UTF-8" -) as out_file: - yaml.safe_dump( - output_dict, - out_file, - allow_unicode=True, - default_flow_style=False, - encoding="UTF8", - # indent=4, - sort_keys=True, - )