<?xml version="1.0" encoding="UTF-8" ?>
<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><Project><name>pylons_sandbox</name>
<shortdesc>An experimental Buildout recipe backwards-compatible with zc.buildout.egg but with extra features for Pylons users.</shortdesc>
<description>***********************
Buildout Sandbox Recipe
***********************

.. contents ::

This is a recipe for use with Buildout. It is identical to Buildout's
zc.recipe.egg but has the following extra features:

* Can install the scripts from any dependent package
* Can setup an executable interpreter if you provide a suitable
  application for your platform

.. warning ::

    This is very much alpha software and has only been tested on Debian Etch.
    There are probably bugs on other platforms such as Windows. It is designed
    more as a proof-of-concept than a production-ready recipe.

To get started first download the Buildout bootstrap::

    wget "http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py"

Then create a ``buildout.cfg`` file, replacing ``/path/to/pylons/app/src`` with
the path to your Pylons application and replacing ``PylonsApp`` with the name
of your application::

    [buildout]
    develop = /path/to/pylons/app/src
    parts = python

    [python]
    recipe = pylons_sandbox
    interpreter = python
    eggs = PylonsApp

You can now buildout your application::

    $ python bootstrap.py
    $ bin/buildout

So far the ``pylons_sandbox`` recipe has behaved *exaclty* the same as the
default ``zc.buildout.egg`` recipe, installing all the required dependencies
for your Pylons app to the local buildout sandbox. It has also set you up with
a ``bin/python`` script and a ``bin/buildout`` script which you can use to
buildout any future changes.

For Pylons use you should set the option ``dependent_scripts=True`` so that
scripts from packages such as ``Nose`` and ``PasteScript`` get created in the
``bin`` directoy::

    [buildout]
    develop = /path/to/pylons/app/src
    parts = python

    [python]
    recipe = pylons_sandbox
    interpreter = python
    eggs = PylonsApp
    dependent_scripts = True

Now run the following to re-buildout the directory::

    $ bin/buildout -N

The ``-N`` option means that buildout doesn't look for new dependencies if it
can meet them from files it already has installed. This means it is a bit
quicker to re-buildout the directory.

You should now have a ``bin/paster`` command you can use to serve your Pylons
application.

For the majority of users this set up will be fine but the ``pylons_sandbox``
recipe has one more feature, the ``launcher`` option.

If you want to treat your buildout setup as a true sandbox you will need a
Python interpreter which is an actual executable so that other scripts can use
your sandboxed Python interpreter in a #! line of in a script such as a CGI
script used by Apache. The ``python`` file generated by Buildout is actually
just a Python script itself so can't be used in this manner.

If you set the ``launcher`` option, the ``pylons_sandbox`` recipe will create a
new interpreter by appending ``.buildout`` to the name specified in the
``interpreter`` option and it will add a facility so that the directory of the
calling script is on sys.path. It will then copy the application specified by
the ``launcher`` option to the name specified in the ``interpreter`` option. In
our exampls so far this means the buildout ``python`` script would be in
``bin/python.buildout`` and the application to lauch it would be in
``bin/python`` and could now be used in a ``#!`` line.

This is all well and good but you need the application itself. Here is some C++
code which when compiled will create a suitable application. It has been
described as "gruesome" so I'm happy to accept a patch with some neater C++. 
Create a ``launcher.cc`` file with this content::

    /*
     * Buildout Launcher 
     * +++++++++++++++++
     *
     * This application excutes a python script in the same directory as the
     * application. This is useful because it effectively turns a Python script
     * into a real executable which you can use on the #! line of other scripts. 
     *
     * The script to be executed should have the same name as the the filename of
     * this compiled program but with a .py extension added to the end. The real
     * Python interpreter used to execute the script is dermined from the script's
     * #! line or /usr/bin/python is used as a fallback if no Python interpreter
     * can be found. 
     *
     * The Python interpreters generated by Buildout are actually just Python
     * scripts so this application allows them to be run from a real executable.
     *
     * Compile this file with the following command:
     *
     *     g++ launcher.cc -o launcher
     *
     * Copyright James Gardner. MIT license. No warranty to the maximum extent
     * possible under the law.
     *
     */
    
    #include &lt;vector&gt;
    #include &lt;string&gt;
    #include &lt;unistd.h&gt;
    #include &lt;fstream&gt;
    
    using namespace std;
    int main(int argc,char *argv[])
    {
        vector&lt;string&gt; args;
        int i;
        args.push_back("python");
        for (i=0;i&lt;argc;i++) 
            args.push_back(argv[i]);
        args[1] = strcat(argv[0], ".buildout");
        char *new_argv[argc+1];
        for (int i=0 ; i&lt;argc+1 ; i++)  {
            new_argv[i] = (char *)args[i].c_str();
        }
        new_argv[argc+1] = NULL;
        vector&lt;string&gt; text_file;
        ifstream ifs(new_argv[1]);
        string temp;
        string temp_short;
        getline(ifs, temp);
        if (strncmp((char *)temp.c_str(), "#!", 2)) {
            /* default to /usr/bin/python if no #! header */
            temp_short = "/usr/bin/python";
        } else {
            temp_short = temp.substr(2,(temp.length()-2));
        }
        char python[temp_short.length()];
        strcpy(python, (char *)temp_short.c_str());
        return execv(python, new_argv);
    }


Compile this with::

    $ g++ launcher.cc -o launcher

and place the ``launcher`` application in the same directory as your
``buildout.cfg``. You can then update your ``buildout.cfg`` to look like this::

    [buildout]
    develop = /path/to/pylons/app/src
    parts = python

    [python]
    recipe = pylons_sandbox
    interpreter = python
    eggs = PylonsApp
    dependent_scripts = True
    launcher = launcher

Now re-buildout again::

    $ bin/buildout -N
    
You should have a nicely working sandbox with a real Python executable as well
as all the other benefits of deploying using the Buildout system.

Test it out::

    $ bin/python
    &gt;&gt;&gt; import pylons
    &gt;&gt;&gt; 

As you can see all the module dependencies are present.


Changes
=======

0.1.0

* First release


Download
========</description>
<maintainer><foaf:Person><foaf:name>James Gardner</foaf:name>
<foaf:mbox_sha1sum>2c9aeb7a45a5e68f20265cc17ef676e567912c0a</foaf:mbox_sha1sum></foaf:Person></maintainer>
<release><Version><revision>0.1.0</revision></Version></release>
</Project></rdf:RDF>