From c5d7d48492f2e49df68cb3fd0203ad5573f42730 Mon Sep 17 00:00:00 2001 From: Digital Studium Date: Sun, 23 Jul 2023 11:30:22 +0300 Subject: [PATCH] Refactor --- crater.py | 144 ++++++++++++++++++++++++++--------------------- requirements.txt | 1 + 2 files changed, 81 insertions(+), 64 deletions(-) diff --git a/crater.py b/crater.py index a7c47f7..e28a4c8 100644 --- a/crater.py +++ b/crater.py @@ -1,10 +1,12 @@ import csv import os -import pathlib import shutil -import http.server -import socketserver +from functools import partial +from http.server import HTTPServer, SimpleHTTPRequestHandler +from pathlib import Path +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler from jinja2 import Environment, FileSystemLoader, select_autoescape import yaml import frontmatter @@ -12,45 +14,65 @@ import markdown import fire -translations = {} - -def copy_file(src, dst): - os.makedirs(os.path.dirname(dst), exist_ok=True) - shutil.copy2(src, dst) +from common.functions import * def load_translations(file_path, _dict): with open(file_path) as f: - reader = csv.DictReader(f, delimiter='|') - for row in reader: - _dict[row['id']] = row - del row['id'] + reader = csv.DictReader(f, delimiter='|') # + for row in reader: # проходим по строкам csv, каждая из которых является словарём + _dict[row['id']] = row # добавляем ключ - значение ключа id, значение - словарь row + del row['id'] # удаляем ключ по названием "id" из словаря row, так как его значение уже является ключом в словаре _dict +# Функции, доступные в теме def translate(id, language): global translations return translations[id][language] +translations = {} # здесь будут переводы от темы и от сайта +config = yaml.safe_load(read_file('config.yaml')) # Чиатем конфиг сайта +running = False # нужно для проверки -def develop(): - PORT = 8000 - os.chdir('public') - handler = http.server.SimpleHTTPRequestHandler - server = socketserver.TCPServer(("", PORT), handler) - print("Server started at port 8000. Press CTRL+C to close the server.") - try: - server.serve_forever() - except KeyboardInterrupt: - server.server_close() - print("Server Closed") +# класс для watchdog. +# При обнаружении изменений в папках content и themes/{config['theme']}, перегенерировать папку public +class Develop(FileSystemEventHandler): + def on_modified(self, event): + print(f'event type: {event.event_type} path : {event.src_path}') + crater() + def on_created(self, event): + print(f'event type: {event.event_type} path : {event.src_path}') + crater() + def on_deleted(self, event): + print(f'event type: {event.event_type} path : {event.src_path}') + crater() -def site_creator(prod=False): - global translations - # Read config of site - with open('config.yaml', 'r') as file: - config = yaml.safe_load(file) +# Функция для запуска веб-сервера +def start_httpd(directory: Path, port: int = 8000): + print(f"Listen on port {port}, serving from {directory}...") + handler = partial(SimpleHTTPRequestHandler, directory=directory) + httpd = HTTPServer(('localhost', port), handler) + httpd.serve_forever() + +# Функция для запуска разработки +def develop(prod): + global running + if not prod and not running: + event_handler = Develop() + observer = Observer() + observer.schedule(event_handler, path='content', recursive=True) + observer.schedule(event_handler, path=f"themes/{config['theme']}", recursive=True) + observer.start() + running = True + try: + start_httpd(directory='public') + except KeyboardInterrupt: + pass + +# Функция для генерации сайта +def crater(prod=False): # Load theme's jinja templates templates = Environment(loader=FileSystemLoader( f"themes/{config['theme']}/templates/"), autoescape=select_autoescape()) @@ -59,6 +81,7 @@ def site_creator(prod=False): base = templates.get_template("base.j2") # Load translations + global translations load_translations(f"themes/{config['theme']}/i18n.csv", translations) load_translations("i18n.csv", translations) @@ -71,69 +94,62 @@ def site_creator(prod=False): posts = {} # Create new public folder for language in config['languages']: - path = f"content/{language}" - content_dir = pathlib.Path(path) - content_files = content_dir.rglob("*.md") + content_dir = Path(f"content/{language}") posts[language] = {} # Create posts dict - for item in list(content_files): - with open(item, 'r') as f: - data = frontmatter.loads(f.read()) + for item in list(content_dir.rglob("*.md")): + post_data = frontmatter.loads(read_file(item)) post_path = str(item).replace( "content", "public").rstrip(".md") os.makedirs(post_path, exist_ok=True) + description = post_data.content.partition('')[0] content = "{% import 'shortcodes.j2' as shortcodes %}" + \ - markdown.markdown(data.content) + markdown.markdown(post_data.content) - content = templates.from_string(content).render() - description = content.partition('')[0] + content = templates.from_string(content).render() url = post_path.replace(f"public/{language}", "") - section = url.split('/')[1] + section = "/" if len(url.split('/')) == 2 else url.split('/')[1] - if not os.path.dirname(url) == "/": - posts[language].setdefault(section, {}) + posts[language].setdefault(section, {}) - posts[language][section][url] = { - 'title': data['title'], - 'description': description, - 'date': data['date'], - 'content': content - } + posts[language][section][url] = { + 'title': post_data['title'], + 'description': description, + 'date': post_data['date'], + 'content': content + } - image = data.get('image', None) - if image: - posts[language][section][url]['image'] = image - copy_file(f'assets{image}', f'public{image}') + image = post_data.get('image', None) + if image: + posts[language][section][url]['image'] = image + copy_file(f'assets{image}', f'public{image}') for section, urls in posts[language].items(): - html = base.render(config=config, section=section, - language=language, posts=posts) + if section != "/": + html = base.render(config=config, section=section, + language=language, posts=posts) - with open(f"public/{language}/{section}/index.html", 'w') as f: - f.write(html) + write_file(f"public/{language}/{section}/index.html", html) for url, post in urls.items(): html = base.render(config=config, post=post, language=language, url=url, posts=posts) - with open(f"public/{language}{url}/index.html", 'w') as f: - f.write(html) + write_file(f"public/{language}{url}/index.html", html) html = base.render(config=config, posts=posts, language=language, home=True) - with open(f"public/{language}/index.html", 'w') as f: - f.write(html) + write_file(f"public/{language}/index.html", html) - shutil.copytree('static', 'public', dirs_exist_ok=True) - shutil.copytree( - f"themes/{config['theme']}/static", 'public', dirs_exist_ok=True) - if not prod: - develop() + for source_folder in ('static', f"themes/{config['theme']}/static"): + shutil.copytree(source_folder, 'public', dirs_exist_ok=True) + + develop(prod) if __name__ == '__main__': - fire.Fire(site_creator) + fire.Fire(crater) diff --git a/requirements.txt b/requirements.txt index b43d1fc..8441e9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ python-frontmatter==1.0.0 PyYAML==6.0.1 six==1.16.0 termcolor==2.3.0 +watchdog==3.0.0