Skip to content

Commit

Permalink
Merge pull request #7 from 9seconds/v0.2
Browse files Browse the repository at this point in the history
0.2
  • Loading branch information
9seconds committed Apr 3, 2016
2 parents 18d4ca3 + 4cde98c commit 9152a10
Show file tree
Hide file tree
Showing 16 changed files with 328 additions and 128 deletions.
41 changes: 31 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,20 @@ or if you want to install it manually, do following:
$ cd concierge
$ python setup.py install
By default, no template support will be installed. If you want to use
Mako_ or Jinja2_, please do following:
By default, no template support is going to be installed. If you want to
use Mako_ or Jinja2_, please refer to `Templaters`_ section.

.. code-block:: shell
$ pip install concierge[mako]
or
Also, it is possible to install support of `libnotify
<https://developer.gnome.org/libnotify/>`_. Please install tool like
this:

.. code-block:: shell
$ pip install concierge[jinja]
$ pip install concierge[libnotify]
If you already have them installed, then you are good.
In that case, you will have a desktop notifications about any problem
with parsing of your ``~/.conciergerc``. Yep, these Ubuntu popups on the
right top of the screen.

If you have a problems with Pip installation (with modifiers, for
example), please update your pip and setuptools first.
Expand All @@ -97,6 +96,28 @@ After installation, 2 utilities will be available:
* ``concierge``


Templaters
----------

``concierge`` comes with support of additional templaters, you may plug
them in installing the packages from PyPI. At the time of writing,
support of following templaters was done:

* `concierge-mako <https://github.com/9seconds/concierge-mako>`_ -
support of Mako_ templates
* `concierge-jinja <https://github.com/9seconds/concierge-jinja>`_ -
support of Jinja2_ templates

To install them just do

.. code-block:: shell
$ pip install concierge-mako
And ``concierge`` will automatically recognizes support of Mako and now
one may use ``concierge -u mako`` for her ``~/.conciergerc``.


concierge-check
---------------

Expand Down
25 changes: 2 additions & 23 deletions concierge/__init__.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
# -*- coding: utf-8 -*-


import collections
import os.path
import warnings


Templater = collections.namedtuple("Templater", ["name", "render"])

EXTRAS = {"templater": Templater(None, lambda content: content)}
HOME_DIR = os.path.expanduser("~")
DEFAULT_RC = os.path.join(HOME_DIR, ".conciergerc")
DEFAULT_SSHCONFIG = os.path.join(HOME_DIR, ".ssh", "config")


try:
import mako.template
except ImportError:
pass
else:
EXTRAS["templater"] = Templater(
"Mako",
lambda content: mako.template.Template(content).render_unicode())


if EXTRAS["templater"].name is None:
try:
import jinja2
except ImportError:
pass
else:
EXTRAS["templater"] = Templater(
"Jinja2",
lambda content: jinja2.Environment().from_string(content).render())
warnings.simplefilter('always', DeprecationWarning)
28 changes: 20 additions & 8 deletions concierge/endpoints/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import argparse

import concierge
import concierge.templater


def create_parser():
Expand Down Expand Up @@ -40,13 +41,24 @@ def create_parser():
"DESTINATION_PATH is stdout, then this option is set to false."),
action="store_true",
default=None)

if concierge.EXTRAS["templater"].name:
parser.add_argument(
"-t", "--no-templater",
help="Do not use {} templater for SOURCE_PATH.".format(
concierge.EXTRAS["templater"].name),
action="store_true",
default=False)
parser.add_argument(
"-u", "--use-templater",
help=("Use following templater for config file. If nothing is set, "
"then default template resolve chain will be "
"used (Mako -> Jinja -> Nothing). Dummy templater means that "
"no templater is actually used."),
choices=concierge.templater.all_templaters().keys(),
default=None)
parser.add_argument(
"-t", "--no-templater",
help=("Do not use any templater. Please be noticed that newer "
"version of concierge will change that behavior."),
action="store_true",
default=False)
parser.add_argument(
"-n", "--no-desktop-notifications",
help="Do not show desktop notifications on problems.",
action="store_true",
default=False)

return parser
51 changes: 41 additions & 10 deletions concierge/endpoints/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@

import abc
import os
import warnings

import concierge.core.processor
import concierge.endpoints.cli
import concierge.endpoints.templates
import concierge.notifications
import concierge.templater
import concierge.utils


Expand All @@ -20,12 +23,37 @@ def specify_parser(cls, parser):
return parser

def __init__(self, options):
if options.use_templater is None:
warnings.warn(
"--use-templater flag and therefore implicit templater "
"autoresolve are deprecated. Please use explicit "
"templater in both concierge-check and concierge.",
FutureWarning)

if options.no_templater:
warnings.warn(
"Flag --no-templater is deprecated. "
"Please use 'dummy' templater instead.",
DeprecationWarning)

self.source_path = options.source_path
self.destination_path = options.destination_path
self.boring_syntax = options.boring_syntax
self.add_header = options.add_header
self.no_templater = getattr(options, "no_templater", False)

if options.no_desktop_notifications:
self.notificator = concierge.notifications.dummy_notifier
else:
self.notificator = concierge.notifications.notifier

try:
self.templater = concierge.templater.resolve_templater(
options.use_templater)
except KeyError:
raise ValueError(
"Cannot find templater for {0}".format(options.use_templater))

if self.add_header is None:
self.add_header = options.destination_path is not None

Expand All @@ -49,8 +77,8 @@ def output(self):
with concierge.utils.topen(self.destination_path, True) as destfp:
destfp.write(content)
except Exception as exc:
LOG.error("Cannot write to file %s: %s",
self.destination_path, exc)
self.log_error("Cannot write to file %s: %s",
self.destination_path, exc)
raise

def get_new_config(self):
Expand Down Expand Up @@ -79,8 +107,8 @@ def fetch_content(self):
try:
content = concierge.utils.get_content(self.source_path)
except Exception as exc:
LOG.error("Cannot fetch content from %s: %s",
self.source_path, exc)
self.log_error("Cannot fetch content from %s: %s",
self.source_path, exc)
raise

LOG.info("Original content of %s:\n%s", self.source_path, content)
Expand All @@ -91,11 +119,10 @@ def apply_template(self, content):
LOG.info("Applying templater to content of %s.", self.source_path)

try:
content = concierge.EXTRAS["templater"].render(content)
content = self.templater.render(content)
except Exception as exc:
LOG.error("Cannot process template (%s) in source file %s.",
self.source_path, concierge.EXTRAS["templater"].name,
exc)
self.log_error("Cannot process template (%s) in source file %s.",
self.source_path, self.templater.name, exc)
raise

LOG.info("Templated content of %s:\n%s", self.source_path, content)
Expand All @@ -106,8 +133,8 @@ def process_syntax(self, content):
try:
return concierge.core.processor.process(content)
except Exception as exc:
LOG.error("Cannot parse content of source file %s: %s",
self.source_path, exc)
self.log_error("Cannot parse content of source file %s: %s",
self.source_path, exc)
raise

def attach_header(self, content):
Expand All @@ -117,6 +144,10 @@ def attach_header(self, content):

return content

def log_error(self, template, *args):
LOG.error(template, *args)
self.notificator(template % args)


def main(app_class):
def main_func():
Expand Down
3 changes: 2 additions & 1 deletion concierge/endpoints/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ def do(self):
if not self.systemd:
return self.track()

script = concierge.endpoints.templates.make_systemd_script()
script = concierge.endpoints.templates.make_systemd_script(
self.templater)

if not self.curlsh:
script = [
Expand Down
10 changes: 5 additions & 5 deletions concierge/endpoints/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
SYSTEMD_CONFIG = """
[Unit]
Description=Daemon for converting ~/.concierge to ~/.ssh/config
After=syslog.target
[Service]
ExecStart={command} -o {sshconfig}
ExecStart={command} -u {templater} -o {sshconfig}
Restart=on-failure
[Install]
WantedBy=multi-user.target
WantedBy=default.target
""".strip()

SYSTEMD_SERVICE_NAME = "concierge.service"
Expand All @@ -52,14 +51,15 @@ def make_header(**kwargs):
rc_file=kwargs.get("rc_file", "???"))


def make_systemd_script():
def make_systemd_script(templater):
systemd_user_path = os.path.join(concierge.HOME_DIR,
".config", "systemd", "user")
systemd_user_service_path = os.path.join(systemd_user_path,
SYSTEMD_SERVICE_NAME)
systemd_config = SYSTEMD_CONFIG.format(
command=distutils.spawn.find_executable(sys.argv[0]),
sshconfig=concierge.DEFAULT_SSHCONFIG)
sshconfig=concierge.DEFAULT_SSHCONFIG,
templater=templater.name.lower())

yield 'mkdir -p "{0}" || true'.format(systemd_user_path)
yield 'cat > "{0}" <<EOF\n{1}\nEOF'.format(systemd_user_service_path,
Expand Down
34 changes: 34 additions & 0 deletions concierge/notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-


import atexit


try:
import pgi
except ImportError:
pgi = None
else:
pgi.install_as_gi()

import gi

gi.require_version("Notify", "0.7")

from gi.repository import Notify

Notify.init("concierge")
atexit.register(Notify.uninit)


def dummy_notifier(_):
pass


notifier = dummy_notifier

if pgi:
def libnotify_notifier(problem):
Notify.Notification.new("concierge", problem, None).show()

notifier = libnotify_notifier
43 changes: 43 additions & 0 deletions concierge/templater.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-


import pkg_resources


TEMPLATER_NAMESPACE = "concierge.templater"
DEFAULT_RESOLVE_SEQ = "mako", "jinja2"


def all_templaters():
templaters = {"dummy": Templater}

for plugin in pkg_resources.iter_entry_points(group=TEMPLATER_NAMESPACE):
templaters[plugin.name] = plugin.load()

return templaters


def resolve_templater(choose=None):
templaters = all_templaters()
found = None

if choose:
found = templaters[choose]
else:
for code in DEFAULT_RESOLVE_SEQ:
if code in templaters:
found = templaters[code]
break
else:
found = Templater

return found()


class Templater(object):

name = "dummy"
"""The name of the templater to show."""

def render(self, content):
return content
Loading

0 comments on commit 9152a10

Please sign in to comment.