示例#1
0
    def __init__(
        self, requirement=None, remote_package_index=None,
        local_cache=None, build_cache=None,
        s3_cache=None, s3_config=None):
        if not s3_cache.endswith('/'): s3_cache += '/'

        self._requirement = requirement
        self._local_cache = path(local_cache).expand() + '/'
        self._build_cache = path(build_cache).expand()
        self._pi_remote = PackageIndex(remote_package_index)
        self._pi_local = PackageIndex(self._local_cache)
        self._s3_cache = s3_cache
        self._s3_config = path(s3_config).expand()
示例#2
0
class Eggcelerator(object):

    def __init__(
        self, requirement=None, remote_package_index=None,
        local_cache=None, build_cache=None,
        s3_cache=None, s3_config=None):
        if not s3_cache.endswith('/'): s3_cache += '/'

        self._requirement = requirement
        self._local_cache = path(local_cache).expand() + '/'
        self._build_cache = path(build_cache).expand()
        self._pi_remote = PackageIndex(remote_package_index)
        self._pi_local = PackageIndex(self._local_cache)
        self._s3_cache = s3_cache
        self._s3_config = path(s3_config).expand()

    def run_all(self):
        if not self._local_cache.exists():
            self._local_cache.makedirs()
        if not self._build_cache.exists():
            self._build_cache.makedirs()

        s3cmd = path(sys.prefix) / 'bin/s3cmd'

        if self._s3_cache:
            log.info('Initial sync with %s', self._s3_cache)
            cmd = [s3cmd, '-c', self._s3_config, 'sync',
                   self._s3_cache, self._local_cache ]
            log.debug('Command is %r', map(str, cmd))
            check_call(cmd)

        with open(self._requirement) as fp:
            requirements = list(parse_requirements(fp))

        log.debug('Generate a set of distributions to satisfy all reqs and their dependencies')
        dists = self.get_distributions(requirements)
        requirements = [ dist.as_requirement() for dist in dists ]

        log.info('Ensure packages are cached locally')
        for req in requirements:
            self.ensure_local_req(req)
        log.debug('done.')

        log.info('Ensure packages have binary eggs locally')
        for req in requirements:
            self.ensure_bdist(req)
            # bdist = self.ensure_bdist(req)
            # self.install_bdist(bdist)
        log.debug('done.')

        log.info('Cleanup build directories')
        self._build_cache.rmtree()

        if self._s3_cache:
            log.info('Final sync with %s', self._s3_cache)
            cmd = [s3cmd, '-c', self._s3_config, 'sync' ]
            cmd += self._local_cache.glob('*')
            cmd.append(self._s3_cache)
            log.debug('Command is %r', map(str, cmd))
            check_call(cmd)

    def get_distributions(self, requirements):
        ws = WorkingSet()
        remote_fetches = []
        def installer(req):
            dist = find_dist(req)
            if dist is None: return None
            self.install_dist(dist)
            return dist
        def find_dist(req):
            self._pi_local.find_packages(req)
            for dist in sorted(self._pi_local[req.key], key=lambda d: -d.precedence):
                if dist in req: return dist
            remote_fetches.append(req)
            self._pi_remote.find_packages(req)
            for dist in sorted(self._pi_remote[req.key], key=lambda d: -d.precedence):
                if dist in req: return dist
        result = ws.resolve(requirements, installer=installer)
        log.debug('Remote fetches:')
        for req in remote_fetches:
            log.debug('%s', req)
        return result

    def ensure_local_req(self, req):
        log.debug('ensure local: %s', req)
        self._pi_local.find_packages(req)
        for dist in sorted(self._pi_local[req.key], key=lambda d: -d.precedence):
            if dist in req:
                log.debug('Found %s to satisfy %s', dist.location, req)
                break
        else:
            self.download_req(req)

    def ensure_bdist(self, req):
        log.debug('ensure bdist: %s', req)
        self._pi_local.find_packages(req)
        dists = [ dist for dist in self._pi_local[req.key]
                  if dist in req ]
        bdists = [ dist for dist in dists
                   if dist.location.endswith('.egg')
                   and dist.platform in (None, get_build_platform()) ]
        assert dists, 'No distributions found for %s' % req
        if bdists:
            log.debug('Found bdist: %s', bdists[0].location)
        if not bdists:
            bdists = self.compile_bdist(dists[0])
            log.debug('Compiled bdist: %s', bdists[0].location)
        return bdists[0]

    def install_dist(self, dist):
        log.info('Install %s', dist.location)
        cmd_local = [ sys.prefix + '/bin/easy_install',
                      '-i', self._local_cache, 
                      dist.location ]
        cmd_remote = [ sys.prefix + '/bin/easy_install',
                      dist.location ]
        log.debug('Command is %r', map(str, cmd_local))
        try:
            check_call(cmd_local)
        except CalledProcessError:
            log.exception('Error installing %s, retrying', dist.location)
            check_call(cmd_remote)

    def install_bdist(self, bdist):
        log.info('Install %s', bdist.location)
        cmd = [ sys.prefix + '/bin/easy_install',
                '-i', self._local_cache, bdist.location]
        log.debug('Command is %r', map(str, cmd))
        try:
            check_call(cmd)
        except CalledProcessError:
            log.exception('Error installing %s, retrying', bdist.location)
            check_call(cmd)

    def download_req(self, req):
        log.debug('Download %s', req)
        try:
            self._pi_remote.find_packages(req)
        except socket.timeout:
            log.warning(
                'Socket timeout looking up %s, may have missing packages', req)
        for dist in self._pi_remote[req.key]:
            if dist.as_requirement() == req:
                dest = self._local_cache / req.project_name
                if not dest.exists():
                    dest.mkdir()
                self._pi_remote.download(req, dest)
                break
        else:
            assert False, "Requirement not found: %s" % req

    def compile_bdist(self, dist):
        build_dir = self._build_cache / dist.project_name + '-' + dist.version
        if build_dir.exists():
            build_dir.rmtree()
            
        unpack_archive(dist.location, self._build_cache)
        dest_dir = self._local_cache / dist.project_name
        result = []
        self._build_an_egg(build_dir)
        fns = (build_dir / 'dist').listdir()
        assert len(fns) == 1, (
            "Don't know what to do with multiple files in the dist dir")
        pathname, ext = path(fns[0]).splitext()
        dest_fn = dest_dir / (fns[0]).basename()
        path(fns[0]).copy(dest_fn)
        result.append(dist.clone(
                location=dest_fn,
                platform=get_build_platform()))
        return result

    def _build_an_egg(self, build_dir):
        with build_dir:
            try:
                check_call(
                    [sys.executable, 'setup.py', 'bdist_egg'])
            except CalledProcessError:
                # Monkey-patch the setup.py to include setuptools instead of distutils
                path('setup.py').copy('setup-eggcelerator-inner.py')
                path('setup.py').write_text(
                    "import distutils.core\n"
                    "import setuptools\n"
                    "distutils.core.setup = setuptools.setup\n"
                    "execfile('setup-eggcelerator-inner.py')")
                check_call(
                    [sys.executable, 'setup.py', 'bdist_egg'])