Skip to content

Commit

Permalink
Rationalize code folder/file structure
Browse files Browse the repository at this point in the history
* Add more explicit documentation
* Add docopt for handling init command
  • Loading branch information
comzeradd committed Jan 19, 2019
1 parent 07f2818 commit 6b0b3ef
Show file tree
Hide file tree
Showing 48 changed files with 183 additions and 78 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
*.pyc
node_modules
yarn-error.log
config.yml
public
build
dist
*.egg-info
7 changes: 2 additions & 5 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
include LICENSE *.md *.yml *.dist
recursive-include pages *
recursive-include posts *
recursive-include skel *
recursive-include templates *
include LICENSE *.md
recursive-include monopati *
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,49 @@

A minimalistic static content generator.

You can read the [relevant post](https://www.roussos.cc/2016/01/11/monopati/) on why. Monopati is inspired by other great minimalistic content generators, like [bucket3](https://github.com/vrypan/bucket3/) and [habu](https://github.com/botherder/habu).
You can read the [relevant post](https://www.roussos.cc/2016/01/11/monopati/) on why I started building this. Monopati is inspired by other great minimalistic content generators, like [bucket3](https://github.com/vrypan/bucket3/) and [habu](https://github.com/botherder/habu).

[![license](https://img.shields.io/badge/license-AGPL%203.0-6672D8.svg)](LICENSE)

## Usage

Clone the repository:
Install from pypi:

```
git clone https://github.com/comzeradd/monopati.git
sudo pip install monopati
```

Install dependencies:
On first run create the website folder:

```
pip install -r requirements.txt
monopati --path=mywebsite init
```

Use `posts`, `pages` folders for blog and static content respectively.

Use templates for adjusting UI to fit your needs.
[Jinja2](http://jinja.pocoo.org/) template engine is being used for
both templates and pages. [Markdown](https://en.wikipedia.org/wiki/Markdown)
for blog posts.

Copy configuration example and edit it to fit your site specifics.
This will create a folder named `mywebsite`. Inside that folder there is a
configuration example file that you should copy and edit to meet your needs.

```
cd mywebsite
cp config.yml.dist config.yml
```

Run monopati:
Finally, build your website:

```
./monopati.py
monopati render
```

This will generate all necessary files for serving the website.
Monopati doesn't create any subfolder for generating the files,
so it should be fairly easy to deploy it by just uploading the whole folder.
This will generate all necessary files for serving the website, under the
folder you picked as output in your configuration file.

### Structure

Use `posts`, `pages` folders for blog and static content respectively.

Use templates for adjusting UI to fit your needs.
[Jinja2](http://jinja.pocoo.org/) template engine is being used for
both templates and pages. [Markdown](https://en.wikipedia.org/wiki/Markdown)
for blog posts.

### Example

Expand Down
49 changes: 49 additions & 0 deletions bin/monopati
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2019 Nikos Roussos <nikos@roussos.cc>.
# This file is part of Monopati - https://github.com/comzeradd/monopati

# Monopati is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Monopati is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# See the file 'LICENSE' for more information.

"""
Usage:
monopati [options] init
monopati render
monopati --version
monopati -h, --help
Options:
-p, --path=<path> top directory of your website.
"""

from docopt import docopt
import sys

from monopati import __version__, helpers, render


if __name__ == '__main__':

args = docopt(__doc__, version=__version__)

if args['init']:
if args['--path']:
helpers.kickstart(args['--path'])
else:
print('Usage:\n\tmonopati --path=mywebsite init')
sys.exit()
elif args['render']:
render.generate_pages()
posts, tag_set = render.generate_posts()
render.generate_archive(posts, tag_set)
render.generate_feeds(posts, tag_set)
render.copy_static()
3 changes: 3 additions & 0 deletions monopati/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env python3

__version__ = '0.3.0'
39 changes: 39 additions & 0 deletions monopati/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (C) 2015-2019 Nikos Roussos <nikos@roussos.cc>.
# This file is part of Monopati - https://github.com/comzeradd/monopati

# Monopati is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Monopati is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# See the file 'LICENSE' for more information.

from os import path, mkdir, listdir
from shutil import copy2, copytree
import sys


def kickstart(folder):
dest = path.abspath(folder)

if not path.isdir(dest):
mkdir(dest)
print('Creating website folder...')
else:
print('Folder already exists')
sys.exit()

skel = path.join(path.dirname(path.abspath(__file__)), 'skel')

for item in listdir(skel):
s = path.join(skel, item)
d = path.join(dest, item)
if path.isdir(s):
copytree(s, d)
else:
copy2(s, d)
95 changes: 59 additions & 36 deletions monopati.py → monopati/render.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2019 Nikos Roussos <nikos@roussos.cc>.
# This file is part of Monopati - https://github.com/comzeradd/monopati

Expand All @@ -14,39 +13,54 @@

# See the file 'LICENSE' for more information.


from glob import glob
from jinja2 import Environment, FileSystemLoader
from markdown import Markdown
from os import path, listdir, makedirs, remove
from os import listdir, makedirs, remove, path
import re
from shutil import copy2, copytree, rmtree
import sys
import time
import yaml


try:
cfg = yaml.load(open('config.yml', 'r').read())
def _config():
"""
Parse the configuration yaml file.
"""
try:
cfg = yaml.load(open('config.yml', 'r').read())
except IOError:
print('No config.yml found. Copy config.yml-dist and edit it to fit your needs')
sys.exit(0)

try:
output = cfg['output']
except KeyError:
output = '.'
else:
if output.endswith('/'):
output = output[:-1]
cfg['output'] = '.'
return cfg

if output.endswith('/'):
output = output[:-1]

try:
makedirs(output)
except OSError:
pass
except IOError:
print('No config.yml found. Copy config.yml-dist and edit it to fit your needs')
sys.exit(0)

return cfg


def generate_pages():
"""
Generates all static pages from templates.
"""
print('Generating pages...')
cfg = _config()

env = Environment()
env.loader = FileSystemLoader(['pages', 'templates'])

for page in listdir('pages'):
print('Generating page {0}...'.format(page))
template = env.get_template(page)
Expand All @@ -57,11 +71,17 @@ def generate_pages():
'logo': cfg['logo'],
'rooturl': cfg['rooturl'],
'link': page})
with open(output + '/' + page, 'w') as file:
with open(cfg['output'] + '/' + page, 'w') as file:
file.write(html)


def generate_posts():
"""
Generates all posts from markdown.
"""
print('Generating posts...')
cfg = _config()

posts = []
alltags = []

Expand Down Expand Up @@ -94,7 +114,7 @@ def generate_posts():
shortdate = str.join('.', (year, month, day))

link = '{0}/'.format(path.join(year, month, day, slug))
postpath = path.join(output, link)
postpath = path.join(cfg['output'], link)
try:
makedirs(path.join(postpath))
except OSError:
Expand Down Expand Up @@ -155,10 +175,15 @@ def generate_posts():


def generate_archive(posts, tag_set):
"""
Generates blog archives.
"""
print('Generating blog archive...')
cfg = _config()

env = Environment()
env.loader = FileSystemLoader('templates')

tpl = env.get_template('blog.html')
html = tpl.render(dict(
sitename=cfg['sitename'],
Expand All @@ -167,7 +192,7 @@ def generate_archive(posts, tag_set):
title='blog',
posts=posts
))
with open(output + '/blog.html', 'w') as file:
with open(cfg['output'] + '/blog.html', 'w') as file:
file.write(html)

for tag in tag_set:
Expand All @@ -184,7 +209,7 @@ def generate_archive(posts, tag_set):
title='blog: #{0}'.format(tag),
posts=post_list
))
tagpath = path.join(output, 'tag', tag)
tagpath = path.join(cfg['output'], 'tag', tag)
try:
makedirs(tagpath)
except OSError:
Expand All @@ -194,12 +219,17 @@ def generate_archive(posts, tag_set):


def generate_feeds(posts, tag_set):
"""
Generates atom feeds
"""
print('Generating atom feed...')
cfg = _config()

updated = str(time.strftime('%Y-%m-%dT%H:%M:%SZ'))

env = Environment()
env.loader = FileSystemLoader('templates')

xml = env.get_template('feed.xml').render(
items=posts[:10],
sitename=cfg['sitename'],
Expand All @@ -209,7 +239,7 @@ def generate_feeds(posts, tag_set):
logo=cfg['logo'],
updated=updated
)
with open(output + '/feed.xml', 'w') as file:
with open(cfg['output'] + '/feed.xml', 'w') as file:
file.write(xml)

for tag in tag_set:
Expand All @@ -226,7 +256,7 @@ def generate_feeds(posts, tag_set):
tagtitle=' - {0}'.format(tag),
updated=updated
)
tagpath = path.join(output, 'tag', tag)
tagpath = path.join(cfg['output'], 'tag', tag)
try:
makedirs(tagpath)
except OSError:
Expand All @@ -236,28 +266,21 @@ def generate_feeds(posts, tag_set):


def copy_static():
dest = path.join(output, 'static')
"""
Updates static files.
"""
print('Updating static files...')
cfg = _config()

if cfg['output'] == '.':
return None

dest = path.join(cfg['output'], 'static')
if path.exists(dest):
rmtree(dest)
copytree('static', dest)

dest = path.join(output, 'favicon.ico')
dest = path.join(cfg['output'], 'favicon.ico')
if path.exists(dest):
remove(dest)
copy2('favicon.ico', dest)




def main():
generate_pages()
posts, tag_set = generate_posts()
generate_archive(posts, tag_set)
generate_feeds(posts, tag_set)

if output != '.':
copy_static()


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion config.yml.dist → monopati/skel/config.yml.dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sitename: blog title here
sitename: website title here
author: your name here
rooturl: https://example.com/
logo: avatar.png
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@
max-complexity = 23
max-line-length = 99
ignore = F403
exclude = *migrations/*

0 comments on commit 6b0b3ef

Please sign in to comment.