A simple filesystem based python index as an extensible application
Python CSS HTML
#12 Compare This branch is 186 commits ahead of k0s:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
cheeseprism
doc
tests
.gitignore
.travis.yml
CHANGES.rst
LICENSE.txt
MANIFEST.in
README.rst
dev-reqs.txt
development.ini
message-extraction.ini
production.ini
pytest.ini
run
runapp.py
setup.cfg
setup.py
tox.ini

README.rst

Cheese Prism

https://secure.travis-ci.org/whitmo/CheesePrism.png

A simple application for managing a static python package index. It borrows heavily from BasketWeaver and cheese_emporium. It leverages pip and setuptools for various package management tasks.

Why?

There are probably better options that are more actively maintained (devpi?).

Cheeseprism mainly excels at turning a folder full of tarballs into something you can pip install against. And the pip cache syncing is handy.

Running

Dev

Install

There are 2 main ways to get your CheesePrism up and running depending on your particular needs.

  1. Pip install the package from pypi:

    Activate your virtual env. Then either check out the code to your chosen location:

    $ git clone git://github.com/SurveyMonkey/CheesePrism.git
    

    and install:

    $ cd CheesePrism; pip install -e ./
    
  2. Pip install the source:

    Use pip to clone and install directly to $VIRTUAL_ENV/src:

    $ pip install git+git://github.com/SurveyMonkey/CheesePrism.git#egg=CheesePrism
    $ cd $VIRTUAL_ENV/src/cheeseprism
    

Test

If you have installed the source, to run the tests, first install the test requirements:

$ cd CheesePrism
$ pip install -r tests-reqs.txt

Then:

$ py.test

This will run tests and spit out coverage.

Run

The following will start the application and a static file server for CheesePrism suitable for testing and development:

$ pserve development.ini

You will need to install PasteScript in order to run this command (easy_install PasteScript).

If you have not installed the source (ie. you installed the package or from the strap file), you will need to copy the development.ini to a convient location.

You will also need to set the ini key cheeseprism.file_root to the directory you wish your index files to live in.

This directory may not exist yet, or could be an empty directory. If the directory contains well formed archives, it will build the index from what it finds there.

Production

CheesePrism doesn't pretend that it or python servers in general excel at serving flat files.

For a more durable and performantized setup, you will want to split the serving between a wsgi host for the management application and a industrial strength file server (say nginx).

Configure Nginx

See doc/sample-nginx.conf and replace alias CheesePrism/files; and alias CheesePrism/static with your fileroot and static filepath.

.. todo::

  have start up announce static and file_root (and document)


Serve management app

Use the prod.ini (edited for your setup) for simplest serving. Be sure to remove such things as pyramid.includes = pyramid_debugtoolbar if security is a concern:

$ pserve prod.ini

Sane people use something like upstart or supervisord to manage this process.

How to use

Release into your index

CheesePrism understand the upload interface of pypi. This means for python2.6 and better you can setup your ~/.pypirc and then upload to your prism as you would pypi:

[distutils]
   index-servers =
       pypi
       local


[pypi]
   username:user
   password:secret

[local]
   # your prism of fromage
   username:user
   password:secret
   repository:http://mycheese/simple

The you can upload a source ala:

$  cd /src/MyAwesomePyPkg
$  python setup.py sdist upload -r local

Note: The prism currently has the most basic support for pypi's basic auth scheme. This mainly exists for the purpose of grabbing the identity of who puports to be uploading a package, rather than any actual security. If you need more, it should provide a starting point for extension (see pyramid documentation for more information on extending pyramid apps).

Install from your index

Now your package is available for install from your prism:

$ pip install -i http://mycheese/index/ MyAwesomePyPkg

All dependencies of MyAwesomePyPkg will also come from your prism, so make sure they are there (coming feature will inspect your release and do the needful).

Populate your index with your dependencies

There are 3 main ways to load files:

  1. If you put archives into the file root of your index and restart the app, it will generate index entries for them. There are plans to make this automagical soon so a restart is not required.

  2. Through the 'Load Requirements' page you may upload a pip requirements files that CheesePrism will use to populate your index. Easiest way to create a pip requirements file for a virtualenv?:

    $ pip freeze -l > myawesomerequirement.txt
    
  3. Use the "Find Package" page to search pypi and load packages into the index. Currently this utilizes some state change on GET but does remain idempotent (to be fixed soon).

See Pip cache syncing below for a final way to populate your index.

JSON API

There is also rudimentary read only json api:

$ curl GET http://mycheese/index/index.json

The resulting json is a hash of objects keyed by md5 hashes of each archive. Let's imagine our index only holds webob:

{u'1b6795baf23f6c1553186a0a8b1a2621':{u'added': 1325609450.792506,
                                      u'filename': u'WebOb-1.2b2.zip',
                                      u'name': u'WebOb',
                                      u'version': u'1.2b2'}}

There is a per package api also (say mock is in our index):

$ curl GET http://mycheese/index/mock/index.json

It returns a list of the available versions for the package:

[{"version": "1.0.1",
  "name": "mock",
  "size": 818644,
  "mtime": 1381377142.0,
  "atime": 1381377142.0,
  "ctime": 1381377142.0,
  "filename": "mock-1.0.1.tar.gz"}]

HTTP API

Files may be added to the index from pypi via a not so RESTful interface that will soon go away. Provided name and version exist in PyPi, the following will download the file from pypi and register it with the index:

$ curl GET http://mycheese/package/{name}/{version}

Advanced Feature Configuration

Cheeseprism has a few knobs that might help adapt it to your usecase.

Pip cache syncing

Occasionally we find ourself needing to populate a virtualenv and lacking network access. Cheeseprism includes an optional that will, upon starting cheeseprism, copy and index all packages in your PIP_DOWNLOAD_CACHE folder, thus making them available to install. Add this line to your ini:

cheeseprism.pipcache_mirror=true

Configure Concurrency for index management

Under the hood for highly repetive tasks, Cheeseprism uses futures to speed certain operations.

The number of workers may be configured by:

cheeseprism.futures.workers = 12

v0.4.0a7 removes the option for the process executor.

Skip writing index.html

Use directory listing in nginx renderers has some advantages over using the Cheeseprism generated index (byte counts, see all the files, etc, faster index updating). This configuration option tells CheesePrism to skip creating the index.html for the root directory or the package directories:

cheeseprism.write_html = false

With html generation turned off, Cheeseprism manages hyperlinks by creating symlinks.

Future

Really, the future is likely an different pypi mirror like devpi.

Some features we thought about implementing:

  • Multi-index support: The general idea is that you can evolve indexes rather like requirements files but by explicit limiting of membership in a group rather than specification that requires talking to an external index. One archive might exist in multiple indexes (but always serve from same location to preserve pip caching).

    This would include a ui for select member archives to compose an new index as well as cloning and extending an existing index.

  • Less crap work: automatic dependency loading for releases and packages loaded via find packages. A file watcher for the repo that rebuilds the appropriate parts of the index when files are added and removed.

  • Better readonly api: versions.json for each package with the data in index.json provided in a more easily consumable fashion.

  • Better REST: Make POST /packages/{name}/{version} to grab a package from PyPi. Make GET /packages/{name}/{version} provide data about the package and indicate whether the package current lives in index or not.

  • Proper sphinx documentation: yup.

Contact / Wanna get involved?

Pull requests welcome!

I'm on freenode at #pyramid, whit most days if you have questions or comments.