From dd7a2fd914b83f320eacc2c1c6adac773b2c6426 Mon Sep 17 00:00:00 2001 From: Ian Foote Date: Mon, 23 Sep 2013 15:10:31 +0100 Subject: [PATCH] Install garden packages listed in buildozer.spec. Requires local copy of garden script. --- buildozer/__init__.py | 26 ++++-- tools/garden | 190 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 6 deletions(-) create mode 100755 tools/garden diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 90e60f8..c4927e0 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -395,21 +395,27 @@ class Buildozer(object): garden_requirements = self.config.getlist('app', 'garden_requirements', '') - if self.state.get('cache.gardenlibs', '') == garden_requirements: + # have we installed the garden packages? + if exists(self.gardenlibs_dir) and \ + self.state.get('cache.gardenlibs', '') == garden_requirements: self.debug('Garden requirements already installed, pass') return + # recreate gardenlibs + self.rmdir(self.gardenlibs_dir) + self.mkdir(self.gardenlibs_dir) + for requirement in garden_requirements: self._install_garden_package(requirement) + # save gardenlibs state self.state['cache.gardenlibs'] = garden_requirements def _install_garden_package(self, package): - self._ensure_virtualenv() - self.debug('Install garden package {} in virtualenv'.format(package)) - self.cmd('garden install --app {}'.format(package), - env=self.env_venv, - cwd=self.app_dir) + self.debug('Install garden package {} in app_dir'.format(package)) + self.cmd('~/buildozer/tools/garden install --app {}'.format( + package), + cwd=self.buildozer_dir) def _ensure_virtualenv(self): if hasattr(self, 'venv'): @@ -554,6 +560,7 @@ class Buildozer(object): def build_application(self): self._copy_application_sources() self._copy_application_libs() + self._copy_garden_libs() self._add_sitecustomize() def _copy_application_sources(self): @@ -642,6 +649,9 @@ class Buildozer(object): # copy also the libs copytree(self.applibs_dir, join(self.app_dir, '_applibs')) + def _copy_garden_libs(self): + copytree(self.gardenlibs_dir, join(self.app_dir, 'libs')) + def _add_sitecustomize(self): copyfile(join(dirname(__file__), 'sitecustomize.py'), join(self.app_dir, 'sitecustomize.py')) @@ -676,6 +686,10 @@ class Buildozer(object): def applibs_dir(self): return join(self.buildozer_dir, 'applibs') + @property + def gardenlibs_dir(self): + return join(self.buildozer_dir, 'libs') + @property def global_buildozer_dir(self): return join(expanduser('~'), '.buildozer') diff --git a/tools/garden b/tools/garden new file mode 100755 index 0000000..2f16bdc --- /dev/null +++ b/tools/garden @@ -0,0 +1,190 @@ +#!/usr/bin/env python + +import sys +import argparse +import zipfile +import tempfile +from shutil import rmtree, move +from os import listdir, getcwd, chdir, makedirs +from os.path import join, realpath, exists, isdir, expanduser + +try: + from cStringIO import StringIO +except ImportError: + try: + from StringIO import StringIO + except ImportError: + from io import StringIO + +try: + import requests +except ImportError: + print('Garden tool require requests library.') + print('Try to "pip install requests" in root') + sys.exit(1) + + +garden_system_dir = join(expanduser('~'), '.kivy', 'garden') +garden_app_dir = join(realpath(getcwd()), 'libs', 'garden') + + +class GardenTool(object): + '''Garden command-line tool. + ''' + + def main(self, argv): + parser = argparse.ArgumentParser(description=self.__doc__) + subparsers = parser.add_subparsers() + + p = subparsers.add_parser('list', + help='List all the installed garden packages') + p.add_argument('--app', action='store_true', + help='Use the local app directory (./libs/garden)') + p.set_defaults(func=self.cmd_list) + + p = subparsers.add_parser('search', + help='Search garden package on github') + p.add_argument('pattern', nargs='?', default='', + help='Word to search in the package name (optional)') + p.set_defaults(func=self.cmd_search) + + p = subparsers.add_parser('install', + help='Install a garden package') + p.add_argument('--app', action='store_true', + help='Install in the local app directory (./libs/garden)') + p.add_argument('--upgrade', action='store_true', + help='Force the installation') + p.add_argument('package', nargs=1, + help='Name of the package to install') + p.set_defaults(func=self.cmd_install) + + p = subparsers.add_parser('uninstall', + help='Uninstall a garden package') + p.add_argument('--app', action='store_true', + help='Use the local app directory (./libs/garden)') + p.add_argument('package', nargs=1, + help='Name of the package to uninstall') + p.set_defaults(func=self.cmd_uninstall) + + self.options = options = parser.parse_args(argv) + + options.func() + + def cmd_list(self): + directory = garden_app_dir if self.options.app else garden_system_dir + if not exists(directory): + return + + for filename in listdir(directory): + fullname = join(directory, filename) + if filename.startswith('garden.') and isdir(fullname): + print(filename.split('.', 1)[-1]) + + def cmd_search(self): + r = requests.get('https://api.github.com/users/kivy-garden/repos') + pattern = self.options.pattern + data = r.json() + for repo in data: + if not repo['name'].startswith('garden.'): + continue + name = repo['name'].split('.', 1)[-1] + if pattern and pattern not in name: + continue + + print("{} - {}".format( + name, repo['description'].splitlines()[0])) + + def cmd_install(self): + opts = self.options + opts.package = self.gardenify(opts.package[0]) + + garden_dir = garden_app_dir if self.options.app else garden_system_dir + dest_dir = join(garden_dir, opts.package) + + if exists(dest_dir) and not opts.upgrade: + print('Garden package already installed in {}'.format(dest_dir)) + print('Use --upgrade to upgrade.') + sys.exit(0) + + fd = self.download(opts.package) + tempdir = tempfile.mkdtemp(prefix='garden-') + try: + self.extract(fd, tempdir) + + if not exists(garden_dir): + makedirs(garden_dir) + + if exists(dest_dir): + print('Removing old version...') + rmtree(dest_dir) + + source_directory = join(tempdir, '{}-master'.format(opts.package)) + + print('Installing new version...') + move(source_directory, dest_dir) + + print('Done! {} is installed at: {}'.format(opts.package, + dest_dir)) + + finally: + print('Cleaning...') + if exists(tempdir): + rmtree(tempdir, ignore_errors=True) + + def cmd_uninstall(self): + opts = self.options + opts.package = self.gardenify(opts.package[0]) + garden_dir = garden_app_dir if self.options.app else garden_system_dir + d = join(garden_dir, opts.package) + if not exists(d): + print('Package {} not installed, nothing to uninstall.'.format( + opts.package)) + sys.exit(0) + + print('Deleting {}...'.format(d)) + rmtree(d) + + + def gardenify(self, package): + if not package.startswith('garden.'): + return 'garden.' + package + return package + + def download(self, package): + url = 'http://github.com/kivy-garden/{}/archive/master.zip'.format( + package) + + print('Downloading {} ...'.format(url)) + r = requests.get(url)#, prefetch=False) + if r.status_code != 200: + print('Unable to found the garden package. (error={})'.format( + r.status_code)) + sys.exit(1) + + animation = '\\|/-' + index = 0 + count = 0 + data = '' + for buf in r.iter_content(1024): + index += 1 + data += buf + count += len(buf) + print('Progression', count, animation[index % len(animation)], '\r') + sys.stdout.flush() + print('Download done ({} downloaded)'.format(count)) + + return StringIO(data) + + def extract(self, fd, directory): + print('Extracting...') + z = zipfile.ZipFile(fd) + curdir = getcwd() + chdir(directory) + z.extractall() + chdir(curdir) + + + +if __name__ == '__main__': + GardenTool().main(sys.argv[1:]) +