Card Stories - Packaging and Distribution Documentation

From Farsides Wiki

Jump to: navigation, search

A python package, a Debian GNU/Linux package and a twistd plugin are bundled together. The server side tests and client side tests can be run with a single command.

Contents

[edit] Packaging

[edit] setup.py

The setup.py exists in conformance to the distutils python requirements. The reference documentation for each fields complements the guide. It is best understood by reading an example such as the django setup.py.

The setup.py file alone describes the binary distribution created with

python setup.py bdist

but it must be complemented with a MANIFEST.in file as explained in the source distribution documentation.

python setup.py sdist

There is no support to run tests at this time.

[edit] Debian GNU/Linux

A native package exists, meaning the debian package is part of the source distribution and is maintained by the author of the package. The static files, including the JavaScript client are copied to /usr/share/cardstories. The database is stored in /var/cache/cardstories. The daemon is launched by an init file using the twistd plugin architecture.

The presence of the setup.py file at the root of the source tree is automatically detected by debhelper 7 and used to figure out the layout of the Debian package.

[edit] Building

git clone http://cardstori.es/cardstories.git
cd cardstories
v=1.0.3 ; python setup.py sdist --dist-dir .. ; mv ../cardstories-$v.tar.gz ../cardstories_$v.orig.tar.gz
debuild -uc -us

[edit] twistd plugin

The plugin is installed in /etc/cardstories and its integration can be seen with :

$ PYTHONPATH=/etc/cardstories twistd --help
...
   cardstories        Find out a card using a sentence made up by another
                       player
...

If it needs to be run manually, the usage can be displayed with:

$ PYTHONPATH=/etc/cardstories twistd cardstories --help
Usage: twistd [options] cardstories [-h|--help] [-p|--port=] [-s|--ssl-port=] [-P|--ssl-pem=] [-d|--db=] [-v|--verbose]
Options:
  -v, --verbose     verbosity level
  -i, --interface=  Interface to which the server must be bound [default:
                    127.0.0.1]
  -p, --port=       Port on which to listen [default: 4923]
  -s, --ssl-port=   Port on which to listen for SSL
  -P, --ssl-pem=    certificate path name [default: /etc/cardstories/cert.pem]
  -d, --db=         sqlite3 game database path [default:
                    /var/cache/cardstories/cardstories.sqlite]
  -a, --auth=       authentication plugin values : basic
      --auth-db=    sqlite3 auth database path [default:
                    /var/cache/cardstories/auth.sqlite]
      --loop=       Number of ping batchs to run, -1 means forever, 0 means
                    never [default: -1]
      --static=     directory where /static files will be fetched [default:
                    /usr/share/cardstories]
      --version
      --help        Display this help and exit.

Find out a card using a sentence made up by another player

[edit] Tests

The maintain.mk file at the root of the source tree runs the tests with

$ make -f maintain.mk check
make -C tests check
python-coverage -e
PYTHONPATH=.. python-coverage -x test_auth.py
__main__.AuthTestInit.test00_create ... [OK]
__main__.AuthTest.test00 ... [OK]                                  

-------------------------------------------------------------------------------
Ran 2 tests in 0.326s                                                          

PASSED (successes=2)
PYTHONPATH=.. python-coverage -x test_service.py
__main__.CardstoriesServiceTestInit.test00_startService ... [OK]
__main__.CardstoriesServiceTest.test01_create ... [OK]
__main__.CardstoriesServiceTest.test02_participate ... [OK]
__main__.CardstoriesServiceTest.test03_player2game ... [OK]
__main__.CardstoriesServiceTest.test04_pick ... [OK]
__main__.CardstoriesServiceTest.test05_state_vote ... [OK]
__main__.CardstoriesServiceTest.test06_vote ... [OK]
__main__.CardstoriesServiceTest.test07_complete ... [OK]
__main__.CardstoriesServiceTest.test08_game ... [OK]
__main__.CardstoriesServiceTest.test09_invitation ... [OK]
__main__.CardstoriesServiceTest.test10_lobby ... [OK]
__main__.CardstoriesServiceTestHandle.test01_required ... [OK]
__main__.CardstoriesServiceTestHandle.test02_handle ... [OK]
__main__.CardstoriesServiceTestRun.test00_run ... [OK]

-------------------------------------------------------------------------------
Ran 14 tests in 2.926s

PASSED (successes=14)
PYTHONPATH=.. python-coverage -x test_site.py
__main__.CardstoriesSiteTest.test00_render ... [OK]
__main__.CardstoriesSiteTest.test00_render_static ... [OK]
__main__.CardstoriesSiteTest.test01_wrap_http ... [OK]
__main__.CardstoriesSiteTest.test02_wrap_http_fail ... [OK]
__main__.CardstoriesSiteTest.test03_handle ... [OK]
__main__.AGPLResourceTest.test00_render ... [OK]
__main__.AGPLResourceTest.test01_agpl ... [OK]

-------------------------------------------------------------------------------
Ran 7 tests in 0.050s

PASSED (successes=7)
PYTHONPATH=.. python-coverage -x test_tap.py
__main__.CardstoriesServerTest.test01_connect ... [OK]
__main__.CardstoriesServerTest.test02_parseOptions ... [OK]
__main__.CardstoriesServerTestSSL.test01 ... [OK]

-------------------------------------------------------------------------------
Ran 3 tests in 0.153s

PASSED (successes=3)
python-coverage -m -a -r ../cardstories/*.py
Name                      Stmts   Exec  Cover   Missing
-------------------------------------------------------
../cardstories/__init__       1      1   100%
../cardstories/auth          38     38   100%
../cardstories/service      248    240    96%   112-114, 183, 186, 252, 330, 334
../cardstories/site          71     67    94%   36, 61, 64, 108
../cardstories/tap           21     21   100%
-------------------------------------------------------
TOTAL                       379    367    96%

The client side tests are run from a web browser and should display at the bottom of the page:

158 tests of 158 passed, 0 failed.

[edit] Automated AGPL compliance

A webservice partially automating the publication of server side sources licensed under the AGPL is included with the cardstories game. It could be reused in different contexts to help the occasional hacker to comply with the terms of the AGPL.

The primary reason for an author to use the AGPL instead of the GPL is to display a link to the server sources, as explained in the preamble:

…if your program is a web application, its interface could display a “Source” link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs;

When deploying an AGPL application server side, care must be taken to provide a way for the user to download the corresponding sources, including the local modifications:

Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software.

If the software is a webservice serving static files such as cardstories, the original sources could be included in an archive available at the same location ( for instance http://cardstories.dachary.org/cardstories/static/cardstories.zip ) and a link added in each page visible to the user.

[edit] Republishing server sources

If someone implements a quick but useful hack in the code, the overhead of the compliance is comparatively high. For a few lines of patch in a python file, one would need to rebuild a source distribution. For cardstories It could be done as follows on Debian GNU/Linux :

cd /usr/share/pyshared/cardstories
git init
git add .
git commit -m 'archive modified version'
apt-get install --reinstall python-cardstories
git diff > /tmp/cardstories-hack.diff
cd /tmp
apt-get source python-cardstories
cd python-cardstories-*/cardstories
patch -R < /tmp/cardstories-hack.diff
apt-get build-dep python-cardstories
dpkg -i ../*cardstories*.deb

It is a fairly long sequence of commands and it requires a knowledge of Debian GNU/Linux packaging that may not be available, even to a seasoned python hacker.

[edit] Automated source archive creation

A path in the webservice builds an archive containing the server side sources from the installed files instead of using the source files from the original distribution. A first version is implemented in cardstories to collect the files that would not be visible if browsing the static tree served by the webservice, i.e.

  • site.py
  • service.py
  • tap.py

The code triggered by the /agpl path is as follows:

class AGPLResource(static.File):

    def __init__(self, directory, module):
        self.directory = directory
        self.module = module
        self.zipfile = module.__name__ + '.zip'
        static.File.__init__(self, self.directory + '/' + self.zipfile)

    def render(self, request):
        self.update()
        return static.File.render(self, request)

    def update(self):
        directory = os.path.dirname(self.module.__file__)
        archive = self.directory + '/' + self.zipfile
        f = zipfile.ZipFile(archive, 'w')
        for path in glob.glob(directory + '/*.py'):
            f.write(path, os.path.basename(path))
        f.close()

This automation only addresses a specific case of AGPL compliance though. When more complex modifications are made to the software or its dependencies, there is a need for a careful update of the complete and corresponding source.

Personal tools