Browse Source
[IMP] initiate hugo site generation with lotusdoc and json content source
[IMP] initiate hugo site generation with lotusdoc and json content source
Stéphan Sainléger
1 year ago
11 changed files with 344 additions and 451 deletions
-
1.python-version
-
7config.toml
-
92content/my-first-post.md
-
81generate.py
-
177generate_lotusdocs.py
-
109generate_v2.py
-
160generate_v3.py
-
38hugo.toml
-
26init_hugo_toml.py
-
76structure.json
-
28update.sh
@ -0,0 +1 @@ |
|||||
|
3.8.10 |
@ -1,7 +0,0 @@ |
|||||
baseURL = 'http://example.org/' |
|
||||
languageCode = 'en-us' |
|
||||
title = 'My New Hugo Site' |
|
||||
theme = "hugo-theme-learn" |
|
||||
|
|
||||
[outputs] |
|
||||
home = [ "HTML", "RSS", "JSON"] |
|
@ -1,92 +0,0 @@ |
|||||
____ |
|
||||
title: "My First Post" |
|
||||
date: 2022-10-29T15:59:37+02:00 |
|
||||
draft: false |
|
||||
____ |
|
||||
|
|
||||
# Procédures organisationnelles |
|
||||
|
|
||||
- [Nouveau fonctionnement du support Lokavaluto](https://docs.lokavaluto.fr/MAI9LEmBTH6hB6II6xUTxA) |
|
||||
- [Ancien fonctionnement du support Lokavaluto et pourquoi cela ne convenait pas](https://docs.lokavaluto.fr/S6uGRvQ-Rl25LiyCgPQvzg) |
|
||||
|
|
||||
# Odoo Community (v12) |
|
||||
|
|
||||
## Procédures d'utilisation |
|
||||
|
|
||||
- [Présentation et interface générale](https://docs.lokavaluto.fr/tgJjJkHfS_OZwj0JWvHsKw) |
|
||||
- [Paramétrage du compte utilisateur](https://docs.lokavaluto.fr/Sc_tIVdCTaSClMkdkg8PaQ) |
|
||||
- [Recherches et vues](https://docs.lokavaluto.fr/6pmPhxmATxSIgNYPKWruvQ) |
|
||||
- [Utilisation du chatter](https://docs.lokavaluto.fr/whiTd855THaucVX6hhBcHQ) |
|
||||
- [Utilisation du calendrier](https://docs.lokavaluto.fr/CJt7IS8OSSmD6yg7vrWTlg) |
|
||||
- [Gestion de la prospection (CRM)](https://docs.lokavaluto.fr/oE_BiLb_RwyrrRwvElbBWw) |
|
||||
- [Gestion des contacts, des membres et cartographie](https://docs.lokavaluto.fr/apAZA45PRwa0Cj5F1i8UDQ) |
|
||||
- [Tutoriel d’utilisation du module Membres pour les Monnaies Locales](https://docs.lokavaluto.fr/Z6I27taoSciMu5pvYjrLLA) |
|
||||
- [Gestion des relations entre contacts](https://docs.lokavaluto.fr/EZU8_sb7RwqyPh4Y9ItRIA) |
|
||||
- [Envoi des newsletter et email Marketing](https://docs.lokavaluto.fr/0RpWDYwWSnaIpH2Tz7-jrg) |
|
||||
- [Gestion des événements](https://docs.lokavaluto.fr/0zFFR8pgSEmdO45mkLzKTQ) |
|
||||
- [Gestion de Projet](https://docs.lokavaluto.fr/UYHemvLrQPewS0HlHEJSvQ) |
|
||||
- [Feuilles de temps](https://docs.lokavaluto.fr/Pl2GX0j1Qf2L5zVHD8nJeQ) |
|
||||
- [Facturation - Comptabilité : utilisation générale](https://docs.lokavaluto.fr/a5ZqnKcfT7OuivOb6F-DAA) |
|
||||
- [Ajout d'une adhésion](https://docs.lokavaluto.fr/9n0Zl9-sRGusmWYQBSkK9A) |
|
||||
- [Rapprochement bancaire](https://docs.lokavaluto.fr/HifCGFN3QNWIRgt30y5OnA) |
|
||||
- [Importer un relevé CSV Crédit coopératif dans Odoo](https://docs.lokavaluto.fr/9xgBdFP2Re-Ym_Jxr21Dpg) |
|
||||
- [Prélèvement SEPA dans Odoo](https://docs.lokavaluto.fr/RifSR2t4TH-ADXq3MzYsyQ) |
|
||||
- [Gestion du nantissement](https://docs.laroue.org/GAQ962niS_6dwu9I-aJisA) |
|
||||
- Gestion des immobilisations |
|
||||
- Comptabilité analytique |
|
||||
- Remises de chèques et bordereaux de remise |
|
||||
|
|
||||
## Procédures de configuration |
|
||||
|
|
||||
- [Liste et détail des modules et applications Odoo régulièrement utilisés](https://docs.lokavaluto.fr/hwh54P5-TbqPAacm6CuG5Q) |
|
||||
- [Installer une application ou un module](https://docs.lokavaluto.fr/koiNU5qpR1iYSsE9F9jhVw) |
|
||||
- [Création d'un utilisateur et gestion des droits d'accès](https://docs.lokavaluto.fr/xePpLWP7TpWLJRIpKOL44Q) |
|
||||
- [Création d'un site internet](https://docs.lokavaluto.fr/aJTv0fo1QuqaX8f5_bAfRA) (à rédiger) |
|
||||
- [Configuration initiale comptabilité/facturation](https://docs.lokavaluto.fr/dqZxMeDoTAipos_Nds01vQ) |
|
||||
- [Configuration des articles d'adhésion](https://docs.lokavaluto.fr/5n-dsw_fQn2lN3taiSqC8w) |
|
||||
- [Configuration et fonctionnement des adhésions en ligne avec Stripe](https://docs.lokavaluto.fr/FyTV4sPRSy2dBckgCV27Yg) (à rédiger) |
|
||||
- [Création et configuration des listes de diffusion](https://docs.lokavaluto.fr/mx5vKuPpTsae9pvCak7d3g) |
|
||||
- [Configuration et utilisation de l'édition en lot](https://docs.lokavaluto.fr/FlG8-e_gRfmu-7pRS9n9MQ) |
|
||||
- [Importer des données dans Odoo](https://docs.lokavaluto.fr/Nzj43P65T-Sfa0re00A7jA) |
|
||||
- [Exporter des données depuis Odoo](https://docs.lokavaluto.fr/UmQyyZ2fQ9WM7RMOq5T_6A) |
|
||||
- [Utilisation du mode développeur](https://docs.lokavaluto.fr/ZPAqfW93T4e0ct_Des2y4Q) |
|
||||
- [Création d'une webb app Odoo]() (à rédiger) |
|
||||
- [Procédure de nettoyage des bases de données Odoo](https://docs.lokavaluto.fr/Tleoi5cHQ9m-eGgTSvvtJg) |
|
||||
|
|
||||
# Autres outils |
|
||||
|
|
||||
- [**SOGO et Thunderbird:** Gérer ses courriels](https://docs.lokavaluto.fr/oNPVbLOyT5GnwfMenLWT_Q) |
|
||||
|
|
||||
# Cyclos |
|
||||
|
|
||||
- [Gestion administrative et comptable Monnaie numérique Cyclos](https://docs.lokavaluto.fr/-ffeZk52SSSShj6z3upleQ) |
|
||||
|
|
||||
# Procédures techniques |
|
||||
|
|
||||
## Général |
|
||||
|
|
||||
- [Installer le kit Lokavaluto / la suite Just Odoo It en moins de 2 heures](https://docs.elabore.coop/yp8m-2HtTjeAlZiyCbAC7w) |
|
||||
- [Configuration du Single Sign On (SSO) dans la suite Just Odoo It](https://docs.elabore.coop/rcWPOJGiTfKWYegB_-S94g) |
|
||||
|
|
||||
## OVH |
|
||||
|
|
||||
- [Procédère d'ouverture d'un Serveur Privé Virtuel (VPS) chez OVH](https://docs.lokavaluto.fr/ofxKNg8ST4SSryBOrs-qYA) |
|
||||
|
|
||||
## Odoo |
|
||||
|
|
||||
- [Copier une base de donnée Odoo d'une instance Odoo à une autre](https://docs.elabore.coop/FCiWj7IIRdCjy0BDhJGWrQ) |
|
||||
- [Mettre à jour / Modifier l’image Docker de Odoo dans la suite Just Odoo It](https://docs.elabore.coop/WdymXfpJSmGsQjnfbZHigw) |
|
||||
- [Installer un module Odoo “à la main” avec Just Odoo It](https://docs.elabore.coop/0QtrHIt2TH-MmrTsSlz8EQ) |
|
||||
|
|
||||
## Nextcloud |
|
||||
|
|
||||
- [Procédure de migration manuelle de Nextcloud](https://doc.myceliandre.fr/nextcloud-update-compose) |
|
||||
|
|
||||
## Gogocarto |
|
||||
|
|
||||
- [Installer et configurer une cartographie Gogocarto basée sur Odoo](https://docs.elabore.coop/xQanUX_IRHyTMjnCV6uGpQ) |
|
||||
|
|
||||
## Cyclos |
|
||||
|
|
||||
- [Installer et configurer Cyclos](https://docs.lokavaluto.fr/pBl-0OIiSeW9HQG1k_OLhQ) |
|
||||
- [Installation full stack Cyclos](https://docs.lokavaluto.fr/uxiFzvb4T-eDmt_RhaTblg) --> ce paramétrage est à intégrer dans le paramétrage de base |
|
@ -1,81 +0,0 @@ |
|||||
import io |
|
||||
import os |
|
||||
import pypandoc |
|
||||
import panflute |
|
||||
import requests |
|
||||
import ipdb |
|
||||
|
|
||||
parent_dir = "./content" |
|
||||
|
|
||||
|
|
||||
def action(elem, doc): |
|
||||
if isinstance(elem, panflute.Image): |
|
||||
doc.images.append(elem) |
|
||||
elif isinstance(elem, panflute.Link): |
|
||||
doc.links.append(elem) |
|
||||
|
|
||||
|
|
||||
def find_link(elem, doc): |
|
||||
if type(elem) == panflute.elements.Link: |
|
||||
doc.link.append(elem) |
|
||||
print(panflute.stringify(elem)) |
|
||||
|
|
||||
|
|
||||
def create_folder_h3(elem, doc): |
|
||||
if type(elem) == panflute.elements.Header and elem.level == 3: |
|
||||
directory = panflute.stringify(elem) |
|
||||
path = os.path.join(parent_dir, directory) |
|
||||
print(path) |
|
||||
|
|
||||
|
|
||||
def download(link): |
|
||||
r = requests.get(link) |
|
||||
return r.text |
|
||||
|
|
||||
|
|
||||
def create_folder_h2(elem, doc): |
|
||||
if type(elem) == panflute.elements.Header and elem.level == 2: |
|
||||
doc.link = [] |
|
||||
directory = panflute.stringify(elem) |
|
||||
path = os.path.join(parent_dir, directory) |
|
||||
os.makedirs(path, exist_ok=True) |
|
||||
elem.next.walk(find_link) |
|
||||
for link in doc.link: |
|
||||
if link.url[-1] == "#": |
|
||||
md_content = download(link.url[:-1] + "/download") |
|
||||
print( |
|
||||
parent_dir |
|
||||
+ "/" |
|
||||
+ directory |
|
||||
+ "/" |
|
||||
+ panflute.stringify(link) |
|
||||
+ ".md" |
|
||||
) |
|
||||
with open( |
|
||||
parent_dir |
|
||||
+ "/" |
|
||||
+ directory |
|
||||
+ "/" |
|
||||
+ panflute.stringify(link) |
|
||||
+ ".md", |
|
||||
"w", |
|
||||
) as f: |
|
||||
hugo_head = """ |
|
||||
--- |
|
||||
title: %s |
|
||||
date: 2022-10-29T15:59:37+02:00 |
|
||||
draft: false |
|
||||
--- |
|
||||
|
|
||||
""" % ( |
|
||||
panflute.stringify(link) |
|
||||
) |
|
||||
f.write(hugo_head + md_content) |
|
||||
|
|
||||
|
|
||||
if __name__ == "__main__": |
|
||||
data = pypandoc.convert_file("content/posts/my-first-post.md", "json") |
|
||||
doc = panflute.load(io.StringIO(data)) |
|
||||
doc.images = [] |
|
||||
doc.links = [] |
|
||||
doc = panflute.run_filter(create_folder_h2, doc=doc) |
|
@ -0,0 +1,177 @@ |
|||||
|
import json |
||||
|
import os |
||||
|
import re |
||||
|
import requests |
||||
|
import toml |
||||
|
from shutil import copytree, rmtree |
||||
|
|
||||
|
|
||||
|
def parse_for_toc(content): |
||||
|
# TODO: ADD .TableofContent directly to the page (see hugo theme ?) |
||||
|
content = content.replace("[TOC]", "") |
||||
|
return content |
||||
|
|
||||
|
|
||||
|
def parse_for_notice(content): |
||||
|
result = re.findall(":::warning.*?:::", content, re.MULTILINE | re.DOTALL) |
||||
|
for notice in result: |
||||
|
old = notice |
||||
|
content = content.replace( |
||||
|
old, |
||||
|
notice.replace(":::warning", '{{% alert context="warning" %}}').replace( |
||||
|
":::", "{{% /alert %}}" |
||||
|
), |
||||
|
) |
||||
|
result = re.findall(":::info.*?:::", content, re.MULTILINE | re.DOTALL) |
||||
|
for notice in result: |
||||
|
old = notice |
||||
|
content = content.replace( |
||||
|
old, |
||||
|
notice.replace(":::info", '{{% alert context="info" %}}').replace( |
||||
|
":::", "{{% /alert %}}" |
||||
|
), |
||||
|
) |
||||
|
result = re.findall(":::success.*?:::", content, re.MULTILINE | re.DOTALL) |
||||
|
for notice in result: |
||||
|
old = notice |
||||
|
content = content.replace( |
||||
|
old, |
||||
|
notice.replace(":::success", '{{% alert context="success" %}}').replace( |
||||
|
":::", "{{% /alert %}}" |
||||
|
), |
||||
|
) |
||||
|
result = re.findall(":::danger.*?:::", content, re.MULTILINE | re.DOTALL) |
||||
|
for notice in result: |
||||
|
old = notice |
||||
|
content = content.replace( |
||||
|
old, |
||||
|
notice.replace(":::danger", '{{% alert context="danger" %}}').replace( |
||||
|
":::", "{{% /alert %}}" |
||||
|
), |
||||
|
) |
||||
|
# print(content) |
||||
|
return content |
||||
|
|
||||
|
|
||||
|
def create_index_file(dir_path, dir_name): |
||||
|
#add _index.md for page organization |
||||
|
with open(dir_path + "/_index.md", "wb") as f: |
||||
|
print("Created", dir_path + "/_index.md") |
||||
|
index = """ |
||||
|
+++ |
||||
|
title = "{dir_name}" |
||||
|
chapter = true |
||||
|
weight = 5 |
||||
|
+++ |
||||
|
|
||||
|
# {dir_name} |
||||
|
|
||||
|
Discover what this Hugo theme is all about and the core-concepts behind it. |
||||
|
""".format( |
||||
|
dir_name=dir_name |
||||
|
) |
||||
|
f.write(b"%s" % index.encode("utf-8")) |
||||
|
|
||||
|
|
||||
|
def generate_directory_structure_and_files(node, parent_path="./content/"): |
||||
|
if "children" in node: |
||||
|
# If the node has children, it's a directory |
||||
|
dir_path = os.path.join(parent_path, node["technical_name"]) |
||||
|
os.makedirs(dir_path, exist_ok=True) # Create directory |
||||
|
create_index_file(dir_path, node["name"]) |
||||
|
for child in node["children"]: |
||||
|
generate_directory_structure_and_files(child, parent_path=dir_path) |
||||
|
elif "url" in node: |
||||
|
# If the node has a URL, it's a document |
||||
|
file_path = os.path.join(parent_path, node["technical_name"] + ".md") |
||||
|
link_url = node["url"] |
||||
|
if link_url: |
||||
|
with open(file_path, "wb") as f: |
||||
|
doc_link = link_url + "/download" |
||||
|
response = requests.get(doc_link) |
||||
|
hugo_header = '---\ntitle: "' + node["name"] + '"\n---\n\n' |
||||
|
content = parse_for_notice( |
||||
|
response.content.decode("utf-8") |
||||
|
).encode("utf-8") |
||||
|
content = parse_for_toc(content.decode("utf-8")).encode("utf-8") |
||||
|
f.write(hugo_header.encode("utf-8")) |
||||
|
f.write(content.replace(b"---", b"")) |
||||
|
print("Downloaded", doc_link, "to", file_path) |
||||
|
|
||||
|
|
||||
|
def generate_book_layout(node): |
||||
|
"""Copy the defaults layout repository 'docs' for the new/other books""" |
||||
|
layout_dir = "./themes/lotusdocs/layouts/" |
||||
|
layout_docs_dir = os.path.join(layout_dir, "docs") |
||||
|
layout_book_dir = os.path.join(layout_dir, node["technical_name"]) |
||||
|
# copy book layout folder from "layouts/docs" if it doesn't exist |
||||
|
if not os.path.exists(layout_book_dir): |
||||
|
# create the layout for the book |
||||
|
copytree(layout_docs_dir, layout_book_dir) |
||||
|
|
||||
|
|
||||
|
def generate_book_menu(node, weight): |
||||
|
"""Generate the menu displayed in the home page""" |
||||
|
book_config = { |
||||
|
"name": node["name"], |
||||
|
"url": node["technical_name"] + "/", |
||||
|
"identifier": node["technical_name"], |
||||
|
"weight": weight, |
||||
|
} |
||||
|
return book_config |
||||
|
|
||||
|
def generate_book_config(node): |
||||
|
"""Generate configuration for each book""" |
||||
|
book_config = { |
||||
|
"title": node["name"], |
||||
|
"darkMode": True |
||||
|
} |
||||
|
return book_config |
||||
|
|
||||
|
|
||||
|
def parse_json_file(json_file_path): |
||||
|
content_dir = "./content/" |
||||
|
config_path ="./hugo.toml" |
||||
|
# new_config_path = "./config_new.toml" # TO DELETE WHEN SCRIPT FINISHED |
||||
|
config_data_dict = toml.load(config_path) |
||||
|
|
||||
|
# Retrieve the init json data |
||||
|
with open(json_file_path, 'r') as json_file: |
||||
|
json_data = json.load(json_file) |
||||
|
|
||||
|
|
||||
|
if not os.path.exists(content_dir): |
||||
|
# Create content directory if it doesn't exist |
||||
|
os.makedirs(content_dir) |
||||
|
else: |
||||
|
# Delete the content directories files and sub-directories |
||||
|
rmtree(content_dir) |
||||
|
|
||||
|
nb_books = 0 |
||||
|
primary_menu = [] |
||||
|
books_config = [] |
||||
|
config_data_dict.update({"params": {}}) |
||||
|
# Loop on the json structure to build repositories and files |
||||
|
for book_node in json_data["books"]: |
||||
|
nb_books +=1 |
||||
|
generate_directory_structure_and_files(book_node) |
||||
|
generate_book_layout(book_node) |
||||
|
primary_menu.append(generate_book_menu(book_node, nb_books)) |
||||
|
# books_config.append(generate_book_config(book_node)) |
||||
|
config_data_dict["params"]["%s" % book_node["technical_name"]] = generate_book_config(book_node) |
||||
|
|
||||
|
|
||||
|
# Add the primary menu data to the whole config |
||||
|
config_data_dict.update({"menu": {"primary": primary_menu}}) |
||||
|
#config_data_dict.update({"params": {"primary": primary_menu}}) |
||||
|
print("WHOLE CONFIG") |
||||
|
print(config_data_dict) |
||||
|
|
||||
|
# Replace the config.toml content with the new params |
||||
|
with open(config_path, 'w') as toml_file: |
||||
|
toml.dump(config_data_dict, toml_file) |
||||
|
|
||||
|
|
||||
|
|
||||
|
parse_json_file("structure.json") |
||||
|
|
@ -1,109 +0,0 @@ |
|||||
import io |
|
||||
import os |
|
||||
from bs4 import BeautifulSoup, Comment |
|
||||
import markdown |
|
||||
import ipdb |
|
||||
|
|
||||
parent_dir = "./content" |
|
||||
|
|
||||
|
|
||||
def parse_markdown_file(file_path): |
|
||||
with open(file_path, "r") as file: |
|
||||
markdown_text = file.read() |
|
||||
html = markdown.markdown(markdown_text) |
|
||||
print(html) |
|
||||
headings = [] |
|
||||
current_level = 0 |
|
||||
for line in html.split("\n"): |
|
||||
if line.startswith("<h1>"): |
|
||||
current_level = 1 |
|
||||
headings.append( |
|
||||
{"level": current_level, "text": line[4:-5], "children": []} |
|
||||
) |
|
||||
elif line.startswith("<h2>"): |
|
||||
if current_level < 2: |
|
||||
current_level = 2 |
|
||||
headings[-1]["children"].append( |
|
||||
{"level": current_level, "text": line[4:-5], "children": []} |
|
||||
) |
|
||||
else: |
|
||||
headings[-1]["children"].append( |
|
||||
{"level": current_level, "text": line[4:-5], "children": []} |
|
||||
) |
|
||||
elif line.startswith("<h3>"): |
|
||||
if current_level < 3: |
|
||||
current_level = 3 |
|
||||
headings[-1]["children"][-1]["children"].append( |
|
||||
{"level": current_level, "text": line[4:-5], "children": []} |
|
||||
) |
|
||||
else: |
|
||||
headings[-1]["children"][-1]["children"].append( |
|
||||
{"level": current_level, "text": line[4:-5], "children": []} |
|
||||
) |
|
||||
return headings |
|
||||
|
|
||||
|
|
||||
def parse_markdown_file_2(file_path): |
|
||||
with open(file_path, "r", encoding="utf-8") as f: |
|
||||
content = f.read() |
|
||||
html = markdown.markdown(content) |
|
||||
print(html) |
|
||||
soup = BeautifulSoup(html, "html.parser") |
|
||||
headings = [] |
|
||||
|
|
||||
def parse_element(element, level): |
|
||||
print(element) |
|
||||
if element.name == "h1": |
|
||||
heading = { |
|
||||
"text": element.text.strip(), |
|
||||
"level": level, |
|
||||
"subheadings": [], |
|
||||
"links": [], |
|
||||
} |
|
||||
headings.append(heading) |
|
||||
elif element.name == "h2": |
|
||||
subheading = { |
|
||||
"text": element.text.strip(), |
|
||||
"level": level, |
|
||||
"subheadings": [], |
|
||||
"links": [], |
|
||||
} |
|
||||
headings[-1]["subheadings"].append(subheading) |
|
||||
elif element.name == "h3": |
|
||||
subsubheading = {"text": element.text.strip(), "level": level, "links": []} |
|
||||
headings[-1]["subheadings"][-1]["subheadings"].append(subsubheading) |
|
||||
elif element.name == "ul": |
|
||||
links = [] |
|
||||
for li in element.find_all("li"): |
|
||||
link = li.find("a") |
|
||||
if link is not None: |
|
||||
links.append({"text": link.text.strip(), "url": link["href"]}) |
|
||||
if level == 1: |
|
||||
headings[-1]["links"].extend(links) |
|
||||
elif level == 2: |
|
||||
headings[-1]["subheadings"][-1]["links"].extend(links) |
|
||||
elif level == 3: |
|
||||
headings[-1]["subheadings"][-1]["subheadings"][-1]["links"].extend( |
|
||||
links |
|
||||
) |
|
||||
|
|
||||
for child in element.children: |
|
||||
if isinstance(child, str) or isinstance(child, Comment): |
|
||||
continue |
|
||||
parse_element(child, level + 1) |
|
||||
|
|
||||
parse_element(soup, 0) |
|
||||
|
|
||||
return headings |
|
||||
|
|
||||
|
|
||||
headings = parse_markdown_file_2("content/posts/my-first-post.md") |
|
||||
print(headings) |
|
||||
for heading in headings: |
|
||||
print(f"Titre de niveau {heading['level']}: {heading['text']}") |
|
||||
for subheading in heading["children"]: |
|
||||
print(f" Sous-titre de niveau {subheading['level']}: {subheading['text']}") |
|
||||
for subsubheading in subheading["children"]: |
|
||||
print( |
|
||||
f" Sous-sous-titre de niveau {subsubheading['level']}: {subsubheading['text']}" |
|
||||
) |
|
@ -1,160 +0,0 @@ |
|||||
import os |
|
||||
import re |
|
||||
import requests |
|
||||
from bs4 import BeautifulSoup |
|
||||
import markdown |
|
||||
|
|
||||
|
|
||||
def parse_for_toc(content): |
|
||||
# TODO: ADD .TableofContent directly to the page (see hugo theme ?) |
|
||||
content = content.replace("[TOC]", "") |
|
||||
return content |
|
||||
|
|
||||
|
|
||||
def parse_for_notice(content): |
|
||||
result = re.findall(":::warning.*?:::", content, re.MULTILINE | re.DOTALL) |
|
||||
for notice in result: |
|
||||
old = notice |
|
||||
content = content.replace( |
|
||||
old, |
|
||||
notice.replace(":::warning", "{{% notice info %}}").replace( |
|
||||
":::", "{{% /notice %}}" |
|
||||
), |
|
||||
) |
|
||||
result = re.findall(":::info.*?:::", content, re.MULTILINE | re.DOTALL) |
|
||||
for notice in result: |
|
||||
old = notice |
|
||||
content = content.replace( |
|
||||
old, |
|
||||
notice.replace(":::info", "{{% notice note %}}").replace( |
|
||||
":::", "{{% /notice %}}" |
|
||||
), |
|
||||
) |
|
||||
result = re.findall(":::success.*?:::", content, re.MULTILINE | re.DOTALL) |
|
||||
for notice in result: |
|
||||
old = notice |
|
||||
content = content.replace( |
|
||||
old, |
|
||||
notice.replace(":::success", "{{% notice tip %}}").replace( |
|
||||
":::", "{{% /notice %}}" |
|
||||
), |
|
||||
) |
|
||||
result = re.findall(":::danger.*?:::", content, re.MULTILINE | re.DOTALL) |
|
||||
for notice in result: |
|
||||
old = notice |
|
||||
content = content.replace( |
|
||||
old, |
|
||||
notice.replace(":::danger", "{{% notice warning %}}").replace( |
|
||||
":::", "{{% /notice %}}" |
|
||||
), |
|
||||
) |
|
||||
# print(content) |
|
||||
return content |
|
||||
|
|
||||
|
|
||||
def parse_markdown_file(markdown_file_path, base_dir="./"): |
|
||||
with open(markdown_file_path, "r") as f: |
|
||||
markdown_text = f.read() |
|
||||
|
|
||||
html = markdown.markdown(markdown_text, extensions=["fenced_code"]) |
|
||||
|
|
||||
soup = BeautifulSoup(html, "html.parser") |
|
||||
|
|
||||
if not os.path.exists(base_dir): |
|
||||
os.makedirs(base_dir) |
|
||||
|
|
||||
current_heading_level = 1 |
|
||||
current_heading_dir = base_dir |
|
||||
last_heading_dir = base_dir |
|
||||
|
|
||||
for element in soup.children: |
|
||||
if element.name in ["h1", "h2", "h3"]: |
|
||||
# Get the text of the heading and the heading level |
|
||||
heading_text = element.text.strip() |
|
||||
heading_level = int(element.name[1]) |
|
||||
|
|
||||
# Determine the directory to create for the heading |
|
||||
print( |
|
||||
"heading_level: %s(%s) , heading_text: %s, base_dir: %s, last_heading_dir: %s, current_heading_dir: %s " |
|
||||
% ( |
|
||||
heading_level, |
|
||||
current_heading_level, |
|
||||
heading_text, |
|
||||
base_dir, |
|
||||
last_heading_dir, |
|
||||
current_heading_dir, |
|
||||
) |
|
||||
) |
|
||||
if heading_level == 1: |
|
||||
heading_dir = os.path.join(base_dir, heading_text) |
|
||||
current_heading_dir = heading_dir |
|
||||
last_heading_dir = base_dir |
|
||||
elif heading_level == current_heading_level: |
|
||||
heading_dir = os.path.join( |
|
||||
os.path.dirname(current_heading_dir), heading_text |
|
||||
) |
|
||||
last_heading_dir = heading_dir |
|
||||
current_heading_dir = heading_dir |
|
||||
elif heading_level >= current_heading_level: |
|
||||
heading_dir = os.path.join(current_heading_dir, heading_text) |
|
||||
last_heading_dir = current_heading_dir |
|
||||
current_heading_dir = heading_dir |
|
||||
else: |
|
||||
print("NOT SUPPORTED YET") |
|
||||
|
|
||||
if not os.path.exists(heading_dir): |
|
||||
os.makedirs(heading_dir) |
|
||||
# add _index.md for page organization |
|
||||
with open(heading_dir + "/_index.md", "wb") as f: |
|
||||
print("Created", heading_dir + "/_index.md") |
|
||||
index = """ |
|
||||
+++ |
|
||||
title = "{heading_text}" |
|
||||
chapter = true |
|
||||
weight = 5 |
|
||||
+++ |
|
||||
|
|
||||
# {heading_text} |
|
||||
|
|
||||
Discover what this Hugo theme is all about and the core-concepts behind it. |
|
||||
""".format( |
|
||||
heading_text=heading_text |
|
||||
) |
|
||||
f.write(b"%s" % index.encode("utf-8")) |
|
||||
|
|
||||
# Set the current heading level and directory |
|
||||
current_heading_level = heading_level |
|
||||
# last_heading_dir = current_heading_dir |
|
||||
# current_heading_dir = heading_dir |
|
||||
|
|
||||
elif element.name == "hr": |
|
||||
current_heading_level = 0 |
|
||||
current_heading_dir = base_dir |
|
||||
|
|
||||
elif element.name == "ul" and current_heading_level != 0: |
|
||||
# Get the links in the list |
|
||||
links = element.find_all("a") |
|
||||
for link in links: |
|
||||
# Get the text and href of the link |
|
||||
link_text = link.text.strip() |
|
||||
link_url = link["href"] |
|
||||
|
|
||||
file_path = os.path.join( |
|
||||
current_heading_dir, os.path.basename(link_text) |
|
||||
) |
|
||||
if link_url: |
|
||||
with open(file_path + ".md", "wb") as f: |
|
||||
doc_link = link_url + "/download" |
|
||||
response = requests.get(doc_link) |
|
||||
hugo_header = '---\ntitle: "' + link_text + '"\n---\n\n' |
|
||||
content = parse_for_notice( |
|
||||
response.content.decode("utf-8") |
|
||||
).encode("utf-8") |
|
||||
content = parse_for_toc(content.decode("utf-8")).encode("utf-8") |
|
||||
f.write(hugo_header.encode("utf-8")) |
|
||||
f.write(content.replace(b"---", b"")) |
|
||||
print("Downloaded", doc_link, "to", file_path) |
|
||||
|
|
||||
|
|
||||
headings = parse_markdown_file("content/my-first-post.md", base_dir="./content") |
|
||||
print(headings) |
|
@ -0,0 +1,38 @@ |
|||||
|
baseURL = "http://example.org/" |
||||
|
languageCode = "en-us" |
||||
|
title = "My New Hugo Site" |
||||
|
|
||||
|
[outputs] |
||||
|
home = [ "HTML", "RSS", "JSON",] |
||||
|
|
||||
|
[module] |
||||
|
replacements = "github.com/colinwilson/lotusdocs -> lotusdocs" |
||||
|
[[module.imports]] |
||||
|
path = "github.com/colinwilson/lotusdocs" |
||||
|
disable = false |
||||
|
|
||||
|
[[module.imports]] |
||||
|
path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5" |
||||
|
disable = false |
||||
|
|
||||
|
[menu] |
||||
|
[[menu.primary]] |
||||
|
name = "User guide" |
||||
|
url = "user/" |
||||
|
identifier = "user" |
||||
|
weight = 1 |
||||
|
|
||||
|
[[menu.primary]] |
||||
|
name = "Developper guide" |
||||
|
url = "dev/" |
||||
|
identifier = "dev" |
||||
|
weight = 2 |
||||
|
|
||||
|
[params] |
||||
|
[[params.user]] |
||||
|
title = "User guide" |
||||
|
darkMode = true |
||||
|
|
||||
|
[[params.dev]] |
||||
|
title = "Developper guide" |
||||
|
darkMode = true |
@ -0,0 +1,26 @@ |
|||||
|
|
||||
|
|
||||
|
def get_hugo_config_content(): |
||||
|
content = """ |
||||
|
baseURL = 'http://example.org/' |
||||
|
languageCode = 'en-us' |
||||
|
title = 'My New Hugo Site' |
||||
|
|
||||
|
[module] |
||||
|
[[module.imports]] |
||||
|
path = "github.com/colinwilson/lotusdocs" |
||||
|
disable = false |
||||
|
[[module.imports]] |
||||
|
path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5" |
||||
|
disable = false |
||||
|
""" |
||||
|
return content |
||||
|
|
||||
|
# Get TOML file content |
||||
|
toml_content = get_hugo_config_content() |
||||
|
|
||||
|
# Write the content in a hugo.toml file |
||||
|
with open('hugo.toml', 'w') as file: |
||||
|
file.write(toml_content) |
||||
|
|
||||
|
print("File hugo.toml generated with success.") |
@ -0,0 +1,76 @@ |
|||||
|
{ |
||||
|
"books": [ |
||||
|
{ |
||||
|
"technical_name": "user", |
||||
|
"name": "User guide", |
||||
|
"children": [ |
||||
|
{ |
||||
|
"technical_name": "menu1-1", |
||||
|
"name": "Menu 1.1", |
||||
|
"children": [ |
||||
|
{ |
||||
|
"technical_name": "new_support", |
||||
|
"name": "Nouveau fonctionnement du support Lokavaluto", |
||||
|
"url": "https://docs.lokavaluto.fr/MAI9LEmBTH6hB6II6xUTxA" |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "old_support", |
||||
|
"name": "Ancien fonctionnement du support Lokavaluto et pourquoi cela ne convenait pas", |
||||
|
"url": "https://docs.lokavaluto.fr/S6uGRvQ-Rl25LiyCgPQvzg" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "menu1-2", |
||||
|
"name": "Menu 1.2", |
||||
|
"children": [ |
||||
|
{ |
||||
|
"technical_name": "pres_general", |
||||
|
"name": "Présentation et interface générale", |
||||
|
"url": "https://docs.lokavaluto.fr/tgJjJkHfS_OZwj0JWvHsKw" |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "old_support", |
||||
|
"name": "Ancien fonctionnement du support Lokavaluto et pourquoi cela ne convenait pas" |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "menu1-2-1", |
||||
|
"name": "Menu 1.2.1", |
||||
|
"children": [ |
||||
|
{ |
||||
|
"technical_name": "prospe_management", |
||||
|
"name": "Gestion de la prospection (CRM)", |
||||
|
"url": "https://docs.lokavaluto.fr/oE_BiLb_RwyrrRwvElbBWw" |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "contact_management", |
||||
|
"name": "Gestion des contacts, des membres et cartographie", |
||||
|
"url": "https://docs.lokavaluto.fr/apAZA45PRwa0Cj5F1i8UDQ" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "menu1-2-2", |
||||
|
"name": "Menu 1.2.2", |
||||
|
"children": [ |
||||
|
{ |
||||
|
"technical_name": "project_management", |
||||
|
"name": "Gestion de projet", |
||||
|
"url": "https://docs.lokavaluto.fr/UYHemvLrQPewS0HlHEJSvQ" |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "event_management", |
||||
|
"name": "Gestion d'événements" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"technical_name": "dev", |
||||
|
"name": "Developper guide" |
||||
|
} |
||||
|
] |
||||
|
} |
@ -1,5 +1,29 @@ |
|||||
#!/bin/bash |
#!/bin/bash |
||||
|
|
||||
python generate_v3.py |
|
||||
|
# Init hugo config file |
||||
|
python init_hugo_toml.py |
||||
|
|
||||
# find ./content -type f -exec sed -i 's/---/____/g' {} \; |
|
||||
|
# Start Hugo server in the background. This will import/update Lotusdocs module. |
||||
|
# The import of the module is important to get the themes files, because some of |
||||
|
# the sub-directories must be adapted to the future doc structure. |
||||
|
hugo server > init_hugo.log 2>&1 & |
||||
|
|
||||
|
# Wait for the end of the initialization process and stop hugo |
||||
|
while true; do |
||||
|
if grep -q "Web Server is available" init_hugo.log; then |
||||
|
# Initialization done |
||||
|
echo "Initialization complete. Web Server is available." |
||||
|
|
||||
|
# Get the PID of the Hugo process and store it in a file for later use |
||||
|
pgrep -f "hugo server" | kill |
||||
|
# You can stop the loop if you don't need to monitor the log anymore |
||||
|
break |
||||
|
fi |
||||
|
sleep 1 |
||||
|
done |
||||
|
# We don't need init_hugo.log anymore |
||||
|
rm init_hugo.log |
||||
|
|
||||
|
|
||||
|
# Generate Hugo Lotusdoc website structure and config |
||||
|
python generate_lotusdocs.py |
Write
Preview
Loading…
Cancel
Save
Reference in new issue