c2p2 0.1.3
Code Commit Push Publish engine.
License: The MIT License
Keywords: tornado,github,blog,publish

C2P2 - A simple markdown pages publisher
========================================

**C**\ ode
**C**\ ommit
**P**\ ush
**P**\ ublish

    Live and die by documentation.
    
    Matthew Ginnard

Installation
------------

.. code-block:: bash

    pip install c2p2

or

.. code-block:: bash

    pip install git+https://github.com/nanvel/c2p2.git

Usage
-----

Fork c2p2_template
~~~~~~~~~~~~~~~~~~

The easiest way to start is to fork this template: https://github.com/nanvel/c2p2-template.

Templates API
~~~~~~~~~~~~~

The application looks for templates inside SOURCE_FOLDER, so we need to add them.
Minimal list of files required is:

.. code-block:: text

    - site
        - engine
            - templates
                - 404.html
                - 500.html
                - index.html
                - page.html
                - label.html
                - sitemap.xml

``index.html``, ``page.html``, ``label.html`` and ``sitemap.xml`` receives, beside `tornado standart template context <http://www.tornadoweb.org/en/stable/guide/templates.html>`__,  
variable ``c``, that uses to access a list of pages and labels, for example:

.. code-block:: django

    {{ c.page }}
    {{ c.page.title }}
    {{ c.page.labels }}
    {{ c.label }}
    {% for page in c.pages %}
    {{ c.pages['<page_slug>'] }}
    {{ c.pages.for_label('<label_slug>') }}

``c.page`` is available only in ``page.html``.
It returns current page object.

``Page`` object has next attributes:
    - uri
    - html
    - created
    - modified
    - title
    - meta
    - labels

``page.meta`` returns ``PageMeta`` object, where all variables specified in the top of the page is available.

.. code-block:: text

    // page.md
    created: 2015-10-10T00:00
    show_comments: true
    labels: Label1
            Label2

.. code-block:: django

    // page.html
    {{ c.page.meta.created }} -> '2015-10-10T00:00'
    {{ c.page.meta.created }} -> '2015-10-10T00:00'
    {{ c.page.meta.labels }} -> 'Label1'
    {{ c.page.meta.get('labels') }} -> 'Label1'
    {{ c.page.meta.get_list('labels') }} -> ['Label1', 'Label2']
    {{ c.page.meta.show_comments }} -> true
    {{ c.page.meta.not_exist }} -> None

``page.labels`` returns list of Label objects connected to the page:

.. code-block:: django

    {% for label in c.page.labels %}{{ label.title }}{% end %}

``Label`` object has next attributes:
    - title
    - slug

``c.pages`` returns an iterable that allows to get all pages list. In ``label.html`` it return only pages belong to the label.
You also can get any page by uri using ``c.pages``.

.. code-block:: django

    {% for page in c.pages %}{{ page.title }}{% end %}

    {{ c.pages['2010/09/blog-post'].html }}

    {{ c.pages.for_label('default') }}

Running the server
~~~~~~~~~~~~~~~~~~

To run the application use ``site/engine/app.py``:

.. code-block:: python

    import os.path

    from c2p2 import app
    from c2p2.settings import settings


    rel = lambda p: os.path.join(os.path.dirname(os.path.realpath(__file__)), p)


    if __name__ == '__main__':
        settings.SOURCE_FOLDER = rel('..')
        app.run()

Settings
--------

There are 4 ways to set settings:
    - default settings (see ``c2p2/settings.py``)
    - environment variables with ``C2P2_`` prefix: ``export C2P2_PORT=5000``
    - command line arguments (``app.py --PORT=5000``)
    - also you can change them directly ``settings.PORT = 5000`` in ``site/engine/app.py`` 

Available settings:
    - ``DEBUG``: Enable tornado debug mode
    - ``PORT``: Port the app listening to
    - ``SOURCE_FOLDER``: Path to folder that contains pages source
    - ``UPDATE_TIMEOUT``: Number of seconds to rescan source folder. 0 - disable
    - ``GITHUB_VALIDATE_IP``: Enable GitHub ip validation
    - ``GITHUB_SECRET``: GitHub web hook secret, optional
    - ``GITHUB_BRANCH``: GitHub branch to watch

Questions and Answers
---------------------

Run locally
~~~~~~~~~~~

.. code-block:: bash

    cd site
    virtualenv venv --no-site-packages -p /usr/local/bin/python3.5
    source venv/bin/activate
    pip install c2p2
    python engine/app.py

Open ``http://localhost:5000`` in browser.

Update site if md file was changed without server restart (watch md files)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Use UPDATE_TIMEOUT setting.

Update site on GitHub push
~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a new GitHub hook for your repository:
    - url: ``http://mysite.com/pull``
    - secret: should be equal to GITHUB_SECRET setting value

Production configuration
~~~~~~~~~~~~~~~~~~~~~~~~

Example settings:
    - DEBUG=false
    - UPDATE_TIMEOUT=0
    - GITHUB_VALIDATE_IP=true
    - GITHUB_SECRET=<webhook secret>
    - GITHUB_BRANCH=master

Example supervisor configuration:

.. code-block:: text

    [program:mysite]
    process_name=mysite
    directory=/home/deploy/mysite
    environment=C2P2_PORT=5100,C2P2_DEBUG=false,C2P2_UPDATE_TIMEOUT=0,C2P2_GITHUB_VALIDATE_ID=true,C2P2_GIHUB_SECRET=123xyz,C2P2_GITHUB_BRANCH=master
    command=/home/deploy/mysite/venv/bin/python engine/app.py
    user=deploy
    stdout_logfile=/var/log/mysite/out.log
    stderr_logfile=/var/log/mysite/err.log
    autostart=true
    autorestart=true

Example nginx configuration:

.. code-block:: nginx

    upstream mysite {
        server 127.0.0.1:5100;
    }

    server {
        listen   80;

        # If you need to restrict access
        # auth_basic "Restricted";
        # auth_basic_user_file /etc/nginx/.htpasswd;

        server_name mysite.com;

        location / {
            proxy_cache off;
            proxy_pass http://mysite;
        }

        location ~* \.(?:css|png|jpe?g|gif|ico|zip|txt)$ {
            root /home/deploy/mysite;
            log_not_found off;
        }

        error_page 500 502 503 504 /home/deploy/mysite/engine/templates/500.html;
        error_page 400 402 403 404 /home/deploy/mysite/engine/templates/400.html;
    }

Favicon and robots.txt
~~~~~~~~~~~~~~~~~~~~~~

Just add favicon.ico and robots.txt to root folder of your site.

Custom md directives
~~~~~~~~~~~~~~~~~~~~

It is possible to register custom md directives:

.. code-block:: python

    from c2p2.utils import ExtensionsRegistry

    ExtensionsRegistry.register(extension=MyExtension)

Edit on GitHub link
~~~~~~~~~~~~~~~~~~~

.. code-block:: django

    <a href="https://github.com/nanvel/mysite/blob/master/{{ c.page.uri }}.md" target="_blank">Edit on GitHub</a>

Tests
-----

.. code-block:: bash

    python -m unittest c2p2.tests

Contribute
----------

If you want to contribute to this project, please perform the following steps:

.. code-block:: bash

    # Fork this repository
    $ virtualenv .env --no-site-packages -p /usr/local/bin/python3.5
    $ source .env/bin/activate
    $ python setup.py install
    $ pip install -r requirements.txt

    $ git branch feature_branch master
    # Implement your feature and tests
    $ git add . && git commit
    $ git push -u origin feature_branch
    # Send me a pull request for your feature branch