From 49a215a5878b9d4fc384518fea77d2fc37bf4af2 Mon Sep 17 00:00:00 2001 From: Akbar Rahman Date: Tue, 2 Jan 2024 03:49:49 +0000 Subject: [PATCH] make gronk.py single file --- fileproperties.py | 188 -------------------------------------------- gronk.py | 195 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 189 insertions(+), 194 deletions(-) delete mode 100644 fileproperties.py diff --git a/fileproperties.py b/fileproperties.py deleted file mode 100644 index 118780f..0000000 --- a/fileproperties.py +++ /dev/null @@ -1,188 +0,0 @@ -from pathlib import Path -import frontmatter -import copy -import magic -import regex as re - - -class FileMap: - """ - this class is used to read file properties, inherit properties, and have a centralised place to access them - """ - def __init__(self, input_dir, output_dir): - self._map = {} - self.input_dir = Path(input_dir) - self.output_dir = Path(output_dir) - - @staticmethod - def _path_to_key(path): - return str(Path(path)) - - def get(self, filepath, default=None, raw=False): - """ - get the properties of a file at a filepath - raw=True to not inherit properties - """ - #print(f"FileMap.get({filepath=}, {default=}, {raw=})") - # TODO maybe store properties of a file once it's in built and mark it as built? might save time but also cba - if self._path_to_key(filepath) not in self._map.keys(): - self.add(filepath) - - properties = copy.deepcopy(self._map.get(self._path_to_key(filepath), default)) - #print(f"FileMap.get({filepath=}, {default=}, {raw=}): {properties=}") - - if raw: - return properties - - parent = filepath - while True: - parent = parent.parent - if parent == Path('.'): - break - - parent_properties = self.get(parent, raw=True) - # TODO inherit any property that isn't defined, append any lists that exist - properties['tags'] = properties.get('tags', []) + parent_properties.get('tags', []) - - if parent == self.input_dir: - break - - return properties - - def add(self, filepath): - filepath = Path(filepath) - #print(f"FileMap.add({filepath=}") - if filepath.is_dir(): - properties = self._get_directory_properties(filepath) - else: - properties = self._get_file_properties(filepath) - - properties['src_path'] = filepath - properties['dst_path'] = self._get_output_filepath(filepath) - - self._map[self._path_to_key(filepath)] = properties - - - def _get_directory_properties(self, filepath: Path, include_index_entries=True): - """ - return dict of directory properties to be used in pandoc template - """ - - post = { - 'title': filepath.name, - 'content_after_search': False, - 'automatic_index': True, - 'search_bar': True, - 'tags': [], - } - - if 'index.md' in filepath.iterdir(): - with open(filepath.joinpath('index.md'), encoding='utf-8') as file_pointer: - for key, val in frontmatter.load(file_pointer).to_dict(): - post[key] = val - - post['is_dir'] = True - - if include_index_entries: - post['index_entries'] = self._get_index_entries(filepath) - - return post - - - def _get_index_entries(self, filepath): - """ - return sorted list of index entries. alphabetically sorted, folders first - """ - entries = [] - - for path in filepath.iterdir(): - print(f'{path=}') - if path.is_dir(): - entry = self._get_directory_properties(path, include_index_entries=False) - else: - entry = self._get_file_properties(path) - - entry['path'] = self._get_output_filepath(path)['web'] - entries.append(entry) - #print(f"FileMap._get_index_entries({filepath=}): {entry=}") - - - entries.sort(key=lambda entry: str(entry.get('title', '')).lower()) - entries.sort(key=lambda entry: entry['is_dir'], reverse=True) - - return entries - - def _get_file_properties(self, filepath): - #print(f"FileMap._get_file_properties({filepath=}") - post = { 'title': filepath.name } - - if filepath.suffix == '.md': - with open(filepath, encoding='utf-8') as file_pointer: - post = frontmatter.load(file_pointer).to_dict() - - # don't store file contents in memory - if 'content' in post.keys(): - del post['content'] - post['is_dir'] = False - - return post - - - def _get_output_filepath(self, input_filepath): - - def webpath(filepath): - return Path('/notes').joinpath(filepath.relative_to(self.output_dir)) - - - r = {} - r['raw'] = self.output_dir.joinpath(input_filepath.relative_to(self.input_dir)) - r['web'] = webpath(r['raw']) - - if input_filepath.is_dir(): - return r - - if input_filepath.suffix == '.md': - r['html'] = self.output_dir.joinpath( - input_filepath.relative_to(self.input_dir) - ).with_suffix('.html') - r['web'] = webpath(r['html']) - - elif self.is_plaintext(input_filepath): - r['html'] = self.output_dir.joinpath( - input_filepath.relative_to(self.input_dir) - ).with_suffix(input_filepath.suffix + '.html') - r['raw'] = self.output_dir.joinpath(input_filepath.relative_to(self.input_dir)) - r['web'] = webpath(r['html']) - - #print(f"{r=}") - - return r - - - def to_list(self): - return [ val for _, val in self._map.items() ] - - - def to_search_data(self): - """ - returns list of every file in map - """ - r = [] - for _, val in self._map.items(): - r.append({ - 'title': val.get('title', ''), - 'tags': val.get('tags', []), - 'path': str(val['dst_path']['web']), - 'is_dir': val['is_dir'] - }) - - return r - - - @staticmethod - def is_plaintext(filename): - """ - check if file is a plaintext format, such as html, css, etc, - return boolean - """ - return re.match(r'^text/', magic.from_file(str(filename), mime=True)) is not None diff --git a/gronk.py b/gronk.py index 0cf00f1..4e0f61e 100755 --- a/gronk.py +++ b/gronk.py @@ -3,24 +3,23 @@ gronk --- view your notes as a static html site """ - import argparse import os from pathlib import Path import shutil import sys +import subprocess +import copy +import time +import magic +import regex as re import pprint -import json - import frontmatter import git import jinja2 import requests -from fileproperties import FileMap - - GRONK_COMMIT = "dev" PANDOC_SERVER_URL = os.getenv("PANDOC_SERVER_URL", r"http://localhost:3030/") @@ -47,6 +46,190 @@ GIT_REPO = None FILEMAP = None +class FileMap: + """ + this class is used to read file properties, inherit properties, + and have a centralised place to access them + """ + + def __init__(self, input_dir, output_dir): + self._map = {} + self.input_dir = Path(input_dir) + self.output_dir = Path(output_dir) + + @staticmethod + def _path_to_key(path): + return str(path) + + @staticmethod + def is_plaintext(filename): + return re.match(r'^text/', magic.from_file(str(filename), + mime=True)) is not None + + def add(self, filepath): + filepath = Path(filepath) + if filepath.is_dir(): + properties = self._get_directory_properties(filepath) + else: + properties = self._get_file_properties(filepath) + + properties['src_path'] = filepath + properties['dst_path'] = self._get_output_filepath(filepath) + + self._map[self._path_to_key(filepath)] = properties + + def get(self, filepath, default=None, raw=False): + """ + get the properties of a file at a filepath + raw=True to not inherit properties + """ + # TODO maybe store properties of a file once it's in built and mark it + # as built? might save time but also cba + if self._path_to_key(filepath) not in self._map.keys(): + self.add(filepath) + + properties = copy.deepcopy( + self._map.get(self._path_to_key(filepath), default)) + + if raw: + return properties + + parent = filepath + while True: + parent = parent.parent + if parent == Path('.'): + break + + parent_properties = self.get(parent, raw=True) + # TODO inherit any property that isn't defined, append any lists + # that exist + properties['tags'] = properties.get( + 'tags', []) + parent_properties.get('tags', []) + + if parent == self.input_dir: + break + + return properties + + def _get_directory_properties(self, + filepath: Path, + include_index_entries=True): + post = { + 'title': filepath.name, + 'content_after_search': False, + 'automatic_index': True, + 'search_bar': True, + 'tags': [], + } + + if 'index.md' in [f.name for f in filepath.iterdir()]: + with open(filepath.joinpath('index.md'), + encoding='utf-8') as file_pointer: + for key, val in frontmatter.load( + file_pointer).to_dict().items(): + post[key] = val + + if 'content' in post.keys(): + post['content'] = render_markdown(post['content']) + + post['is_dir'] = True + + if include_index_entries: + post['index_entries'] = self._get_index_entries(filepath) + + return post + + def _get_index_entries(self, filepath): + entries = [] + + for path in filepath.iterdir(): + if path.is_dir(): + entry = self._get_directory_properties( + path, include_index_entries=False) + else: + entry = self._get_file_properties(path) + + entry['path'] = self._get_output_filepath(path)['web'] + entries.append(entry) + + entries.sort(key=lambda entry: str(entry.get('title', '')).lower()) + entries.sort(key=lambda entry: entry['is_dir'], reverse=True) + + return entries + + def _get_file_properties(self, filepath): + post = {'title': filepath.name} + + if filepath.suffix == '.md': + with open(filepath, encoding='utf-8') as file_pointer: + post = frontmatter.load(file_pointer).to_dict() + + # don't store file contents in memory + if 'content' in post.keys(): + del post['content'] + post['is_dir'] = False + + return post + + def _get_output_filepath(self, input_filepath): + + def webpath(filepath): + return Path('/notes').joinpath( + filepath.relative_to(self.output_dir)) + + r = {} + r['raw'] = self.output_dir.joinpath( + input_filepath.relative_to(self.input_dir)) + r['web'] = webpath(r['raw']) + + if input_filepath.is_dir(): + return r + + if input_filepath.suffix == '.md': + r['html'] = self.output_dir.joinpath( + input_filepath.relative_to( + self.input_dir)).with_suffix('.html') + r['web'] = webpath(r['html']) + + elif self.is_plaintext(input_filepath): + r['html'] = self.output_dir.joinpath( + input_filepath.relative_to( + self.input_dir)).with_suffix(input_filepath.suffix + + '.html') + r['raw'] = self.output_dir.joinpath( + input_filepath.relative_to(self.input_dir)) + r['web'] = webpath(r['html']) + + return r + + def to_list(self): + return [val for _, val in self._map.items()] + + def to_search_data(self): + """ + returns list of every file in map + """ + r = [] + for _, val in self._map.items(): + r.append({ + 'title': val.get('title', ''), + 'tags': val.get('tags', []), + 'path': str(val['dst_path']['web']), + 'is_dir': val['is_dir'] + }) + + return r + + def get_uuid_map(self): + d = {} + for _, val in self._map.items(): + if 'uuid' not in val.keys(): + continue + d[val['uuid']] = str(val['dst_path']['web']) + + return d + + def update_required(src_filepath, output_filepath): """ check if file requires an update,