Skip to content

Commit

Permalink
(MAJOR) Merge pull request #69 from jamiefdhurst/feature/local-develo…
Browse files Browse the repository at this point in the history
…pment

Local Development
  • Loading branch information
jamiefdhurst authored Aug 12, 2024
2 parents b19cd28 + fb6074b commit 1ccaa97
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 58 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ jobs:
python-version: '3.12'
- name: Install Dependencies
run: |
python -m pip install setuptools
python setup.py develop
python -m pip install -r requirements.txt
- name: Generate Distribution
run: |
python -m blog.generate
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ jobs:
python-version: '3.12'
- name: Install Dependencies
run: |
python -m pip install setuptools pylint pytest requests-mock coverage
python setup.py develop
python -m pip install -r requirements.txt
- name: Test
run: |
coverage run -m pytest --verbose --junit-xml tests.xml
Expand Down
4 changes: 0 additions & 4 deletions MANIFEST.in

This file was deleted.

22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ static site.
You will require Python 3. Run the following to install required modules:

```bash
python3 -m pip installl -r requirements.txt
python3 setup.py develop
```

Expand All @@ -17,9 +18,28 @@ You can then generate the site using:
python3 -m blog.generate
```

To run a local Docker instance of Nginx to serve a generated set of files, run:

```bash
docker run --rm -d --name blog -v $(pwd)/docker/nginx.conf:/etc/nginx/nginx.conf:ro -v $(pwd)/dist:/usr/share/nginx/html -p 8080:80 nginx
```

You can then run the when-changed package to automatically generate the blog files anytime a change is made:

```bash
when-changed -r -1 articles blog -c python3 -m blog.generate
```

*(You must be using a virtual environment or your
Python bin files must be on your path for this to work.)*

Then head to http://localhost:8080 to view the results.

You can stop the docker container with `docker stop blog`.

## Testing

Testing uses Pytest - run it as follows:
Testing uses Pytest - run it as follows (installing the required modules too):

```bash
pytest --verbose
Expand Down
13 changes: 7 additions & 6 deletions blog/articles.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ def __init__(self, directory, filename):

self.filename = filename
try:
with open(directory + filename, encoding='UTF8') as file:
with open(directory + filename, encoding='UTF-8') as file:
self.contents = markdown(file.read(), extensions=['fenced_code'])
except FileNotFoundError as fnfe:
raise ArticleNotFoundException(f"Could not find article file {filename}") from fnfe
raise ArticleNotFoundException(f'Could not find article file {filename}') from fnfe

def get_contents(self):
return self.contents

def get_content_only(self):
title = self.find_title.search(self.contents)
summary = self.find_summary.search(self.contents)
contents = self.contents.replace(title.group(0), '')
contents = self.contents.replace(title.group(0), '')
if summary:
return contents.replace(summary.group(0), '')
return contents
Expand All @@ -34,7 +34,8 @@ def get_date(self):
find_date = re.compile(r'^(\d{4}-\d{2}-\d{2})_')
date = find_date.match(self.filename)
if not date:
raise InvalidDateForArticleException(f"Could not parse date for article {self.filename}")
raise InvalidDateForArticleException(
f'Could not parse date for article {self.filename}')
return datetime.datetime.strptime(date.group(1), '%Y-%m-%d')

def get_image(self):
Expand All @@ -55,7 +56,8 @@ def get_summary(self):
def get_title(self):
title = self.find_title.search(self.contents)
if not title:
raise InvalidTitleForArticleException(f"Could not parse title for article {self.filename}")
raise InvalidTitleForArticleException(
f'Could not parse title for article {self.filename}')
return title.group(1)


Expand All @@ -70,7 +72,6 @@ def __parse_articles(directory, files):
def get_article(directory, file):
return Article(directory, file + '.md')


def get_paginated_articles(directory, page=1, per_page=10):
files = [f for f in listdir(directory) if isfile(join(directory, f))]
files.sort()
Expand Down
2 changes: 1 addition & 1 deletion blog/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from os import environ
from os import environ

ARTICLES_DIR = environ.get('ARTICLES_DIR', default='articles/')
DIST_DIR = environ.get('DIST_DIR', default='dist/')
Expand Down
29 changes: 15 additions & 14 deletions blog/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import shutil
import sys
from jinja2 import Environment, PackageLoader, select_autoescape
from .articles import *
from .config import *
from .articles import get_all_articles, get_paginated_articles, get_pages
from .config import ARTICLES_DIR, DIST_DIR, VERSION

env = Environment(
loader=PackageLoader('blog'),
Expand All @@ -15,7 +15,7 @@ def render_template(file, **kwargs):
return template.render(**kwargs, version=VERSION)

def generate(articles_dir=ARTICLES_DIR, dist_dir=DIST_DIR):

# Create/clear dist folder
if os.path.isdir(dist_dir):
print('[INFO] Clearing existing output dir...')
Expand All @@ -26,46 +26,47 @@ def generate(articles_dir=ARTICLES_DIR, dist_dir=DIST_DIR):
# Get all articles and generate a page for each one
print('[INFO] Loading articles...')
items = get_all_articles(articles_dir)
print('[INFO] Loaded {} articles...'.format(len(items)))
print(f'[INFO] Loaded {len(items)} articles...')
for item in items:
print('[INFO] Rendering and writing {}...'.format(item.get_name()))
print(f'[INFO] Rendering and writing {item.get_name()}...')
rendered = render_template('view.html', article=item)
with open(dist_dir + item.get_name() + '.html', 'w') as output_file:
with open(dist_dir + item.get_name() + '.html', 'w', encoding='UTF-8') as output_file:
output_file.write(rendered)

# Generate sitemap
print('[INFO] Rendering and writing sitemap...')
rendered = render_template('sitemap.xml', articles=items)
with open(dist_dir + 'sitemap.xml', 'w') as output_file:
with open(dist_dir + 'sitemap.xml', 'w', encoding='UTF-8') as output_file:
output_file.write(rendered)

# Generate static pages (inc error pages)
for static_page in ['404', '500', 'now']:
print('[INFO] Rendering and writing {}...'.format(static_page))
print(f'[INFO] Rendering and writing {static_page}...')
rendered = render_template(static_page + '.html')
with open(dist_dir + static_page + '.html', 'w') as output_file:
with open(dist_dir + static_page + '.html', 'w', encoding='UTF-8') as output_file:
output_file.write(rendered)

# Generate home page and paginated elements
pages = get_pages(articles_dir)
print('[INFO] Found {} pages of articles...'.format(pages))
print(f'[INFO] Found {pages} pages of articles...')
for p in range(1, pages + 1):
print('[INFO] Rendering and writing index page {}...'.format(p))
print(f'[INFO] Rendering and writing index page {p}...')
paged_items = get_paginated_articles(articles_dir, p)
rendered = render_template(
'index.html',
articles=paged_items,
current_page=p,
pages=[None] * pages
)
with open(dist_dir + 'index.html' if p == 1 else dist_dir + 'index-{}.html'.format(p), 'w') as output_file:
with open(dist_dir + 'index.html' if p == 1 else dist_dir +
f'index-{p}.html', 'w', encoding='UTF-8') as output_file:
output_file.write(rendered)

# Copy static assets
print('[INFO] Copying static assets...')
shutil.copytree('blog/static', dist_dir + 'static')
print('Blog {} generated and output to {}'.format(VERSION, dist_dir))

print(f'Blog {VERSION} generated and written to {dist_dir}')

if __name__ == '__main__':
sys.exit(generate())
2 changes: 1 addition & 1 deletion blog/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h1><a href="/{{ article.get_name() }}">{{ article.get_title() }}</a></h1>
<ol>
{% for page in pages %}
<li class="{% if current_page == loop.index %}current{% endif %}">
<a href="/?page={{ loop.index }}">{{ loop.index }}</a>
<a href="/{% if loop.index > 1 %}?page={{ loop.index }}{% endif %}">{{ loop.index }}</a>
</li>
{% endfor %}
</ol>
Expand Down
40 changes: 40 additions & 0 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
keepalive_timeout 65;
gzip on;

server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;

if ($request_uri ~ \?page=(.*)) {
rewrite .* /index-$arg_page.html;
}

if ($request_uri ~ ^/([\w\-]+)$) {
rewrite .* $request_uri.html;
}
}
}
23 changes: 23 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
astroid==3.2.4
certifi==2024.7.4
charset-normalizer==3.3.2
coverage==7.6.1
dill==0.3.8
idna==3.7
iniconfig==2.0.0
isort==5.13.2
Jinja2==3.1.4
Markdown==3.6
MarkupSafe==2.1.5
mccabe==0.7.0
packaging==24.1
platformdirs==4.2.2
pluggy==1.5.0
pylint==3.2.6
pytest==8.3.2
requests==2.32.3
requests-mock==1.12.1
tomlkit==0.13.0
urllib3==2.2.2
watchdog==4.0.2
when-changed==0.3.0
15 changes: 0 additions & 15 deletions setup.cfg

This file was deleted.

12 changes: 0 additions & 12 deletions setup.py

This file was deleted.

0 comments on commit 1ccaa97

Please sign in to comment.