extras.filters: docker_link() filter ; package refactoring

This commit is contained in:
Mark Vartanyan 2014-10-08 15:25:04 +02:00
parent 1a11f02071
commit a0a27b35a6
15 changed files with 404 additions and 64 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
# ===[ APP ]=== #
# ===[ PYTHON PACKAGE ]=== #
/.tox/
/build/
/dist/
/MANIFEST

View File

@ -1,10 +1,7 @@
language: python
python:
- "2.7"
# - "3.3" # not so fast :)
install:
- "pip install -e '.[_dev]'"
script: make test
- pip install tox
script:
- tox
env:
- TOXENV=py27

View File

@ -1,2 +1,3 @@
include README.md
include README.*
include LICENSE
include tox.ini

View File

@ -1,17 +1,13 @@
all:
.PHONY: README.md env test test3 check clean build publish install
SHELL := /bin/bash
.PHONY: clean build publish
# Run tests
test:
@nosetests tests/
test3:
@nosetests3 tests/
# Package
check:
@./setup.py check
clean:
@rm -rf build/ dist/ *.egg-info/ README.rst
@rm -rf build/ dist/ *.egg-info/ README.md README.rst
README.md: $(shell find misc/ j2cli/)
@python misc/_doc/README.py | j2 -f json misc/_doc/README.md.j2 > $@
README.rst: README.md
@pandoc -f markdown -t rst -o README.rst README.md
build: README.rst

View File

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/kolypto/j2cli.svg?branch=v0.3.0-0)](https://travis-ci.org/kolypto/j2cli)
[![Build Status](https://travis-ci.org/kolypto/j2cli.svg)](https://travis-ci.org/kolypto/j2cli)
j2cli - Jinja2 Command-Line Tool
================================
@ -20,6 +20,12 @@ Inspired by [mattrobenolt/jinja2-cli](https://github.com/mattrobenolt/jinja2-cli
pip install j2cli
```
To enable the YAML support with [pyyaml](http://pyyaml.org/):
```
pip install j2cli[yaml]
```
## Usage
Compile a template using INI-file data source:
@ -63,7 +69,31 @@ There is some special behavior with environment variables:
## Formats
### env
Data input from environment variables.
Render directly from the current environment variable values:
$ j2 config.j2
Or alternatively, read the values from a file:
```
NGINX_HOSTNAME=localhost
NGINX_WEBROOT=/var/www/project
NGINX_LOGS=/var/log/nginx/
```
And render with:
$ j2 config.j2 data.env
$ env | j2 --format=env config.j2.
This is especially useful with Docker to link containers together.
### ini
INI data input format.
data.ini:
@ -80,6 +110,7 @@ Usage:
$ cat data.ini | j2 --format=ini config.j2
### json
JSON data input format
data.json:
@ -93,12 +124,13 @@ data.json:
}
```
Usage:
Usage:
$ j2 config.j2 data.json
$ cat data.json | j2 --format=ini config.j2
### yaml
YAML data input format.
data.yaml:
@ -109,26 +141,37 @@ nginx:
logs: /var/log/nginx
```
Usage:
Usage:
$ j2 config.j2 data.yml
$ cat data.yml | j2 --format=yaml config.j2
### env
Render directly from environment variable values:
$ j2 config.j2
Or read them from a file:
```
NGINX_HOSTNAME=localhost
NGINX_WEBROOT=/var/www/project
NGINX_LOGS=/var/log/nginx/
Extras
======
## Filters
### `docker_link(value, format='{addr}:{port}')`
Given a Docker Link environment variable value, format it into something else.
This first parses a Docker Link value like this:
DB_PORT=tcp://172.17.0.5:5432
Into a dict:
```python
{
'proto': 'tcp',
'addr': '172.17.0.5',
'port': '5432'
}
```
And render with:
$ j2 config.j2 data.env
$ env | j2 --format=env config.j2.
And then uses `format` to format it, where the default format is '{addr}:{port}'.
More info here: [Docker Links](https://docs.docker.com/userguide/dockerlinks/)

View File

@ -23,6 +23,12 @@ Installation
pip install j2cli
To enable the YAML support with `pyyaml <http://pyyaml.org/>`__:
::
pip install j2cli[yaml]
Usage
-----
@ -86,9 +92,39 @@ There is some special behavior with environment variables:
Formats
-------
env
~~~
Data input from environment variables.
Render directly from the current environment variable values:
::
$ j2 config.j2
Or alternatively, read the values from a file:
::
NGINX_HOSTNAME=localhost
NGINX_WEBROOT=/var/www/project
NGINX_LOGS=/var/log/nginx/
And render with:
::
$ j2 config.j2 data.env
$ env | j2 --format=env config.j2.
This is especially useful with Docker to link containers together.
ini
~~~
INI data input format.
data.ini:
::
@ -108,6 +144,8 @@ Usage:
json
~~~~
JSON data input format
data.json:
::
@ -130,6 +168,8 @@ Usage:
yaml
~~~~
YAML data input format.
data.yaml:
::
@ -146,29 +186,39 @@ Usage:
$ j2 config.j2 data.yml
$ cat data.yml | j2 --format=yaml config.j2
env
~~~
Extras
======
Render directly from environment variable values:
Filters
-------
``docker_link(value, format='{addr}:{port}')``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Given a Docker Link environment variable value, format it into something
else.
This first parses a Docker Link value like this:
::
$ j2 config.j2
DB_PORT=tcp://172.17.0.5:5432
Or read them from a file:
Into a dict:
::
.. code:: python
NGINX_HOSTNAME=localhost
NGINX_WEBROOT=/var/www/project
NGINX_LOGS=/var/log/nginx/
{
'proto': 'tcp',
'addr': '172.17.0.5',
'port': '5432'
}
And render with:
And then uses ``format`` to format it, where the default format is
'{addr}:{port}'.
::
More info here: `Docker
Links <https://docs.docker.com/userguide/dockerlinks/>`__
$ j2 config.j2 data.env
$ env | j2 --format=env config.j2.
.. |Build Status| image:: https://travis-ci.org/kolypto/j2cli.svg?branch=v0.3.0-0
.. |Build Status| image:: https://travis-ci.org/kolypto/j2cli.svg
:target: https://travis-ci.org/kolypto/j2cli

View File

@ -2,9 +2,34 @@ import os, sys
import argparse
import jinja2
import jinja2.loaders
from . import __version__
from .context import read_context_data, FORMATS
from .extras import filters
class FilePathLoader(jinja2.BaseLoader):
""" Custom Jinja2 template loader which just loads a single template file """
def __init__(self, cwd, encoding='utf-8'):
self.cwd = cwd
self.encoding = encoding
def get_source(self, environment, template):
# Path
filename = os.path.join(self.cwd, template)
# Read
try:
with open(template, 'r') as f:
contents = f.read().decode(self.encoding)
except IOError:
raise jinja2.TemplateNotFound(template)
# Finish
uptodate = lambda: False
return contents, filename, uptodate
def render_template(cwd, template_path, context):
@ -17,9 +42,13 @@ def render_template(cwd, template_path, context):
:rtype: basestring
"""
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(cwd),
loader=FilePathLoader(cwd),
undefined=jinja2.StrictUndefined # raises errors for undefined variables
)
# Register extras
env.filters['docker_link'] = filters.docker_link
return env \
.get_template(template_path) \
.render(context) \

View File

@ -3,9 +3,21 @@ import sys
#region Parsers
def _parse_ini(data_string):
""" Parse INI
:type data_string: basestring
:rtype: dict
""" INI data input format.
data.ini:
```
[nginx]
hostname=localhost
webroot=/var/www/project
logs=/var/log/nginx/
```
Usage:
$ j2 config.j2 data.ini
$ cat data.ini | j2 --format=ini config.j2
"""
from io import BytesIO
@ -29,23 +41,67 @@ def _parse_ini(data_string):
return ini.as_dict()
def _parse_json(data_string):
""" Parse JSON
:type data_string: basestring
:rtype: dict
""" JSON data input format
data.json:
```
{
"nginx":{
"hostname": "localhost",
"webroot": "/var/www/project",
"logs": "/var/log/nginx/"
}
}
```
Usage:
$ j2 config.j2 data.json
$ cat data.json | j2 --format=ini config.j2
"""
return json.loads(data_string)
def _parse_yaml(data_string):
""" Parse YAML
:type data_string: basestring
:rtype: dict
""" YAML data input format.
data.yaml:
```
nginx:
hostname: localhost
webroot: /var/www/project
logs: /var/log/nginx
```
Usage:
$ j2 config.j2 data.yml
$ cat data.yml | j2 --format=yaml config.j2
"""
return yaml.load(data_string)
def _parse_env(data_string):
""" Parse environment variables file
:type data_string: str|dict
:rtype: dict
""" Data input from environment variables.
Render directly from the current environment variable values:
$ j2 config.j2
Or alternatively, read the values from a file:
```
NGINX_HOSTNAME=localhost
NGINX_WEBROOT=/var/www/project
NGINX_LOGS=/var/log/nginx/
```
And render with:
$ j2 config.j2 data.env
$ env | j2 --format=env config.j2.
This is especially useful with Docker to link containers together.
"""
# Parse
if isinstance(data_string, basestring):

1
j2cli/extras/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import filters

38
j2cli/extras/filters.py Normal file
View File

@ -0,0 +1,38 @@
""" Custom Jinja2 filters """
import re
def docker_link(value, format='{addr}:{port}'):
""" Given a Docker Link environment variable value, format it into something else.
This first parses a Docker Link value like this:
DB_PORT=tcp://172.17.0.5:5432
Into a dict:
```python
{
'proto': 'tcp',
'addr': '172.17.0.5',
'port': '5432'
}
```
And then uses `format` to format it, where the default format is '{addr}:{port}'.
More info here: [Docker Links](https://docs.docker.com/userguide/dockerlinks/)
:param value: Docker link (from an environment variable)
:param format: The format to apply. Supported placeholders: `{proto}`, `{addr}`, `{port}`
:return: Formatted string
"""
# Parse the value
m = re.match(r'(?P<proto>.+)://' r'(?P<addr>.+):' r'(?P<port>.+)$', value)
if not m:
raise ValueError('The provided value does not seems to be a Docker link: {}'.format(value))
d = m.groupdict()
# Format
return format.format(**d)

87
misc/_doc/README.md.j2 Normal file
View File

@ -0,0 +1,87 @@
[![Build Status](https://travis-ci.org/kolypto/j2cli.svg)](https://travis-ci.org/kolypto/j2cli)
j2cli - Jinja2 Command-Line Tool
================================
`j2cli` is a command-line tool for templating in shell-scripts,
leveraging the [Jinja2](http://jinja.pocoo.org/docs/) library.
Features:
* Jinja2 templating
* Allows to use environment variables! Hello [Docker](http://www.docker.com/) :)
* INI, YAML, JSON data sources supported
Inspired by [mattrobenolt/jinja2-cli](https://github.com/mattrobenolt/jinja2-cli)
## Installation
```
pip install j2cli
```
To enable the YAML support with [pyyaml](http://pyyaml.org/):
```
pip install j2cli[yaml]
```
## Usage
Compile a template using INI-file data source:
$ j2 config.j2 data.ini
Compile using JSON data source:
$ j2 config.j2 data.json
Compile using YAML data source (requires PyYAML):
$ j2 config.j2 data.yaml
Compile using JSON data on stdin:
$ curl http://example.com/service.json | j2 --format=json config.j2
Compile using environment variables (hello Docker!):
$ j2 config.j2
Or even read environment variables from a file:
$ j2 --format=env config.j2 data.env
# Reference
`j2` accepts the following arguments:
* `template`: Jinja2 template file to render
* `data`: (optional) path to the data used for rendering. The default is `-`: use stdin
Options:
* `--format, -f`: format for the data file. The default is `?`: guess from file extension.
There is some special behavior with environment variables:
* When `data` is not provided (data is `-`), `--format` defaults to `env` and thus reads environment variables
* When `--format=env`, it can read a special "environment variables" file made like this: `env > /tmp/file.env`
## Formats
{% for name, format in formats|dictsort() %}
### {{ name }}
{{ format.doc }}
{% endfor %}
Extras
======
## Filters
{% for filter in extras.filters|sort() %}
### `{{ filter.qsignature }}`
{{ filter.doc }}
{% endfor %}

24
misc/_doc/README.py Executable file
View File

@ -0,0 +1,24 @@
#! /usr/bin/env python
import json
import inspect
from exdoc import doc, getmembers
import j2cli
import j2cli.context
import j2cli.extras.filters
README = {
'formats': {
name: doc(f)
for name, f in j2cli.context.FORMATS.items()
},
'extras': {
'filters': [doc(v)
for k, v in getmembers(j2cli.extras.filters)
if inspect.isfunction(v)]
}
}
print json.dumps(README)

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
wheel
nose
exdoc
pyyaml

View File

@ -18,7 +18,7 @@ from setuptools import setup, find_packages
setup(
name='j2cli',
version='0.3.0-1',
version='0.3.1-0',
author='Mark Vartanyan',
author_email='kolypto@gmail.com',
@ -40,7 +40,7 @@ setup(
'jinja2 >= 2.7.2',
],
extras_require={
'_dev': ['wheel', 'nose'],
'yaml': ['pyyaml',]
},
include_package_data=True,
zip_safe=False,

13
tox.ini Normal file
View File

@ -0,0 +1,13 @@
[tox]
envlist=py27
skip_missing_interpreters=True
[testenv]
deps=-rrequirements.txt
commands=
nosetests {posargs:tests/}
whitelist_externals=make
[testenv:dev]
deps=-rrequirements.txt
usedevelop=True