From: Denis Thulin <denis.thulin@openwide.fr>
To: buildroot@busybox.net
Subject: [Buildroot] [PATCH 1/2] scanpypi: new utility
Date: Mon, 31 Aug 2015 17:58:18 +0200 (CEST) [thread overview]
Message-ID: <2127757025.300457.1441036698136.JavaMail.zimbra@openwide.fr> (raw)
In-Reply-To: <1438089330-18923-1-git-send-email-denis.thulin@openwide.fr>
Hi all,
There was no comments on that patch, so I'm assuming it went unnoticed.
If there is anything wrong or not working, just let me know.
Have a good day.
Denis.
----- Le 28 Juil 15, ? 15:15, Denis THULIN denis.thulin at openwide.fr a ?crit :
> An utility for creating python package from the python package index
> It fetches packages info from http://pypi.python.org and generates
> corresponding packages files.
>
> Signed-off-by: Denis THULIN <denis.thulin@openwide.fr>
> ---
> v0: initial commit
> python-pacakage-generator.py is an utility for automatically generating a
> python package. It fetches packages info from http://pypi.python.org and
> generates corresponding packages files.
>
> v1:
> - renamed python-package-generator to scanpypi
> - split the huge script into a lot of functions
> - fixed mistakes and small bugs
>
> v2:
> - Rewrited most of the functions into a class
> - Changed the method for importing setup.py
> - Created a main function to avoid use of global variable
> - Now adds new dependencies to the list of packages to create
> - Droppped the .py extension
>
> v3:
> - Fixed bugs on import setup (Relative import works again)
> - Can handle packages as zipfile
> - Now avoids bdist packages
> - Changed behaviour for packages that are not hosted on PyPI
> - Added various clarifications of the code
> - Works with: flask django robotframework pyxml pyzmq Twisted Six
> - Does not work with: setuptools
> ---
> docs/manual/adding-packages-python.txt | 43 +++
> support/scripts/scanpypi | 653 +++++++++++++++++++++++++++++++++
> 2 files changed, 696 insertions(+)
> create mode 100755 support/scripts/scanpypi
>
> diff --git a/docs/manual/adding-packages-python.txt
> b/docs/manual/adding-packages-python.txt
> index 588dbf8..1f160ca 100644
> --- a/docs/manual/adding-packages-python.txt
> +++ b/docs/manual/adding-packages-python.txt
> @@ -7,6 +7,49 @@ This infrastructure applies to Python packages that use the
> standard
> Python setuptools mechanism as their build system, generally
> recognizable by the usage of a +setup.py+ script.
>
> +[[scanpypi]]
> +
> +==== Generating a +python-package+ from a PyPI repository
> +
> +You may want to use the +scanpypi+ located in +support/script+ to generate a
> +package from an existing PyPI package.
> +
> +you can find the list of existing PyPI package https://pypi.python.org[here].
> +
> +Please keep in mind that you most likely need to manually check the package for
> +any mistakes as there are things that cannot be guessed by the generator (e.g.
> +dependencies on any of the python core modules such as
> BR2_PACKAGE_PYTHON_ZLIB).
> +Also, please take note that the license and license files are guessed and must
> +be checked. You also need to manually add the package to the
> +package/Config.in+
> +file.
> +
> +When at the root of your buildroot directory just do :
> +
> +-----------------------
> +./support/script/scanpypi foo bar -o package
> +-----------------------
> +
> +This will generate packages +python-foo+ and +python-bar+ in the package
> +folder if they exist on https://pypi.python.org.
> +
> +Find the +external python modules+ menu and insert your package inside.
> +Keep in mind that the items inside a menu should be in alphabetical order.
> +
> +If your package is external, use the -o flag.
> +
> +-----------------------
> +./support/script/scanpypi foo bar -o other_package_dir
> +-----------------------
> +
> +This will generate packages +python-foo+ and +python-bar+ in the
> ++other_package_directory+ instead of +package+.
> +
> +Option +-h+ wil list the options available
> +
> +-----------------------
> +./support/script/scanpypi -h
> +-----------------------
> +
> [[python-package-tutorial]]
>
> ==== +python-package+ tutorial
> diff --git a/support/scripts/scanpypi b/support/scripts/scanpypi
> new file mode 100755
> index 0000000..3e51bae
> --- /dev/null
> +++ b/support/scripts/scanpypi
> @@ -0,0 +1,653 @@
> +#!/usr/bin/python2
> +"""
> +Utility for building buildroot packages for existing pypi packages
> +
> +Any package built by scanpypi should be manually checked for
> +errors.
> +"""
> +from __future__ import print_function
> +import argparse
> +import json
> +import urllib2
> +import sys
> +import os
> +import shutil
> +import StringIO
> +import tarfile
> +import zipfile
> +import errno
> +import hashlib
> +import re
> +import textwrap
> +import tempfile
> +import imp
> +from functools import wraps
> +
> +
> +def setup_decorator(func, method):
> + """
> + Decorator for distutils.core.setup and setuptools.setup.
> + Puts the arguments with which setup is called as a dict
> + Add key 'method' which should be either 'setuptools' or 'distutils'.
> +
> + Keyword arguments:
> + func -- either setuptools.setup or distutils.core.setup
> + method -- either 'setuptools' or 'distutils'
> + """
> +
> + @wraps(func)
> + def closure(*args, **kwargs):
> + # Any python packages calls its setup function to be installed.
> + # Argument 'name' of this setup function is the package's name
> + BuildrootPackage.setup_args[kwargs['name']] = kwargs
> + BuildrootPackage.setup_args[kwargs['name']]['method'] = method
> + return closure
> +
> +
> +# monkey patch
> +import setuptools
> +setuptools.setup = setup_decorator(setuptools.setup, 'setuptools')
> +import distutils
> +distutils.core.setup = setup_decorator(setuptools.setup, 'distutils')
> +
> +
> +def find_file_upper_case(filenames, path='./'):
> + """
> + List generator:
> + Recursively find files that matches one of the specified filenames.
> + Returns a relative path starting with path argument.
> +
> + Keyword arguments:
> + filenames -- List of filenames to be found
> + path -- Path to the directory to search
> + """
> + for root, dirs, files in os.walk(path):
> + for file in files:
> + if file.upper() in filenames:
> + yield (os.path.join(root, file))
> +
> +
> +def pkg_buildroot_name(pkg_name):
> + """
> + Returns the buildroot package name for the PyPI package pkg_name.
> + Remove all non alphanumeric characters except -
> + Also lowers the name and adds 'python-' suffix
> +
> + Keyword arguments:
> + pkg_name -- String to rename
> + """
> + name = re.sub('[^\w-]', '', pkg_name.lower())
> + prefix = 'python-'
> + pattern = re.compile('^(?!' + prefix + ')(.+?)$')
> + name = pattern.sub(r'python-\1', name)
> + return name
> +
> +
> +class DownloadFailed(Exception):
> + pass
> +
> +
> +class BuildrootPackage():
> + """
> + This class's methods are not meant to be used individually please use those
> + in the correct order:
> + __init__
> +
> + download_package
> +
> + extract_package
> +
> + load_module
> +
> + get_requirements
> +
> + create_package_mk
> +
> + create_hash_file
> +
> + create_config_in
> + """
> + setup_args = {}
> +
> + def __init__(self, real_name, pkg_folder):
> + self.real_name = real_name
> + self.buildroot_name = pkg_buildroot_name(self.real_name)
> + self.pkg_dir = os.path.join(pkg_folder, self.buildroot_name)
> + self.mk_name = self.buildroot_name.upper().replace('-', '_')
> + self.as_string = None
> + self.md5_sum = None
> + self.metadata = None
> + self.metadata_name = None
> + self.metadata_url = None
> + self.pkg_req = None
> + self.setup_metadata = None
> + self.tmp_extract = None
> + self.used_url = None
> + self.filename = None
> + self.url = None
> + self.version = None
> +
> + def fetch_package_info(self):
> + """
> + Fetch a package's metadata from the python package index
> + """
> + self.metadata_url = 'https://pypi.python.org/pypi/{pkg}/json'.format(
> + pkg=self.real_name)
> + try:
> + pkg_json = urllib2.urlopen(self.metadata_url).read().decode()
> + except urllib2.HTTPError as error:
> + print('ERROR:', error.getcode(), error.msg, file=sys.stderr)
> + print('ERROR: Could not find package {pkg}.\n'
> + 'Check syntax inside the python package index:\n'
> + 'https://pypi.python.org/pypi/ '
> + .format(pkg=self.real_name))
> + raise
> + except urllib2.URLError:
> + print('ERROR: Could not find package {pkg}.\n'
> + 'Check syntax inside the python package index:\n'
> + 'https://pypi.python.org/pypi/ '
> + .format(pkg=self.real_name))
> + raise
> + self.metadata = json.loads(pkg_json)
> + self.version = self.metadata['info']['version']
> + self.metadata_name = self.metadata['info']['name']
> +
> + def download_package(self):
> + """
> + Download a package using metadata from pypi
> + """
> + try:
> + self.metadata['urls'][0]['filename']
> + except IndexError:
> + print(
> + 'Non-conventional package, ',
> + 'please check carefully after creation')
> + self.metadata['urls'] = [{
> + 'packagetype': 'sdist',
> + 'url': self.metadata['info']['download_url'],
> + 'md5_digest': None}]
> + # In this case, we can't get the name of the downloaded file
> + # from the pypi api, so we need to find it, this should work
> + urlpath = urllib2.urlparse.urlparse(
> + self.metadata['info']['download_url']).path
> + # urlparse().path give something like
> + # /path/to/file-version.tar.gz
> + # We use basename to remove /path/to
> + self.metadata['urls'][0]['filename'] = os.path.basename(urlpath)
> + for download_url in self.metadata['urls']:
> + if 'bdist' in download_url['packagetype']:
> + continue
> + try:
> + print('Downloading package {pkg} from {url}...'.format(
> + pkg=self.real_name, url=download_url['url']))
> + download = urllib2.urlopen(download_url['url'])
> + except urllib2.HTTPError as http_error:
> + download = http_error
> + else:
> + self.used_url = download_url
> + self.as_string = download.read()
> + if not download_url['md5_digest']:
> + break
> + self.md5_sum = hashlib.md5(self.as_string).hexdigest()
> + if self.md5_sum == download_url['md5_digest']:
> + break
> + else:
> + if download.__class__ == urllib2.HTTPError:
> + raise download
> + raise DownloadFailed('Failed to downloas package {pkg}'
> + .format(pkg=self.real_name))
> + self.filename = self.used_url['filename']
> + self.url = self.used_url['url']
> +
> + def extract_package(self, tmp_path):
> + """
> + Extract the package contents into a directrory
> +
> + Keyword arguments:
> + tmp_path -- directory where you want the package to be extracted
> + """
> + as_file = StringIO.StringIO(self.as_string)
> + if self.filename[-3:] == 'zip':
> + with zipfile.open(fileobj=as_file) as as_zipfile:
> + tmp_pkg = os.path.join(tmp_path, self.buildroot_name)
> + try:
> + os.makedirs(tmp_pkg)
> + except OSError as exception:
> + if exception.errno != errno.EEXIST:
> + print("ERROR: ", exception.message, file=sys.stderr)
> + return None, None
> + print('WARNING:', exception.message, file=sys.stderr)
> + print('Removing {pkg}...'.format(pkg=tmp_pkg))
> + shutil.rmtree(tmp_pkg)
> + os.makedirs(tmp_pkg)
> + as_zipfile.extractall(tmp_pkg)
> + else:
> + with tarfile.open(fileobj=as_file) as as_tarfile:
> + tmp_pkg = os.path.join(tmp_path, self.buildroot_name)
> + try:
> + os.makedirs(tmp_pkg)
> + except OSError as exception:
> + if exception.errno != errno.EEXIST:
> + print("ERROR: ", exception.message, file=sys.stderr)
> + return None, None
> + print('WARNING:', exception.message, file=sys.stderr)
> + print('Removing {pkg}...'.format(pkg=tmp_pkg))
> + shutil.rmtree(tmp_pkg)
> + os.makedirs(tmp_pkg)
> + as_tarfile.extractall(tmp_pkg)
> +
> + tmp_extract = '{folder}/{name}-{version}'
> + self.tmp_extract = tmp_extract.format(
> + folder=tmp_pkg,
> + name=self.metadata_name,
> + version=self.version)
> +
> + def load_setup(self):
> + """
> + Loads the corresponding setup and store its metadata
> + """
> + current_dir = os.getcwd()
> + os.chdir(self.tmp_extract)
> + sys.path.append(self.tmp_extract)
> + s_file, s_path, s_desc = imp.find_module('setup', [self.tmp_extract])
> + setup = imp.load_module('setup', s_file, s_path, s_desc)
> + try:
> + self.setup_metadata = self.setup_args[self.metadata_name]
> + except KeyError:
> + # This means setup was not called which most likely mean that it is
> + # called through the if __name__ == '__main__' directive.
> + # In this case, we can only pray that it is called through a
> + # function called main() in setup.py.
> + setup.main([]) # Will raise AttributeError if not found
> + self.setup_metadata = self.setup_args[self.metadata_name]
> + # Here we must remove the module the hard way.
> + # We must do this because of a very sepcific case: if a package calls
> + # setup from the __main__ but does not come with a 'main()' function,
> + # for some reason setup.main([]) will successfully call the main
> + # function of a previous package...
> + sys.modules.pop('setup',None)
> + del setup
> + os.chdir(current_dir)
> + sys.path.remove(self.tmp_extract)
> +
> + def get_requirements(self, pkg_folder):
> + """
> + Retrieve dependencies from the metadata found in the setup.py script of
> + a pypi package.
> +
> + Keyword Arguments:
> + pkg_folder -- location of the already created packages
> + """
> + if 'install_requires' not in self.setup_metadata:
> + self.pkg_req = None
> + return set()
> + self.pkg_req = self.setup_metadata['install_requires']
> + self.pkg_req = [re.sub('([-.\w]+).*', r'\1', req)
> + for req in self.pkg_req]
> + req_not_found = self.pkg_req
> + self.pkg_req = map(pkg_buildroot_name, self.pkg_req)
> + pkg_tuples = zip(req_not_found, self.pkg_req)
> + # pkg_tuples is a list of tuples that looks like
> + # ('werkzeug','python-werkzeug') because I need both when checking if
> + # dependencies already exist or are already in the download list
> + req_not_found = set(
> + pkg[0] for pkg in pkg_tuples
> + if not os.path.isdir(pkg[1])
> + )
> + return req_not_found
> +
> + def __create_mk_header(self):
> + """
> + Create the header of the <package_name>.mk file
> + """
> + header = ['#' * 80 + '\n']
> + header.append('#\n')
> + header.append('# {name}\n'.format(name=self.buildroot_name))
> + header.append('#\n')
> + header.append('#' * 80 + '\n')
> + header.append('\n')
> + return header
> +
> + def __create_mk_download_info(self):
> + """
> + Create the lines refering to the download information of the
> + <package_name>.mk file
> + """
> + lines = []
> + version_line = '{name}_VERSION = {version}\n'.format(
> + name=self.mk_name,
> + version=self.version)
> + lines.append(version_line)
> +
> + targz = self.filename.replace(
> + self.version,
> + '$({name}_VERSION)'.format(name=self.mk_name))
> + targz_line = '{name}_SOURCE = {filename}\n'.format(
> + name=self.mk_name,
> + filename=targz)
> + lines.append(targz_line)
> +
> + if self.filename not in self.url:
> + # Sometimes the filename is in the url, sometimes it's not
> + site_url = self.url
> + else:
> + site_url = self.url[:self.url.find(self.filename)]
> + site_line = '{name}_SITE = {url}'.format(name=self.mk_name,
> + url=site_url)
> + site_line = site_line.rstrip('/') + '\n'
> + lines.append(site_line)
> + return lines
> +
> + def __create_mk_setup(self):
> + """
> + Create the line refering to the setup method of the package of the
> + <package_name>.mk file
> +
> + There are two things you can use to make an installer
> + for a python package: distutils or setuptools
> + distutils comes with python but does not support dependencies.
> + distutils is mostly still there for backward support.
> + setuptools is what smart people use,
> + but it is not shipped with python :(
> + """
> + lines = []
> + setup_type_line = '{name}_SETUP_TYPE = {method}\n'.format(
> + name=self.mk_name,
> + method=self.setup_metadata['method'])
> + lines.append(setup_type_line)
> + return lines
> +
> + def __create_mk_license(self):
> + """
> + Create the lines referring to the package's license informations of the
> + <package_name>.mk file
> +
> + The license is found using the metadata from pypi.
> + In the metadata, the license can be found either with standard names in
> + the classifiers part or with naming from the packager in the "License"
> + part.
> +
> + From the classifiers, the license is "translated" according to
> + buildroot standards if need be (i.e. from Apache Software License to
> + Apache-2.0).
> +
> + From the License part, we cannot guess what formatting the packager
> + used. Hence, it is likely to be incorrect. (i.e. Apache License 2.0
> + instead of Apache-2.0).
> +
> + The license's files are found by searching the package for files named
> + license or license.txt (case insensitive).
> + If more than one license file is found, the user is asked to select
> + which ones he wants to use.
> + """
> + license_dict = {
> + 'Apache Software License': 'Apache-2.0',
> + 'BSD License': 'BSD',
> + 'European Union Public Licence 1.0': 'EUPLv1.0',
> + 'European Union Public Licence 1.1': 'EUPLv1.1',
> + "GNU General Public License": "GPL",
> + "GNU General Public License v2": "GPLv2",
> + "GNU General Public License v2 or later": "GPLv2+",
> + "GNU General Public License v3": "GPLv3",
> + "GNU General Public License v3 or later": "GPLv3+",
> + "GNU Lesser General Public License v2": "LGPLv2.1",
> + "GNU Lesser General Public License v2 or later": "LGPLv2.1+",
> + "GNU Lesser General Public License v3": "LGPLv3",
> + "GNU Lesser General Public License v3 or later": "LGPLv3+",
> + "GNU Library or Lesser General Public License": "LGPLv2",
> + "ISC License": "ISC",
> + "MIT License": "MIT",
> + "Mozilla Public License 1.0": "MPL-1.0",
> + "Mozilla Public License 1.1": "MPL-1.1",
> + "Mozilla Public License 2.0": "MPL-2.0",
> + "Zope Public License": "ZPL"
> + }
> + regexp = re.compile('^License :* *.* *:+ (.*)( \(.*\))?$')
> + classifiers_licenses = [regexp.sub(r"\1", lic)
> + for lic in self.metadata['info']['classifiers']
> + if regexp.match(lic)]
> + licenses = map(lambda x: license_dict[x] if x in license_dict else x,
> + classifiers_licenses)
> + lines = []
> + if not len(licenses):
> + print('WARNING: License has been set to "{license}". It is most'
> + ' likely wrong, please change it if need be'.format(
> + license=', '.join(licenses)))
> + licenses = [self.metadata['info']['license']]
> + license_line = '{name}_LICENSE = {license}\n'.format(
> + name=self.mk_name,
> + license=', '.join(licenses))
> + lines.append(license_line)
> +
> + filenames = ['LICENSE', 'LICENSE.TXT', 'COPYING', 'COPYING.TXT']
> + license_files = list(find_file_upper_case(filenames, self.tmp_extract))
> + license_files = [license.replace(self.tmp_extract, '')[1:]
> + for license in license_files]
> + if len(license_files) > 0:
> + if len(license_files) > 1:
> + print('More than one file found for license:',
> + ', '.join(license_files))
> + license_files = [filename
> + for index, filename in enumerate(license_files)]
> + license_file_line = ('{name}_LICENSE_FILES ='
> + ' {files}\n'.format(
> + name=self.mk_name,
> + files=' '.join(license_files)))
> + lines.append(license_file_line)
> + else:
> + print('WARNING: No license file found,'
> + ' please specify it manually afterwards')
> + license_file_line = '# No license file found\n'
> +
> + return lines
> +
> + def __create_mk_requirements(self):
> + """
> + Create the lines referring to the dependencies of the of the
> + <package_name>.mk file
> +
> + Keyword Arguments:
> + pkg_name -- name of the package
> + pkg_req -- dependencies of the package
> + """
> + lines = []
> + dependencies_line = ('{name}_DEPENDENCIES ='
> + ' {reqs}\n'.format(
> + name=self.mk_name,
> + reqs=' '.join(self.pkg_req)))
> + lines.append(dependencies_line)
> + return lines
> +
> + def create_package_mk(self):
> + """
> + Create the lines corresponding to the <package_name>.mk file
> + """
> + pkg_mk = '{name}.mk'.format(name=self.buildroot_name)
> + path_to_mk = os.path.join(self.pkg_dir, pkg_mk)
> + print('Creating {file}...'.format(file=path_to_mk))
> + lines = self.__create_mk_header()
> + lines += self.__create_mk_download_info()
> + lines += self.__create_mk_setup()
> + lines += self.__create_mk_license()
> + if self.pkg_req:
> + lines += self.__create_mk_requirements()
> +
> + lines.append('\n')
> + lines.append('$(eval $(python-package))')
> + lines.append('\n')
> + with open(path_to_mk, 'w') as mk_file:
> + mk_file.writelines(lines)
> +
> + def create_hash_file(self):
> + """
> + Create the lines corresponding to the <package_name>.hash files
> + """
> + pkg_hash = '{name}.hash'.format(name=self.buildroot_name)
> + path_to_hash = os.path.join(self.pkg_dir, pkg_hash)
> + print('Creating {filename}...'.format(filename=path_to_hash))
> + lines = []
> + if self.used_url['md5_digest']:
> + md5_comment = '# md5 from {url}\n'.format(url=self.metadata_url)
> + lines.append(md5_comment)
> + hash_line = '{method}\t{digest} {filename}\n'.format(
> + method='md5',
> + digest=self.used_url['md5_digest'],
> + filename=self.filename)
> + lines.append(hash_line)
> + sha256_comment = '# sha256 calculated by scanpypi\n'
> + lines.append(sha256_comment)
> + digest = hashlib.sha256(self.as_string).hexdigest()
> + hash_line = '{method}\t{digest} {filename}\n'.format(
> + method='sha256',
> + digest=digest,
> + filename=self.filename)
> + lines.append(hash_line)
> +
> + with open(path_to_hash, 'w') as hash_file:
> + hash_file.writelines(lines)
> +
> + def create_config_in(self):
> + """
> + Creates the Config.in file of a package
> + """
> + path_to_config = os.path.join(self.pkg_dir, 'Config.in')
> + print('Creating {file}...'.format(file=path_to_config))
> + lines = []
> + config_line = 'config BR2_PACKAGE_{name}\n'.format(
> + name=self.mk_name)
> + lines.append(config_line)
> +
> + bool_line = '\tbool "{name}"\n'.format(name=self.buildroot_name)
> + lines.append(bool_line)
> + if self.pkg_req:
> + for dep in self.pkg_req:
> + dep_line = '\tselect BR2_PACKAGE_{req}\n'.format(
> + req=dep.upper().replace('-', '_'))
> + lines.append(dep_line)
> +
> + lines.append('\thelp\n')
> +
> + help_lines = textwrap.wrap(self.metadata['info']['summary'],
> + initial_indent='\t ',
> + subsequent_indent='\t ')
> + # \t + two spaces is 3 char long
> + help_lines.append('')
> + help_lines.append('\t ' + self.metadata['info']['home_page'])
> + help_lines = map(lambda x: x + '\n', help_lines)
> + lines += help_lines
> +
> + with open(path_to_config, 'w') as config_file:
> + config_file.writelines(lines)
> +
> +
> +def main():
> + # Building the parser
> + parser = argparse.ArgumentParser(
> + description="Creates buildroot packages from the metadata of "
> + "an existing PyPI packages and include it "
> + "in menuconfig")
> + parser.add_argument("packages",
> + help="list of packages to be created",
> + nargs='+')
> + parser.add_argument("-o", "--output",
> + help="""
> + Output directory for packages.
> + Default is ./package
> + """,
> + default='./package')
> +
> + args = parser.parse_args()
> + packages = list(set(args.packages))
> +
> + # tmp_path is where we'll extract the files later
> + tmp_prefix = 'scanpypi-'
> + pkg_folder = args.output
> + tmp_path = tempfile.mkdtemp(prefix=tmp_prefix)
> + try:
> + for real_pkg_name in packages:
> + package = BuildrootPackage(real_pkg_name, pkg_folder)
> + print('buildroot package name for {}:'.format(package.real_name),
> + package.buildroot_name)
> + # First we download the package
> + # Most of the info we need can only be found inside the package
> + print('Package:', package.buildroot_name)
> + print('Fetching package', package.real_name)
> + try:
> + package.fetch_package_info()
> + except (urllib2.URLError, urllib2.HTTPError):
> + continue
> + if package.metadata_name.lower() == 'setuptools':
> + # setuptools imports itself, that does not work very well
> + # with the monkey path at the begining
> + print('Error: setuptools cannot be built using scanPyPI')
> + continue
> +
> + try:
> + package.download_package()
> + except urllib2.HTTPError as error:
> + print('Error: {code} {reason}'.format(code=error.code,
> + reason=error.reason))
> + print('Error downloading package :', package.buildroot_name)
> + print()
> + continue
> +
> + # extract the tarball
> + try:
> + package.extract_package(tmp_path)
> + except (tarfile.ReadError, zipfile.BadZipfile):
> + print('Error extracting package {}'.format(package.real_name))
> + print()
> + continue
> +
> + # Loading the package install info from the package
> + try:
> + package.load_setup()
> + except ImportError as err:
> + if 'buildutils' in err.message:
> + print('This package needs buildutils')
> + else:
> + raise
> + continue
> + except AttributeError:
> + print('Error: Could not install package {pkg}'.format(
> + pkg=package.real_name))
> + continue
> +
> + # Package requirement are an argument of the setup function
> + req_not_found = package.get_requirements(pkg_folder)
> + req_not_found = req_not_found.difference(packages)
> +
> + packages += req_not_found
> + if req_not_found:
> + print('Added packages \'{pkgs}\' as dependencies of {pkg}'
> + .format(pkgs=", ".join(req_not_found),
> + pkg=package.buildroot_name))
> + print('Checking if package {name} already exists...'.format(
> + name=package.pkg_dir))
> + try:
> + os.makedirs(package.pkg_dir)
> + except OSError as exception:
> + if exception.errno != errno.EEXIST:
> + print("ERROR: ", exception.message, file=sys.stderr)
> + continue
> + print('Error: Package {name} already exists'
> + .format(name=package.pkg_dir))
> + del_pkg = raw_input(
> + 'Do you want to delete existing package ? [y/N]')
> + if del_pkg.lower() == 'y':
> + shutil.rmtree(package.pkg_dir)
> + os.makedirs(package.pkg_dir)
> + else:
> + continue
> + package.create_package_mk()
> +
> + package.create_hash_file()
> +
> + package.create_config_in()
> + print()
> + # printing an empty line for visual confort
> + finally:
> + shutil.rmtree(tmp_path)
> +
> +if __name__ == "__main__":
> + main()
> --
> 2.4.6
next prev parent reply other threads:[~2015-08-31 15:58 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-28 13:15 [Buildroot] [PATCH 1/2] scanpypi: new utility Denis THULIN
2015-07-28 13:15 ` [Buildroot] [PATCH 2/2] python-robotframework: New package Denis THULIN
2015-08-31 15:58 ` Denis Thulin [this message]
2016-01-10 10:59 ` [Buildroot] [PATCH 1/2] scanpypi: new utility Yann E. MORIN
2016-01-10 15:36 ` Arnout Vandecappelle
2016-01-13 15:23 ` Thomas Petazzoni
2016-01-14 8:32 ` Yegor Yefremov
2016-01-27 13:30 ` Yegor Yefremov
2016-02-02 18:02 ` Eelco Chaudron
2016-02-02 19:54 ` Eelco Chaudron
2016-03-01 1:44 ` Carlos Santos
-- strict thread matches above, loose matches on Subject: below --
2015-07-09 13:31 [Buildroot] [PATCH 0/2] python-package-generator Denis THULIN
2015-07-09 13:31 ` [Buildroot] [PATCH 1/2] scanpypi: new utility Denis THULIN
2015-07-11 12:56 ` Arnout Vandecappelle
2015-07-15 14:08 ` Denis Thulin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2127757025.300457.1441036698136.JavaMail.zimbra@openwide.fr \
--to=denis.thulin@openwide.fr \
--cc=buildroot@busybox.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox