Compare commits

...

16 Commits
web ... master

Author SHA1 Message Date
e78f3e80c4 add example site 2018-07-21 02:39:08 +02:00
c59961093b add rss 2018-07-21 02:25:50 +02:00
18c77e71f2 add indexing in compile_all 2018-07-21 02:01:36 +02:00
4c7839728d Add compile_all command 2018-07-21 01:38:42 +02:00
5302b7dc78 fix default input dir for app command 2018-07-21 00:16:24 +02:00
Peppuz
b91d123334 Merge branch 'anew' of git://192.168.1.3/ciclostile into anew 2018-04-24 18:21:05 +02:00
Peppuz
df55fe032c Doc posts 2018-04-24 18:20:47 +02:00
04decbdf55 update readme 2018-04-24 18:19:27 +02:00
a32f16e07e add recursive search 2018-04-24 18:17:54 +02:00
eccff07b8f refactor cli interface 2018-04-24 18:09:02 +02:00
Peppuz
7d52b773b9 ignore pyc 2018-04-24 17:59:07 +02:00
Peppuz
24b62ab307 Merge branch 'anew' of git://192.168.1.3/ciclostile into anew 2018-04-24 17:57:36 +02:00
36ac6b8a80 web: add list api 2018-04-24 17:57:17 +02:00
98fd9a24d8 web: add list api 2018-04-24 17:55:59 +02:00
870d0fca44 add setup tools 2018-04-24 17:22:36 +02:00
e444d2b2f6 Refactor lib, add cli 2018-04-07 04:17:49 +02:00
18 changed files with 349 additions and 82 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.egg-info
*.pyc
test_site/
example/target/

View File

@ -10,14 +10,8 @@ Just run:
pip install .
## Example
## Usage
The `example` folder contains a ready to use basic project.
TODO
To build the example run:
cd example
mkdir target
ciclostile_render
A `test.html` file will appear inside the `target` folder.
`ciclostile --help`

View File

@ -0,0 +1,47 @@
import os
import markdown
import jinja2
def read_markdown(page_name, markdown_path):
md_file = os.path.join(markdown_path, page_name + '.md')
with open(md_file) as f:
md_text = f.read()
return md_text
def render_from_text(md_text, template_path):
md = markdown.Markdown(extensions=['meta'], output_format='html5')
html = md.convert(md_text)
# get markdown metadata
data = {key: md.Meta[key][0] for key in md.Meta.keys()}
data.update({
'content': html,
# 'page_name': page_name, # Needed?
})
template_name = data.get('template', 'default')
template_file = os.path.join(template_path, template_name + '.html')
with open(template_file) as f:
template = f.read()
page = jinja2.Template(template).render(**data)
return page
def render(page_name, markdown_path, template_path):
md_text = read_markdown(page_name, markdown_path)
page = render_from_text(md_text, template_path)
return page
def save(md_text, page_name, markdown_path):
md_file = os.path.join(markdown_path, page_name + '.md')
with open(md_file, 'w') as f:
f.write(md_text)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/home/subnixr/.virtualenvs/ciclostile/bin/python3
import os
import ciclostile

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/home/subnixr/.virtualenvs/ciclostile/bin/python3
import os
from flask import Flask, send_from_directory, render_template, request
from flask_httpauth import HTTPDigestAuth

13
example/markdown/page1.md Normal file
View File

@ -0,0 +1,13 @@
Template: default
Title: Page one
Description: Test page one
When: today
# Header
Some text
- one
- two

11
example/markdown/page2.md Normal file
View File

@ -0,0 +1,11 @@
Template: default
Title: Page two
When: tomorrow
# Header
- three
- four
Bottom text

View File

@ -1,8 +0,0 @@
Title: Home Page
Author: anon
# Site
Some text

View File

@ -1,8 +0,0 @@
Title: Other Test Page
Template: other_template
# Title
Some other text

View File

@ -1,10 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div class="content">
{{ content }}
</div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>INDEX</title>
</head>
<body>
{% for pname, page in pages.items() %}
<div>
<p>
<a href="{{page.link}}">{{page.title}}</a>
</p>
<p>{{page.description}}</p>
<p>{{page.when}}</p>
</div>
{% endfor %}
</body>
</html>

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Other Template</h1>
{{ content }}
</body>
</html>

17
example/templates/rss.xml Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Unit</title>
<link>https://unit.macaomilano.org</link>
<description>unit</description>
{% for pname, page in pages.items() %}
<item>
<title>{{ page.title }}</title>
<link>{{ page.link }}</link>
<description>{{ page.description }}</description>
</item>
{% endfor %}
</channel>
</rss>

12
setup.py Normal file → Executable file
View File

@ -1,10 +1,10 @@
from distutils.core import setup
from setuptools import setup
from os import path
here = path.abspath(path.dirname(__file__))
setup(
name='Ciclostile',
name='ciclostile',
version='0.0.0.dev0',
description='Static site generator',
@ -16,7 +16,11 @@ setup(
package_dir={'': 'src'},
packages=['ciclostile'],
scripts=['src/ciclostile_render', 'src/ciclostile_web'],
# scripts=['src/ciclostile_cli'],
entry_points='''
[console_scripts]
ciclostile=cli:cli
''',
install_requires=['markdown', 'jinja2', 'flask', 'flask-httpauth']
install_requires=['Click', 'markdown', 'jinja2', 'flask', 'flask-httpauth']
)

View File

@ -1,47 +1,95 @@
#!/usr/bin/env python3
import os
import markdown
import jinja2
def read_markdown(page_name, markdown_path):
md_file = os.path.join(markdown_path, page_name + '.md')
with open(md_file) as f:
md_text = f.read()
return md_text
def render_from_text(md_text, template_path):
md = markdown.Markdown(extensions=['meta'], output_format='html5')
html = md.convert(md_text)
def parse(mdtext, parser=None):
if parser is None:
parser = markdown.Markdown(extensions=['meta'], output_format='html5')
html = parser.convert(mdtext)
# get markdown metadata
data = {key: md.Meta[key][0] for key in md.Meta.keys()}
data = {key: parser.Meta[key][0] for key in parser.Meta.keys()}
data.update({
'content': html,
# 'page_name': page_name, # Needed?
})
template_name = data.get('template', 'default')
template_file = os.path.join(template_path, template_name + '.html')
with open(template_file) as f:
template = f.read()
page = jinja2.Template(template).render(**data)
return page
return data
def render(page_name, markdown_path, template_path):
md_text = read_markdown(page_name, markdown_path)
page = render_from_text(md_text, template_path)
return page
def parse_file(filepath, parser=None):
with open(filepath) as fh:
return parse(fh.read(), parser=parser)
def save(md_text, page_name, markdown_path):
md_file = os.path.join(markdown_path, page_name + '.md')
def index(folder):
data = {'pages': []}
parser = markdown.Markdown(extensions=['meta'], output_format='html5')
for dirpath, _, files in os.walk(folder):
valid_files = (os.path.join(dirpath, f)
for f in files
if f.endswith('.md'))
for fpath in valid_files:
data['pages'].append(parse_file(fpath, parser=parser))
return data
with open(md_file, 'w') as f:
f.write(md_text)
def compile(template, data):
t = jinja2.Template(template)
return t.render(**data)
def compile_all(root_path):
md_path = os.path.join(root_path, 'markdown')
template_path = os.path.join(root_path, 'templates')
target_path = os.path.join(root_path, 'target')
data = {'pages': {}}
templates = {}
md_files = [f
for f in os.listdir(md_path)
if f.endswith('.md')]
template_files = [f
for f in os.listdir(template_path)
if f.endswith('.html')]
rss_file = 'templates/rss.xml'
for md_fname in md_files:
full_path = os.path.join(md_path, md_fname)
name, _ = os.path.splitext(md_fname)
data['pages'][name] = parse_file(full_path)
data['pages'][name]['link'] = f"/{name}.html"
for file_name in template_files:
full_path = os.path.join(template_path, file_name)
name, _ = os.path.splitext(file_name)
templates[name] = full_path
for page_name, page in data['pages'].items():
t_name = page.get('template', 'default')
with open(templates[t_name]) as tf:
t = jinja2.Template(tf.read())
out_path = os.path.join(target_path, page_name + '.html')
out = t.render(**data['pages'][page_name])
with open(out_path, 'w') as f:
f.write(out)
# index
with open(templates['index']) as fh:
index_template = jinja2.Template(fh.read())
out = index_template.render(**data)
out_path = os.path.join(target_path, 'index.html')
with open(out_path, "w") as f:
f.write(out)
# rss
with open(rss_file) as fh:
rss_template = jinja2.Template(fh.read())
out = rss_template.render(**data)
out_path = os.path.join(target_path, 'rss.xml')
with open(out_path, "w") as f:
f.write(out)

View File

@ -0,0 +1,11 @@
import click
from flask import Flask, send_from_directory, render_template, request
from flask_httpauth import HTTPDigestAuth
from .api import api
app = Flask(__name__)
app.register_blueprint(api, url_prefix="/api")
app.config['SECRET_KEY'] = 'secret key here'

65
src/ciclostile/web/api.py Executable file
View File

@ -0,0 +1,65 @@
import os
from glob import glob
from flask import Blueprint, send_from_directory, render_template, request, jsonify
from flask_httpauth import HTTPDigestAuth
import ciclostile
api = Blueprint('api', __name__)
# TODO: get from cli param
POST_DIR = "."
# auth = HTTPDigestAuth()
# users = {
# 'admin': 'password',
# }
# @auth.get_password
# def get_pw(username):
# if username in users:
# return users.get(username)
# return None
# @api.route('/assets/<path:path>')
# def assets(path):
# assets_path = os.path.join(target_path, 'assets')
# return send_from_directory(assets_path, path)
# @api.route('/<string:page_name>')
# @api.route('/<string:page_name>.html')
# def page(page_name):
# return ciclostile.render(page_name, markdown_path, template_path)
# @api.route('/<string:page_name>/edit')
# @auth.login_required
# def edit(page_name):
# md_text = ciclostile.read_markdown(page_name, markdown_path)
# return render_template('edit.html', **locals())
# @api.route('/edit', methods=['POST'])
# @auth.login_required
# def edit_actions():
# page_name = request.form['page_name']
# md_text = request.form['md_text']
# if request.form['action'] == 'preview':
# return ciclostile.render_from_text(md_text, template_path)
# if request.form['action'] == 'save':
# ciclostile.save(md_text, page_name, markdown_path)
# return page(page_name)
@api.route("/posts")
def posts_list():
"""
Returns all .md files under POST_DIR
"""
posts = glob(f"{POST_DIR}/**/*.md", recursive=True)
return jsonify(posts)

56
src/cli.py Executable file
View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
import os
import sys
import click
import ciclostile
# from ciclostile.web import app as webapp
@click.group()
def cli():
pass
@cli.command()
@click.option('-t', '--template', type=click.File('r'))
@click.option('-o', '--output', type=click.File('w'), default=sys.stdout)
@click.argument('markdown', type=click.File('r'), default=sys.stdin)
def compile(template, output, markdown):
data = ciclostile.parse(markdown.read())
html = ciclostile.compile(template.read(), data)
output.write(html)
@cli.command()
@click.option('-t', '--template', type=click.File('r'))
@click.option('-o', '--output', type=click.File('w'), default=sys.stdout)
@click.argument('folder', type=click.Path(exists=True,
file_okay=False))
def index(template, output, folder):
data = ciclostile.index(folder)
html = ciclostile.compile(template.read(), data)
output.write(html)
@cli.command()
@click.argument("input_dir", default=os.getcwd(),
type=click.Path(exists=True,
file_okay=False))
def compile_all(input_dir):
ciclostile.compile_all(input_dir)
@cli.command()
@click.option("-p", "--port", type=int, default=12345)
@click.argument("input_dir", default=os.getcwd(),
type=click.Path(exists=True,
file_okay=False))
def app(port, input_dir):
print({'port': port,
'input': input_dir})
# webapp.run(port=port)
if __name__ == "__main__":
cli()