Compare commits
30 Commits
c3c47e418d
...
0dd69c3fe3
Author | SHA1 | Date | |
---|---|---|---|
0dd69c3fe3 | |||
95003803eb | |||
fddbbf4c50 | |||
8b4765e9fb | |||
d83611f12a | |||
1eca81cd1d | |||
91a57aa8c9 | |||
3a9cc4c0f8 | |||
44bea9c982 | |||
5c8e1e5253 | |||
451bc567e2 | |||
80dce5d4ed | |||
48f64bf3d4 | |||
4e5bd41953 | |||
de3d758005 | |||
444c777135 | |||
9c6b2247a7 | |||
09334831f7 | |||
af5bef0125 | |||
b4aa431f4d | |||
49a215a587 | |||
0a0bd542fc | |||
36f40f3269 | |||
b61f1ba3b2 | |||
bef8aeda52 | |||
5bb40a57d1 | |||
29529cfd6a | |||
8bd9173847 | |||
dc4560c232 | |||
da0d9db113 |
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.git
|
||||||
|
.env
|
||||||
|
env
|
||||||
|
**/__pycache__
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
.env
|
||||||
env
|
env
|
||||||
n
|
n
|
||||||
web
|
web
|
||||||
planning.txt
|
planning.txt
|
||||||
__pycache__
|
**/__pycache__
|
||||||
|
31
Dockerfile
Normal file
31
Dockerfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
FROM python:3.12-bookworm
|
||||||
|
|
||||||
|
ARG ARCH=
|
||||||
|
|
||||||
|
ENV BUILDARCH=${ARCH}
|
||||||
|
ENV GRONK_CSS_DIR=./css
|
||||||
|
ENV GRONK_JS_DIR=./js
|
||||||
|
ENV GRONK_TEMPLATES_DIR=./templates
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN mkdir /notes
|
||||||
|
RUN mkdir /web
|
||||||
|
|
||||||
|
VOLUME /usr/src/app/notes
|
||||||
|
VOLUME /usr/src/app/web
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& wget -O ./pandoc.deb https://github.com/jgm/pandoc/releases/download/3.1.11/pandoc-3.1.11-1-${BUILDARCH}.deb \
|
||||||
|
&& apt install -y -f ./pandoc.deb \
|
||||||
|
&& rm ./pandoc.deb
|
||||||
|
|
||||||
|
COPY requirements.txt ./
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
RUN useradd -Ms /bin/nologin user
|
||||||
|
USER user
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD [ "python3", "-u", "gronk.py", "--output-dir", "./web", "./notes" ]
|
11
docker-compose.yml
Normal file
11
docker-compose.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
gronk:
|
||||||
|
build:
|
||||||
|
context: '.'
|
||||||
|
args:
|
||||||
|
ARCH: ${ARCH}
|
||||||
|
volumes:
|
||||||
|
- '${SOURCE}:/usr/src/app/notes'
|
||||||
|
- '${OUTPUT}:/usr/src/app/web'
|
64
gronk.py
64
gronk.py
@ -23,14 +23,15 @@ GRONK_COMMIT = "dev"
|
|||||||
|
|
||||||
PANDOC_SERVER_URL = os.getenv("PANDOC_SERVER_URL", r"http://localhost:3030/")
|
PANDOC_SERVER_URL = os.getenv("PANDOC_SERVER_URL", r"http://localhost:3030/")
|
||||||
PANDOC_TIMEOUT = int(os.getenv("PANDOC_TIMEOUT", "120"))
|
PANDOC_TIMEOUT = int(os.getenv("PANDOC_TIMEOUT", "120"))
|
||||||
GRONK_CSS_DIR = Path(os.getenv("CSS_DIR", "/opt/gronk/css"))
|
GRONK_CSS_DIR = Path(os.getenv("GRONK_CSS_DIR", "/opt/gronk/css"))
|
||||||
GRONK_JS_DIR = Path(os.getenv("JS_DIR", "/opt/gronk/js"))
|
GRONK_JS_DIR = Path(os.getenv("GRONK_JS_DIR", "/opt/gronk/js"))
|
||||||
GRONK_TEMPLATES_DIR = Path(os.getenv("TEMPLATES_DIR", "/opt/gronk/templates"))
|
GRONK_TEMPLATES_DIR = Path(
|
||||||
|
os.getenv("GRONK_TEMPLATES_DIR", "/opt/gronk/templates/"))
|
||||||
|
|
||||||
JINJA_ENV = jinja2.Environment(loader=jinja2.PackageLoader("gronk"),
|
JINJA_ENV = jinja2.Environment(
|
||||||
|
loader=jinja2.FileSystemLoader(searchpath=GRONK_TEMPLATES_DIR),
|
||||||
autoescape=jinja2.select_autoescape)
|
autoescape=jinja2.select_autoescape)
|
||||||
|
|
||||||
JINJA_TEMPLATES = {}
|
|
||||||
JINJA_TEMPLATE_TEXTARTICLE = JINJA_ENV.get_template("article-text.html")
|
JINJA_TEMPLATE_TEXTARTICLE = JINJA_ENV.get_template("article-text.html")
|
||||||
JINJA_TEMPLATE_HOME_INDEX = JINJA_ENV.get_template("home.html")
|
JINJA_TEMPLATE_HOME_INDEX = JINJA_ENV.get_template("home.html")
|
||||||
JINJA_TEMPLATE_INDEX = JINJA_ENV.get_template("index.html")
|
JINJA_TEMPLATE_INDEX = JINJA_ENV.get_template("index.html")
|
||||||
@ -117,8 +118,8 @@ class FileMap:
|
|||||||
'tags': [],
|
'tags': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
if 'index.md' in [f.name for f in filepath.iterdir()]:
|
if 'readme.md' in [f.name for f in filepath.iterdir()]:
|
||||||
with open(filepath.joinpath('index.md'),
|
with open(filepath.joinpath('readme.md'),
|
||||||
encoding='utf-8') as file_pointer:
|
encoding='utf-8') as file_pointer:
|
||||||
for key, val in frontmatter.load(
|
for key, val in frontmatter.load(
|
||||||
file_pointer).to_dict().items():
|
file_pointer).to_dict().items():
|
||||||
@ -138,6 +139,9 @@ class FileMap:
|
|||||||
entries = []
|
entries = []
|
||||||
|
|
||||||
for path in filepath.iterdir():
|
for path in filepath.iterdir():
|
||||||
|
if '.git' in path.parts:
|
||||||
|
continue
|
||||||
|
|
||||||
if path.is_dir():
|
if path.is_dir():
|
||||||
entry = self._get_directory_properties(
|
entry = self._get_directory_properties(
|
||||||
path, include_index_entries=False)
|
path, include_index_entries=False)
|
||||||
@ -354,7 +358,7 @@ def process_home_index(args, notes_git_head_sha1=None):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
post = {'title': 'gronk', 'content': ''}
|
post = {'title': 'gronk', 'content': ''}
|
||||||
custom_content_file = args.notes.joinpath('index.md')
|
custom_content_file = args.notes.joinpath('readme.md')
|
||||||
if custom_content_file.is_file():
|
if custom_content_file.is_file():
|
||||||
fmpost = frontmatter.loads(custom_content_file.read_text()).to_dict()
|
fmpost = frontmatter.loads(custom_content_file.read_text()).to_dict()
|
||||||
for key, val in fmpost.items():
|
for key, val in fmpost.items():
|
||||||
@ -434,6 +438,8 @@ def generate_tag_browser(output_dir):
|
|||||||
def main(args):
|
def main(args):
|
||||||
""" Entry point for script """
|
""" Entry point for script """
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
global LICENSE
|
global LICENSE
|
||||||
global FILEMAP
|
global FILEMAP
|
||||||
|
|
||||||
@ -462,7 +468,7 @@ def main(args):
|
|||||||
root_properties = FILEMAP.get(root)
|
root_properties = FILEMAP.get(root)
|
||||||
root_properties['dst_path']['raw'].mkdir(parents=True, exist_ok=True)
|
root_properties['dst_path']['raw'].mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
pprint.pprint(root_properties)
|
#pprint.pprint(root_properties)
|
||||||
html = JINJA_TEMPLATE_INDEX.render(
|
html = JINJA_TEMPLATE_INDEX.render(
|
||||||
gronk_commit=GRONK_COMMIT,
|
gronk_commit=GRONK_COMMIT,
|
||||||
title=root_properties.get('title', ''),
|
title=root_properties.get('title', ''),
|
||||||
@ -481,8 +487,8 @@ def main(args):
|
|||||||
|
|
||||||
# render each file
|
# render each file
|
||||||
for file in files:
|
for file in files:
|
||||||
# don't render index.md as index as it is used for directory
|
# don't render readme.md as index as it is used for directory
|
||||||
if file == "index.md":
|
if file == "readme.md":
|
||||||
continue
|
continue
|
||||||
render_file(root.joinpath(file))
|
render_file(root.joinpath(file))
|
||||||
|
|
||||||
@ -499,16 +505,44 @@ def main(args):
|
|||||||
generate_tag_browser(args.output_dir.joinpath('tags'))
|
generate_tag_browser(args.output_dir.joinpath('tags'))
|
||||||
generate_permalink_page(args.output_dir)
|
generate_permalink_page(args.output_dir)
|
||||||
|
|
||||||
|
elapsed_time = time.time() - start_time
|
||||||
|
print(f"generated notes {elapsed_time=}")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def start_pandoc_server():
|
||||||
|
"""
|
||||||
|
attempt to get the version of pandoc server in a loop until it is
|
||||||
|
successful and return version as string
|
||||||
|
"""
|
||||||
|
start_time = time.time()
|
||||||
|
process = subprocess.Popen(["/usr/bin/pandoc-server"],
|
||||||
|
stdout=subprocess.PIPE)
|
||||||
|
version = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
resp = requests.get(f"{PANDOC_SERVER_URL}/version")
|
||||||
|
version = resp.content.decode('utf-8')
|
||||||
|
break
|
||||||
|
except requests.ConnectionError:
|
||||||
|
time.sleep(0.1)
|
||||||
|
rc = process.poll()
|
||||||
|
if rc is not None:
|
||||||
|
print(f"PANDOC SERVER FAILED TO START: {rc=}")
|
||||||
|
print(process.stdout.read().decode("utf-8"))
|
||||||
|
raise Exception("Pandoc server failed to start")
|
||||||
|
|
||||||
|
elapsed_time = time.time() - start_time
|
||||||
|
print(f"pandoc-server started {version=} {elapsed_time=}")
|
||||||
|
return process
|
||||||
|
|
||||||
|
|
||||||
# TODO implement useful logging and debug printing
|
# TODO implement useful logging and debug printing
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
pandoc_process = subprocess.Popen(["/usr/bin/pandoc-server"],
|
pandoc_process = start_pandoc_server()
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
time.sleep(1)
|
|
||||||
print(pandoc_process.stdout)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.exit(main(get_args()))
|
sys.exit(main(get_args()))
|
||||||
|
56
readme.md
56
readme.md
@ -10,22 +10,39 @@ Tested with [pandoc v2.19.2](https://github.com/jgm/pandoc/releases/tag/2.19.2).
|
|||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
- View notes as a website, on any device
|
- View notes as a website, on any device
|
||||||
- Write notes with Pandoc markdown
|
|
||||||
- Easily share notes
|
- Easily share notes
|
||||||
|
- Powered by Pandoc, and therefore supports [Pandoc's markdown](https://pandoc.org/MANUAL.html#pandocs-markdown) (I mainly care about equations)
|
||||||
|
- [flatnotes](https://github.com/Dullage/flatnotes) is cool but I really would rather type my notes in Vim
|
||||||
- Lightweight HTML generated
|
- Lightweight HTML generated
|
||||||
- Minimal JavaScript
|
- Minimal JavaScript
|
||||||
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
0. Install [Pandoc](https://pandoc.org/index.html) and [Pip](https://github.com/pypa/pip)
|
### Docker
|
||||||
|
|
||||||
On arch:
|
Run the following, modifing the `-v` arguments as needed to mount the correct folders and
|
||||||
```
|
setting the value of `ARCH` to either `amd64` or `arm64` as appropriate.
|
||||||
# pacman -S pandoc python-pip
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Run `make install` as root
|
```
|
||||||
|
docker build . -t gronk --build-arg ARCH=amd64
|
||||||
|
docker run -v ./n:/usr/src/app/notes -v ./web:/usr/src/app/web gronk
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Compose
|
||||||
|
|
||||||
|
A [docker compose file](./docker-compose.yml) file has been provided.
|
||||||
|
|
||||||
|
Set the following environment variables (or create a .env file) and run `docker compose up`:
|
||||||
|
|
||||||
|
- `ARCH`
|
||||||
|
- `SOURCE`
|
||||||
|
- `OUTPUT`
|
||||||
|
|
||||||
|
### Locally
|
||||||
|
|
||||||
|
0. Install [Pandoc](https://pandoc.org/index.html) and [Pip](https://github.com/pypa/pip), python3-dev, and a C compiler
|
||||||
|
1. `sudo make install`
|
||||||
|
|
||||||
## Other Things to Know
|
## Other Things to Know
|
||||||
|
|
||||||
@ -34,9 +51,9 @@ Tested with [pandoc v2.19.2](https://github.com/jgm/pandoc/releases/tag/2.19.2).
|
|||||||
- gronk looks for the plaintext file `LICENSE` in the root directory of your notes
|
- gronk looks for the plaintext file `LICENSE` in the root directory of your notes
|
||||||
|
|
||||||
|
|
||||||
## Custom Directory Index
|
## Custom Directory Index and Metadata
|
||||||
|
|
||||||
To add custom content to a directory index, put it in a file called `index.md` under the directory.
|
To add custom content to a directory index, put it in a file called `readme.md` under the directory.
|
||||||
|
|
||||||
You can set the following frontmatter variables to customise the directory index of a directory:
|
You can set the following frontmatter variables to customise the directory index of a directory:
|
||||||
|
|
||||||
@ -44,7 +61,7 @@ You can set the following frontmatter variables to customise the directory index
|
|||||||
|------------------------|-------------------|--------------------------------------------------------------------------------------------|
|
|------------------------|-------------------|--------------------------------------------------------------------------------------------|
|
||||||
| `tags` | `[]` | list of tags, used by search and inherited by any notes and subdirectories |
|
| `tags` | `[]` | list of tags, used by search and inherited by any notes and subdirectories |
|
||||||
| `uuid` | none | unique id to reference directory, used for permalinking |
|
| `uuid` | none | unique id to reference directory, used for permalinking |
|
||||||
| `content_after_search` | `false` | show custom content in `index.md` after search bar and directory index |
|
| `content_after_search` | `false` | show custom content in `readme.md` after search bar and directory index |
|
||||||
| `automatic_index` | `true` | show the automatically generated directory index. required for search bar to function. |
|
| `automatic_index` | `true` | show the automatically generated directory index. required for search bar to function. |
|
||||||
| `search_bar` | `true` | show search bar to search directory items. requires `automatic_index` (enabled by default) |
|
| `search_bar` | `true` | show search bar to search directory items. requires `automatic_index` (enabled by default) |
|
||||||
|
|
||||||
@ -82,8 +99,8 @@ a file called `styles.css`.
|
|||||||
To add additional styling, the default styling will attempt to import `styles.css` from the root of the notes
|
To add additional styling, the default styling will attempt to import `styles.css` from the root of the notes
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
To add additional content to the homepage, create a file called `index.md` at the top level of your notes directory.
|
To add additional content to the homepage, create a file called `readme.md` at the top level of your notes directory.
|
||||||
To set the HTML `title` tag, set `title` in the frontmatter of `index.md`:
|
To set the HTML `title` tag, set `title` in the frontmatter of `readme.md`:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
@ -103,7 +120,18 @@ $ gronk.py notes_directory
|
|||||||
|
|
||||||
Output of `gronk.py --help`:
|
Output of `gronk.py --help`:
|
||||||
|
|
||||||
TODO add cli output
|
```
|
||||||
|
usage: gronk.py [-h] [-o OUTPUT_DIR] [-F] notes
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
notes
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
|
||||||
|
-F, --force Generate new output html even if source file was modified before output
|
||||||
|
html
|
||||||
|
```
|
||||||
|
|
||||||
The command will generate a website in the `output-dir` directory (`./web` by default).
|
The command will generate a website in the `output-dir` directory (`./web` by default).
|
||||||
It will then generate a list of all note files and put it in `index.html`.
|
It will then generate a list of all note files and put it in `index.html`.
|
||||||
@ -121,5 +149,3 @@ Then you just have to point a webserver at `output-dir`.
|
|||||||
Default synatx highlighting is based off [Pygments](https://pygments.org/)' default theme and
|
Default synatx highlighting is based off [Pygments](https://pygments.org/)' default theme and
|
||||||
made using Pandoc v2.7.2.
|
made using Pandoc v2.7.2.
|
||||||
I found the theme [here](https://github.com/tajmone/pandoc-goodies/blob/master/skylighting/css/built-in-styles/pygments.css).
|
I found the theme [here](https://github.com/tajmone/pandoc-goodies/blob/master/skylighting/css/built-in-styles/pygments.css).
|
||||||
|
|
||||||
Pretty sure the link colours are taken from [thebestmotherfucking.website](https://thebestmotherfucking.website/).
|
|
||||||
|
@ -11,7 +11,9 @@ oyaml==1.0
|
|||||||
pypandoc==1.5
|
pypandoc==1.5
|
||||||
python-frontmatter==1.0.0
|
python-frontmatter==1.0.0
|
||||||
python-magic==0.4.24
|
python-magic==0.4.24
|
||||||
PyYAML==6.0.1
|
PyYAML==5.3.1
|
||||||
|
regex==2021.11.10
|
||||||
|
soupsieve==2.2.1
|
||||||
regex==2021.11.10
|
regex==2021.11.10
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
smmap==5.0.1
|
smmap==5.0.1
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
<div id="content">
|
<div id="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<p class="smallText"> page generated by <a href="https://github.com/alvierahman90/gronk">gronk</a> (commit {{ gronk_commit }}) {% if notes_git_head_sha1 %}notes commit {{ notes_git_head_sha1 }}{% endif %}</p>
|
<p class="smallText"> page generated by <a href="https://github.com/alvierahman90/gronk">gronk</a> <!--(commit {{ gronk_commit }}) {% if notes_git_head_sha1 %}notes commit {{ notes_git_head_sha1 }}{% endif %}--></p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
Reference in New Issue
Block a user