Source

xenv / xenv / models.py

import os
from paver.easy import path
from subprocess import call, check_output
from urllib2 import urlopen
from urlparse import urljoin


class XenvFS(object):
    '''The xenv filesystem object provides the specification for the
    xenv filesystem. This will allow finding directories, establishing
    the PATH when calling a command along with locations for specific
    files.'''
    def __init__(self, root=None):
        self.root = path(root or '.')

    def create_base_env(self):
        (self.root / 'local').mkdir()

    def create_venv(self):
        venv = self.root.abspath() / 'usr'
        cmd = 'virtualenv --no-site-packages %s' % venv
        call(cmd.split())

    def path(self):
        '''Return the path hiearchy'''
        return ':'.join([
                (self.root / 'usr' / 'bin').abspath(),
                (self.root / 'local' / 'bin').abspath(),
                ])


class Xenv(object):
    def __init__(self, root=None):
        self.xenv_fs = XenvFS(root)
        self.root = self.xenv_fs.root.abspath()

    def run(self, cmd):
        env = os.environ.copy()
        env['PATH'] = self.xenv_fs.path() + ':' + env['PATH']
        try:
            call(cmd, env=env)
        except OSError as e:
            print(e)
        except KeyboardInterrupt:
            pass

    def create(self):
        self.xenv_fs.root.mkdir()
        self.xenv_fs.create_base_env()
        self.xenv_fs.create_venv()

    def install(self, pkg):
        pkgfile = pkg.fetch(self)
        call(['tar', 'xf', pkgfile], cwd=self.root)
        install_hook = self.root / 'packages' / 'install'

        history = self.root / 'packages' / pkg.name / pkg.version
        history.makedirs()

        if install_hook.isfile():
            call(install_hook.abspath(), cwd=self.root)
            install_hook.move(history)
        (self.root / pkg.fname).move(history)

    def uninstall(self, pkg):
        pkg_path = self.root / 'packages' / pkg.name / pkg.version / pkg.fname
        filelist = check_output([
            'tar', 'tf', pkg_path
        ])
        uninstall_hook = os.path.join(self.root, 'packages',
                                      pkg.name, pkg.version,
                                      'uninstall')
        history = self.root / 'packages' / pkg.name / pkg.version

        for line in filelist.split('\n'):
            name = path(line)
            if name.isfile():
                name.remove()

        if uninstall_hook.isfile():
            call(uninstall_hook.abspath(), cwd=self.root)

        history.removedirs()


class Package(object):
    '''
    A simple package format for a xenv. See the README for more info.
    '''

    def __init__(self, name, version, base='file:'):
        self.name = name
        self.version = version
        self.base = base
        self.pkg_tmpl = '{self.name}-{self.version}.tar'

    @property
    def fname(self):
        return path(self.pkg_tmpl.format(**vars()))

    def fetch(self, xenv):
        if self.base.startswith('file:'):
            fname = self.fname.abspath()
        url = urljoin(self.base, fname)
        pkgfile = urlopen(url)
        return self.save(pkgfile, xenv)

    def save(self, fh, xenv):
        fname = self.pkg_tmpl.format(**vars())
        pkgfile = xenv.root.abspath() / fname
        with open(pkgfile, 'w+') as pkg:
            for line in fh:
                pkg.write(line)
        return pkgfile