From: Georgios Atheridis Date: Sun, 12 Feb 2023 00:10:33 +0000 (+0000) Subject: Generate Files from Directories X-Git-Url: https://git.atheridis.org/?a=commitdiff_plain;h=4f93b4194656c5485f6751bfbaf2ab0c71e6089c;p=personal%2Fsigma.git Generate Files from Directories Can compile output files with the same name as a directory. This allows for easier control over variable definitions, as it keeps the data.toml file smaller and can much more easily define multiline variables--such as scripts. Updated README, added a TODO list and added some more example pages that show sigma's functionality. --- diff --git a/README b/README index 180c63a..4df6195 100644 --- a/README +++ b/README @@ -1,21 +1,52 @@ sigma is a static site generator written in python -==================== +================================================== data.toml: +---------- It is used to define variables for each file. Variables in the root are -global and are inherited by their children. If a child has a variable of -the same name, then the child's variable is used instead. --------------------- +global and are inherited by their children. If a child has a variable +of the same name, then the child's variable is used instead. + +----------------------------------------------------------------------- Keywords: -_PAGE_ROOT: specifies the default page root -_TEMPLATES: specifies the template directory -_OUT: designates the directory where the output files go +--------- +- `_PAGE_ROOT` specifies the default page root +- `_TEMPLATES` specifies the template directory +- `_OUT` designates the directory where the output files go +- `_DATE_FORMAT` designates the date format to use when using `_date` + ++ `self` the file which invoked the template ++ `_extend` the template which the file should invoke ++ `_value` value of a file + +* `_name` defaults to file name without extension +* `_date` defaults to the mtime of the file, in case of a directory, + the latest mtime file within the directory is used. -self: the file which invoked the template -_extend: the template which the file should invoke -_value: value of a file +----------------------------------------------------------------------- -_name: defaults to file name without extension -_date: defaults to the mtime of the file --------------------- +Functionality: +-------------- +- Ability to use directories as page outputs. + ``` + pages/ + ├─ index.html + ├─ textfile.txt + ├─ posts/ + │ ├─ example.md + │ ├─ other.md + │ ├─ test.md + │ ├─ python-code.html/ + │ │ ├─ _value.md + │ │ ├─ _code.py + ├─ about.html/ + │ ├─ _value.md + │ ├─ _title.txt + │ ├─ _article.md + │ ├─ _test.py + ``` + Where the file names inside the directory become the variables of the + file. Python files are not run here, as they will often be used to + write code which can then be imported into the _value variable. Files + that are meant to be ran should go into the templates directory. diff --git a/TODO b/TODO new file mode 100644 index 0000000..d37fbc1 --- /dev/null +++ b/TODO @@ -0,0 +1,19 @@ +TODO +==== + +- Allow for a _build variable which will produce html files through + key-value pairs. Directories will also be able to be created by + having another key-value pair inside of the value. This will allow + for recursive creation of html files and directories. + + If the _build variable is a python file inside of the pages directory + it will run the python file and the _value variable inside the file + will result in the value of the _build variable. + +- Do not update files that haven't changed. Include data.toml values. + +- Allow any executable to be executed as a template. Its standard + output becomes the _value of that template. Make sure to transfer + appropriate data to the executable. + +- Add logging. diff --git a/pages/about.html/_article.md b/pages/about.html/_article.md new file mode 100644 index 0000000..43d7414 --- /dev/null +++ b/pages/about.html/_article.md @@ -0,0 +1,7 @@ +This is my **article** + +#### We have lists + +- many good reasons +- to choose lists +- they're awesome diff --git a/pages/about.html/_test.py b/pages/about.html/_test.py new file mode 100644 index 0000000..46a4fdd --- /dev/null +++ b/pages/about.html/_test.py @@ -0,0 +1,6 @@ +def hello_world(): + print("hello world") + + +if __name__ == "__main__": + hello_world() diff --git a/pages/about.html/_title.txt b/pages/about.html/_title.txt new file mode 100644 index 0000000..6965192 --- /dev/null +++ b/pages/about.html/_title.txt @@ -0,0 +1 @@ +Hello Title diff --git a/pages/about.html/_value.md b/pages/about.html/_value.md new file mode 100644 index 0000000..9f9bfd7 --- /dev/null +++ b/pages/about.html/_value.md @@ -0,0 +1,15 @@ +# This is a test + +## The title should be: {{ self._title }} + +with the following article: + +{{ self._article }} + +It was last edited on {{ self._date }} + +### Here we see the a python file + +```python +{{ self._test }} +``` diff --git a/pages/posts/example.md b/pages/posts/example.md index 5a8afd0..5a0ba54 100644 --- a/pages/posts/example.md +++ b/pages/posts/example.md @@ -1,3 +1,6 @@ +This *is a header* for +=== + # Hello ## Hello ### Hello @@ -8,16 +11,19 @@ Using a variable: {{ self._owner }} 1. This -1. Is -1. An -1. Ordered -1. List - +0. Is +0. An +0. Ordered +3. List * This * Is -* Not -* Ordered +- Not ++ Ordered + +> block +> +> quote --- @@ -25,13 +31,20 @@ Above me you will see a horizontal line as well as below me ---- +*** + + + + + _this is how you write in italics_ -**this is how you write in bold** +*this is how you also write in italics* + +__this is how you write in bold__ -~~And this is how you strikethrough~~ +**this is how you also write in bold** `this is a codeblock` diff --git a/pages/posts/python-code.html/_code.py b/pages/posts/python-code.html/_code.py new file mode 100644 index 0000000..ce6ddb5 --- /dev/null +++ b/pages/posts/python-code.html/_code.py @@ -0,0 +1,5 @@ +print("hello world") + +print("{{ self._title }}") + +print("The above won't get changed if you called this file with {! !}") diff --git a/pages/posts/python-code.html/_value.md b/pages/posts/python-code.html/_value.md new file mode 100644 index 0000000..8968ece --- /dev/null +++ b/pages/posts/python-code.html/_value.md @@ -0,0 +1,7 @@ +# Here is some python code inside my page + +

test

+```python +

test

+{! self._code !} +``` diff --git a/sigma b/sigma index e03b4ee..1f72c08 100755 --- a/sigma +++ b/sigma @@ -35,15 +35,43 @@ import markdown regex_extend = re.compile(r"^{%\s?extend (\"|')(.+)\1\s?%}$") regex_variable = re.compile(r"{{\s?(\S+)\s?}}") +regex_variable_no_interpret = re.compile(r"{!\s?(\S+)\s?!}") regex_execute = re.compile(r"{%\s?file (\"|')(.+)\1\s?%}") def md_to_html(md: str) -> str: - return markdown.markdown(md, extensions=["tables"]) + return markdown.markdown(md, extensions=["extra", "sane_lists"]) + + +def get_max_mtime(dir: str) -> float: + mtime = 0 + for f in os.walk(dir): + mtime = max( + map( + os.path.getmtime, + map(lambda file: os.path.join(f[0], file), f[2]), + ) + ) + return mtime def initialize_values(data: dict): for dir in os.walk(data["_PAGE_ROOT"]): + _, ext = os.path.splitext(dir[0]) + if ext: + rel_path = os.path.relpath(dir[0], data["_PAGE_ROOT"]) + mtime = get_max_mtime(dir[0]) + rel_path_no_type, _ = os.path.splitext(rel_path) + namespace = split_path(rel_path_no_type) + update_value(data, namespace, "_name", namespace[-1], False) + update_value( + data, + namespace, + "_date", + time.strftime(data["_DATE_FORMAT"], time.localtime(mtime)), + False, + ) + continue for file in dir[2]: path = os.path.join(dir[0], file) rel_path = os.path.relpath(path, data["_PAGE_ROOT"]) @@ -60,7 +88,38 @@ def initialize_values(data: dict): ) -def get_value(data: dict, namespace: tuple, key: str): +def get_value_from_file( + data: dict, namespace: tuple, key: str, interpret_ok: bool +) -> str | None: + path = os.path.join(data["_PAGE_ROOT"], *namespace[:-1]) + for dir in os.listdir(path): + dir_name, dir_ext = os.path.splitext(dir) + if namespace[-1] == dir_name: + break + else: + return + + if not os.path.isdir(os.path.join(path, dir_name + dir_ext)): + return + + for file in os.listdir(os.path.join(path, dir_name + dir_ext)): + file_name, file_ext = os.path.splitext(file) + if key == file_name: + with open(os.path.join(path, dir_name + dir_ext, file), "r") as file_in: + if interpret_ok: + _value = interpret(file_in.read(), data, namespace) + else: + _value = file_in.read() + if file_ext == ".md": + _value = md_to_html(_value) + return _value + + +def get_value(data: dict, namespace: tuple, key: str, interpret_ok=True): + if key != "_value" and ( + value := get_value_from_file(data, namespace, key, interpret_ok) + ): + return value value = data.get(key) for namespace_item in namespace: data = data.get(namespace_item, data) @@ -83,6 +142,27 @@ def split_path(path: str) -> tuple: return split_path(rest) + (tail,) +def interpret_no_recursion(file_value: str, data: dict, namespace: tuple) -> str: + start_pos = 0 + while variable := regex_variable_no_interpret.search(file_value, start_pos): + varspace = variable.group(1).split(".") + try: + varspace.remove("self") + except ValueError: + varspace = tuple(varspace) + else: + varspace = namespace + tuple(varspace) + repl_value = str(get_value(data, varspace[:-1], varspace[-1], False)) + start_pos = variable.start() + len(repl_value) + regex_variable_no_interpret.search(file_value, start_pos) + file_value = file_value.replace( + variable.group(0), + str(get_value(data, varspace[:-1], varspace[-1], False)), + 1, + ) + return file_value + + def interpret(file_value: str, data: dict, namespace: tuple) -> str: while regex_execute.search(file_value) or regex_variable.search(file_value): while file_to_run := regex_execute.search(file_value): @@ -110,24 +190,45 @@ def interpret(file_value: str, data: dict, namespace: tuple) -> str: file_value = regex_variable.sub( str(get_value(data, varspace[:-1], varspace[-1])), file_value, 1 ) + return file_value +def dir_to_file(file: str) -> dict[str, str]: + if not os.path.isdir(file): + return {"_value": file} + files = {} + for f in os.listdir(file): + files[os.path.splitext(f)[0]] = os.path.join(file, f) + return files + + def generate_output(file: str, data: dict, namespace: tuple) -> str: - _, file_type = os.path.splitext(file) - with open(file, "r") as in_file: + files = dir_to_file(file) + _, _value_file_type = os.path.splitext(files["_value"]) + with open(files["_value"], "r") as in_file: _value = in_file.read() if result := regex_extend.search(_value.splitlines()[0]): update_value(data, namespace, "_extend", result.group(2)) _value = _value.removeprefix(result.group(0) + "\n") _value = interpret(_value, data, namespace) - if file_type == ".md": + if _value_file_type == ".md": _value = md_to_html(_value) update_value(data, namespace, "_value", _value) if _extend := get_value(data, namespace, "_extend"): update_value(data, namespace, "_extend", "") generate_output(os.path.join(data["_TEMPLATES"], _extend), data, namespace) + + update_value( + data, + namespace, + "_value", + interpret_no_recursion( + str(get_value(data, namespace, "_value")), data, namespace + ), + ) + return str(get_value(data, namespace, "_value")) @@ -162,6 +263,10 @@ def main(args): if not args.pages: pages = [] for dir in os.walk(data["_PAGE_ROOT"]): + _, ext = os.path.splitext(dir[0]) + if ext: + pages.append(dir[0]) + continue for file in dir[2]: pages.append(os.path.join(dir[0], file)) else: diff --git a/templates/scripts/build_nav.py b/templates/scripts/build_nav.py index a2e5d45..46644f6 100644 --- a/templates/scripts/build_nav.py +++ b/templates/scripts/build_nav.py @@ -13,7 +13,7 @@ for page in os.listdir(data["_PAGE_ROOT"]): path = "/" + page page = os.path.splitext(page)[0] - links += '{{ pages.%(page)s._name }}' % { + links += '{{ %(page)s._name }}' % { "path": path, "page": page, }