Skip to content

Commit

Permalink
Merge Better CLI #11
Browse files Browse the repository at this point in the history
Use the `click` library to handle arguments, options and flags.

Add modules to `build`, `init`ialize, and copy a `quickstart` project. These are callable
just by typing `ginpar [COMMAND]`.

Run `ginpar` to get a complete list of commands and options. This is equivalent to running
`ginpar --help`.
  • Loading branch information
davidomarf committed Oct 19, 2019
2 parents ae217c7 + f7c23bb commit 24d8873
Show file tree
Hide file tree
Showing 23 changed files with 683 additions and 65 deletions.
26 changes: 22 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

# Created by https://www.gitignore.io/api/node,linux,python,visualstudiocode
# Edit at https://www.gitignore.io/?templates=node,linux,python,visualstudiocode
# Created by https://www.gitignore.io/api/node,linux,python,visualstudiocode,venv
# Edit at https://www.gitignore.io/?templates=node,linux,python,visualstudiocode,venv

### Linux ###
*~
Expand Down Expand Up @@ -127,7 +127,7 @@ dist/
downloads/
eggs/
.eggs/
## lib/
lib/
lib64/
parts/
sdist/
Expand Down Expand Up @@ -214,6 +214,24 @@ dmypy.json
# Pyre type checker
.pyre/

### venv ###
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
pip-selfcheck.json

### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
Expand All @@ -225,7 +243,7 @@ dmypy.json
# Ignore all local history of files
.history

# End of https://www.gitignore.io/api/node,linux,python,visualstudiocode
# End of https://www.gitignore.io/api/node,linux,python,visualstudiocode,venv

/sketches
/themes
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "/home/d/.local/share/virtualenvs/ginpar-rqgfLzln/bin/python"
}
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pylint = "*"
[packages]
Jinja2 = "*"
PyYAML = "*"
click = "*"

[requires]
python_version = "3.7"
10 changes: 9 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions ginpar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import shutil
import yaml
import click

from jinja2 import Environment, FileSystemLoader

Expand Down Expand Up @@ -97,9 +98,7 @@ def main():
_index_template = _jinja_env.get_template("index.html")
index = open("public/index.html", "w")
index.write(
_index_template.render(
sketches=map(lambda a: a["name"], sketches), site=_SITE
)
_index_template.render(sketches=map(lambda a: a["name"], sketches), site=_SITE)
)
index.close()

Expand Down
4 changes: 2 additions & 2 deletions ginpar/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"""
from . import main

if __name__ == '__main__':
main()
if __name__ == "__main__":
main()
155 changes: 155 additions & 0 deletions ginpar/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"""
ginpar.build
~~~~~~~~~~~~
Implements the generation of the static site.
"""
import os
import shutil
import yaml
import click

from jinja2 import Environment, FileSystemLoader

from ginpar.settings import read_config
import ginpar.generators as gg

from ginpar.utils.echo import echo, success
from ginpar.utils.strings import unkebab

import click

_SITE_FILE = "config.json"
_SITE = read_config(_SITE_FILE)
_THEME = _SITE["theme"]
_TEMPLATES_PATH = os.path.join("themes", _THEME, "templates")
_SKETCHES_PATH = _SITE["content_path"]
_jinja_env = Environment(loader=FileSystemLoader(_TEMPLATES_PATH), trim_blocks=True)
_jinja_env.filters["unkebab"] = unkebab


def build_link(sketch):
title = sketch.split("/")[-1].split(".")[0]
return f'<a href="./{title}"">{title}</a><br/>\n'


def build_index(sketches):
content = ""
for s in sketches:
content += build_link(s)
return content


def get_sketches(path):
sketches = []
# Create a list with all the directories inside path
for r, d, _ in os.walk(path):
for sketch in d:
sketches.append(
{
"name": sketch,
"script": os.path.join(r, sketch, "sketch.js"),
"data": os.path.join(r, sketch, "data.yaml"),
}
)

return map(
# Convert the data.yaml file into a dictionary
convert_information,
# Remove sketch if either `sketch.js` or `data.yaml` don't exist
filter(
lambda a: os.path.isfile(a["script"]) and os.path.isfile(a["data"]),
sketches,
),
)


def convert_information(sketch):
path = sketch["data"]
with open(path, "r") as stream:
try:
parsed_data = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
sketch["data"] = parsed_data
return sketch


def create_publishing_directory(path):
if os.path.exists(path):
shutil.rmtree(path)
os.mkdir(path)


def copy_theme(path, theme_path):
## Copy the static/ folder of the theme
shutil.copytree(
os.path.join("themes", theme_path, "static"), os.path.join(path, "static")
)


def render_index(path, sketches, site):
## Create an index to contain all the sketches
_index_template = _jinja_env.get_template("index.html")
index = open(os.path.join(path, "index.html"), "w")
index.write(
_index_template.render(sketches=map(lambda a: a["name"], sketches), site=site)
)
index.close()


def render_sketch_page(path, s, site):
## Create a directory with the sketch title
os.mkdir(f"public/{s['name']}")

## Convert the form JSON into a dict
form_dict = s["data"]

## Add name key to the dict elements
form_dict = gg.add_name(form_dict)

## Create index.html
_sketch_template = _jinja_env.get_template("sketch.html")
sketch_index = open(f"public/{s['name']}/index.html", "w+")
sketch_index.write(
_sketch_template.render(
sketch=unkebab(s["name"]), form=gg.sketch_index(form_dict), site=_SITE
)
)
sketch_index.close()

## Create sketch.js
sketch_path = f"public/{s['name']}/sketch.js"
sketch = open(sketch_path, "w+")

## Copy all the content from original sketches/{title}.js to sketch.js
sf = open(s["script"], "r")

sketch.write(gg.makeValueGetter(form_dict))

for x in sf.readlines():
sketch.write(x)
sf.close()
sketch.close()


def build(path):
create_publishing_directory(path)
echo(f"Building in `{os.path.abspath(path)}`")

copy_theme(path, _THEME)
echo(f"Building using theme `{_THEME}`")

## Create a sketches array
sketches = list(get_sketches(_SKETCHES_PATH))
echo(f"Found {len(sketches)} sketch(es)")

render_index(path, sketches, _SITE)
echo("Building main page")

echo("Building sketches:")
for s in sketches:
echo(f" Building {s['name']}")
render_sketch_page(path, s, _SITE)

success("Success.")
118 changes: 118 additions & 0 deletions ginpar/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
ginpar.cli
~~~~~~~~~~
Implements the command line application to manage ginpar projects.
"""

import click


@click.group()
@click.version_option(message="%(prog)s v%(version)s")
def cli():
"""
Ginpar is an extra simple static content generator for interactive and parametrisable p5 canvases.
"""
pass


@cli.command()
@click.option(
"--path",
"-p",
default="public",
type=click.Path(),
help="The PATH for the generated site.\nDefault = public",
)
def build(path):
"""Build a static website in PATH"""
from ginpar.build import build as ginpar_build

click.echo("")
ginpar_build(path)
click.echo("")


@cli.command()
@click.option(
"--force",
"-f",
default=False,
is_flag=True,
help="Remove existing directories that may interfere with the initialization",
)
@click.option(
"--quick",
"-q",
default=False,
is_flag=True,
help="Skip the configuration prompts and use the default values",
)
@click.option(
"--path",
"-p",
default="",
help="The PATH to initialize the project. Defaults to ./",
)
def init(force, path, quick):
"""Initialize a new project in PATH"""
from ginpar.init import init as ginpar_init

click.echo("")
ginpar_init(force, path, quick)
click.echo("")


@cli.command()
@click.argument("sketch", default="new-sketch")
@click.option(
"--path",
"-p",
default="sketches",
type=click.Path(),
help="The path for the newly created sketch",
)
def new(sketch, path):
"""Create a new SKETCH in PATH"""
click.secho(f"Attemping to create `{sketch}` in `{path}/`", fg="blue")
from ginpar.new import new as ginpar_new

click.echo("")
ginpar_new(sketch, path)
click.echo("")


@cli.command()
@click.option(
"--force",
"-f",
default=False,
is_flag=True,
help="Remove existing directories that may interfere the quickstart",
)
@click.option(
"--path", "-p", default="./", help="The path the demo content will be copied to."
)
def quickstart(force, path):
"""Load a working example in PATH"""
from ginpar.quickstart import quickstart as ginpar_quickstart

click.echo("")
ginpar_quickstart(force, path)
click.echo("")


@cli.command()
@click.option("--port", "-p", default="8080", help="Port for the web server")
def serve(port):
"""Serve the content using PORT"""
from ginpar.serve import serve as ginpar_serve

click.echo("")
ginpar_serve(port)
click.echo("")


if __name__ == "__main__":
cli()

0 comments on commit 24d8873

Please sign in to comment.