def convert(self, pip_install_arguments): """ Convert one or more Python packages to Debian packages. :param pip_install_arguments: The command line arguments to the ``pip install`` command. :returns: A tuple with two lists: 1. A list of strings containing the pathname(s) of the generated Debian package package archive(s). 2. A list of strings containing the Debian package relationship(s) required to depend on the converted package(s). :raises: :exc:`~deb_pkg_tools.checks.DuplicateFilesFound` if two converted package archives contain the same files (certainly not what you want within a set of dependencies). Here's an example of what's returned: >>> from py2deb.converter import PackageConverter >>> converter = PackageConverter() >>> archives, relationships = converter.convert(['py2deb']) >>> print(archives) ['/tmp/python-py2deb_0.18_all.deb'] >>> print(relationships) ['python-py2deb (=0.18)'] """ try: generated_archives = [] dependencies_to_report = [] # Download and unpack the requirement set and store the complete # set as an instance variable because transform_version() will need # it later on. self.packages_to_convert = list(self.get_source_distributions(pip_install_arguments)) # Convert packages that haven't been converted already. for package in self.packages_to_convert: # If the requirement is a 'direct' (non-transitive) requirement # it means the caller explicitly asked for this package to be # converted, so we add it to the list of converted dependencies # that we report to the caller once we've finished converting. if package.requirement.is_direct: dependencies_to_report.append('%s (= %s)' % (package.debian_name, package.debian_version)) if package.existing_archive: # If the same version of this package was converted in a # previous run we can save a lot of time by skipping it. logger.info("Package %s (%s) already converted: %s", package.python_name, package.python_version, package.existing_archive.filename) generated_archives.append(package.existing_archive) else: archive = package.convert() if not os.path.samefile(os.path.dirname(archive), self.repository.directory): shutil.move(archive, self.repository.directory) archive = os.path.join(self.repository.directory, os.path.basename(archive)) generated_archives.append(archive) # Use deb-pkg-tools to sanity check the generated package archives # for duplicate files. This should never occur but unfortunately # can happen because Python's packaging infrastructure is a lot # more `forgiving' in the sense of blindly overwriting files # installed by other packages ;-). if len(generated_archives) > 1: check_duplicate_files(generated_archives, cache=get_default_cache()) # Let the caller know which archives were generated (whether # previously or now) and how to depend on the converted packages. return generated_archives, sorted(dependencies_to_report) finally: # Always clean up temporary directories created by pip and pip-accel. self.pip_accel.cleanup_temporary_directories()
def main(): """ Command line interface for the ``deb-pkg-tools`` program. """ # Configure logging output. coloredlogs.install() # Enable printing of Unicode strings even when our standard output and/or # standard error streams are not connected to a terminal. This is required # on Python 2.x but will break on Python 3.x which explains the ugly # version check. See also: http://stackoverflow.com/q/4374455/788200. if sys.version_info[0] == 2: sys.stdout = codecs.getwriter(OUTPUT_ENCODING)(sys.stdout) sys.stderr = codecs.getwriter(OUTPUT_ENCODING)(sys.stderr) # Command line option defaults. prompt = True actions = [] control_file = None control_fields = {} # Initialize the package cache. cache = get_default_cache() # Parse the command line options. try: options, arguments = getopt.getopt( sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [ 'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=', 'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=', 'yes', 'verbose', 'help' ]) for option, value in options: if option in ('-i', '--inspect'): actions.append( functools.partial(show_package_metadata, archive=value)) elif option in ('-c', '--collect'): actions.append( functools.partial(collect_packages, archives=arguments, directory=check_directory(value), prompt=prompt, cache=cache)) arguments = [] elif option in ('-C', '--check'): actions.append( functools.partial(check_package, archive=value, cache=cache)) elif option in ('-p', '--patch'): control_file = os.path.abspath(value) assert os.path.isfile( control_file), "Control file does not exist!" elif option in ('-s', '--set'): name, _, value = value.partition(':') control_fields[name] = value.strip() elif option in ('-b', '--build'): actions.append( functools.partial(build_package, check_directory(value))) elif option in ('-u', '--update-repo'): actions.append( functools.partial(update_repository, directory=check_directory(value), cache=cache)) elif option in ('-a', '--activate-repo'): actions.append( functools.partial(activate_repository, check_directory(value))) elif option in ('-d', '--deactivate-repo'): actions.append( functools.partial(deactivate_repository, check_directory(value))) elif option in ('-w', '--with-repo'): actions.append( functools.partial(with_repository_wrapper, directory=check_directory(value), command=arguments, cache=cache)) elif option in ('-y', '--yes'): prompt = False elif option in ('-v', '--verbose'): coloredlogs.increase_verbosity() elif option in ('-h', '--help'): usage() return if control_file: assert control_fields, "Please specify one or more control file fields to patch!" actions.append( functools.partial(patch_control_file, control_file, control_fields)) except Exception as e: logger.error(e) print usage() sys.exit(1) # Execute the selected action. try: if actions: for action in actions: action() cache.collect_garbage() else: usage() except Exception as e: if isinstance(e, KeyboardInterrupt): logger.error("Interrupted by Control-C, aborting!") else: logger.exception("An error occurred!") sys.exit(1)
def convert(self, pip_install_arguments): """ Convert one or more Python packages to Debian packages. :param pip_install_arguments: The command line arguments to the ``pip install`` command. :returns: A tuple with two lists: 1. A list of strings containing the pathname(s) of the generated Debian package package archive(s). 2. A list of strings containing the Debian package relationship(s) required to depend on the converted package(s). :raises: :py:exc:`~deb_pkg_tools.checks.DuplicateFilesFound` if two converted package archives contain the same files (certainly not what you want within a set of dependencies). Here's an example of what's returned: >>> from py2deb import PackageConverter >>> converter = PackageConverter() >>> archives, relationships = converter.convert(['py2deb']) >>> print(archives) ['/tmp/python-py2deb_0.18_all.deb'] >>> print(relationships) ['python-py2deb (=0.18)'] """ try: generated_archives = [] dependencies_to_report = [] # Download and unpack the requirement set and store the complete # set as an instance variable because transform_version() will need # it later on. self.packages_to_convert = list(self.get_source_distributions(pip_install_arguments)) # Convert packages that haven't been converted already. for package in self.packages_to_convert: # If the requirement is a 'direct' (non-transitive) requirement # it means the caller explicitly asked for this package to be # converted, so we add it to the list of converted dependencies # that we report to the caller once we've finished converting. if package.requirement.is_direct: dependencies_to_report.append('%s (= %s)' % (package.debian_name, package.debian_version)) if package.existing_archive: # If the same version of this package was converted in a # previous run we can save a lot of time by skipping it. logger.info("Package %s (%s) already converted: %s", package.python_name, package.python_version, package.existing_archive.filename) generated_archives.append(package.existing_archive) else: archive = package.convert() if not os.path.samefile(os.path.dirname(archive), self.repository.directory): shutil.move(archive, self.repository.directory) archive = os.path.join(self.repository.directory, os.path.basename(archive)) generated_archives.append(archive) # Use deb-pkg-tools to sanity check the generated package archives # for duplicate files. This should never occur but unfortunately # can happen because Python's packaging infrastructure is a lot # more `forgiving' in the sense of blindly overwriting files # installed by other packages ;-). if len(generated_archives) > 1: check_duplicate_files(generated_archives, cache=get_default_cache()) # Let the caller know which archives were generated (whether # previously or now) and how to depend on the converted packages. return generated_archives, sorted(dependencies_to_report) finally: # Always clean up temporary directories created by pip and pip-accel. self.pip_accel.cleanup_temporary_directories()
def main(): """ Command line interface for the ``deb-pkg-tools`` program. """ # Configure logging output. coloredlogs.install() # Enable printing of Unicode strings even when our standard output and/or # standard error streams are not connected to a terminal. This is required # on Python 2.x but will break on Python 3.x which explains the ugly # version check. See also: http://stackoverflow.com/q/4374455/788200. if sys.version_info[0] == 2: sys.stdout = codecs.getwriter(OUTPUT_ENCODING)(sys.stdout) sys.stderr = codecs.getwriter(OUTPUT_ENCODING)(sys.stderr) # Command line option defaults. prompt = True actions = [] control_file = None control_fields = {} # Initialize the package cache. cache = get_default_cache() # Parse the command line options. try: options, arguments = getopt.getopt(sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [ 'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=', 'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=', 'yes', 'verbose', 'help' ]) for option, value in options: if option in ('-i', '--inspect'): actions.append(functools.partial(show_package_metadata, archive=value)) elif option in ('-c', '--collect'): actions.append(functools.partial(collect_packages, archives=arguments, directory=check_directory(value), prompt=prompt, cache=cache)) arguments = [] elif option in ('-C', '--check'): actions.append(functools.partial(check_package, archive=value, cache=cache)) elif option in ('-p', '--patch'): control_file = os.path.abspath(value) assert os.path.isfile(control_file), "Control file does not exist!" elif option in ('-s', '--set'): name, _, value = value.partition(':') control_fields[name] = value.strip() elif option in ('-b', '--build'): actions.append(functools.partial(build_package, check_directory(value))) elif option in ('-u', '--update-repo'): actions.append(functools.partial(update_repository, directory=check_directory(value), cache=cache)) elif option in ('-a', '--activate-repo'): actions.append(functools.partial(activate_repository, check_directory(value))) elif option in ('-d', '--deactivate-repo'): actions.append(functools.partial(deactivate_repository, check_directory(value))) elif option in ('-w', '--with-repo'): actions.append(functools.partial(with_repository_wrapper, directory=check_directory(value), command=arguments, cache=cache)) elif option in ('-y', '--yes'): prompt = False elif option in ('-v', '--verbose'): coloredlogs.increase_verbosity() elif option in ('-h', '--help'): usage() return if control_file: assert control_fields, "Please specify one or more control file fields to patch!" actions.append(functools.partial(patch_control_file, control_file, control_fields)) except Exception as e: logger.error(e) print usage() sys.exit(1) # Execute the selected action. try: if actions: for action in actions: action() cache.collect_garbage() else: usage() except Exception as e: if isinstance(e, KeyboardInterrupt): logger.error("Interrupted by Control-C, aborting!") else: logger.exception("An error occurred!") sys.exit(1)
def main(): """Command line interface for the ``deb-pkg-tools`` program.""" # Configure logging output. coloredlogs.install() # Command line option defaults. prompt = True actions = [] control_file = None control_fields = {} directory = None # Initialize the package cache. cache = get_default_cache() # Parse the command line options. try: options, arguments = getopt.getopt(sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [ 'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=', 'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=', 'gc', 'garbage-collect', 'yes', 'verbose', 'help' ]) for option, value in options: if option in ('-i', '--inspect'): actions.append(functools.partial(show_package_metadata, archive=value)) elif option in ('-c', '--collect'): directory = check_directory(value) elif option in ('-C', '--check'): actions.append(functools.partial(check_package, archive=value, cache=cache)) elif option in ('-p', '--patch'): control_file = os.path.abspath(value) assert os.path.isfile(control_file), "Control file does not exist!" elif option in ('-s', '--set'): name, _, value = value.partition(':') control_fields[name] = value.strip() elif option in ('-b', '--build'): actions.append(functools.partial( build_package, check_directory(value), repository=tempfile.gettempdir(), )) elif option in ('-u', '--update-repo'): actions.append(functools.partial(update_repository, directory=check_directory(value), cache=cache)) elif option in ('-a', '--activate-repo'): actions.append(functools.partial(activate_repository, check_directory(value))) elif option in ('-d', '--deactivate-repo'): actions.append(functools.partial(deactivate_repository, check_directory(value))) elif option in ('-w', '--with-repo'): actions.append(functools.partial(with_repository_wrapper, directory=check_directory(value), command=arguments, cache=cache)) elif option in ('--gc', '--garbage-collect'): actions.append(functools.partial(cache.collect_garbage, force=True)) elif option in ('-y', '--yes'): prompt = False elif option in ('-v', '--verbose'): coloredlogs.increase_verbosity() elif option in ('-h', '--help'): usage(__doc__) return # We delay the patch_control_file() and collect_packages() partials # until all command line options have been parsed, to ensure that the # order of the command line options doesn't matter. if control_file: if not control_fields: raise Exception("Please specify one or more control file fields to patch!") actions.append(functools.partial(patch_control_file, control_file, control_fields)) if directory: actions.append(functools.partial(collect_packages, archives=arguments, directory=directory, prompt=prompt, cache=cache)) except Exception as e: warning("Error: %s", e) sys.exit(1) # Execute the selected action. try: if actions: for action in actions: action() cache.collect_garbage() else: usage(__doc__) except Exception as e: logger.exception("An error occurred!") sys.exit(1)
def main(): """Command line interface for the ``deb-pkg-tools`` program.""" # Configure logging output. coloredlogs.install() # Command line option defaults. prompt = True actions = [] control_file = None control_fields = {} directory = None # Initialize the package cache. cache = get_default_cache() # Parse the command line options. try: options, arguments = getopt.getopt( sys.argv[1:], 'i:c:C:p:s:b:u:a:d:w:yvh', [ 'inspect=', 'collect=', 'check=', 'patch=', 'set=', 'build=', 'update-repo=', 'activate-repo=', 'deactivate-repo=', 'with-repo=', 'gc', 'garbage-collect', 'yes', 'verbose', 'help' ]) for option, value in options: if option in ('-i', '--inspect'): actions.append( functools.partial(show_package_metadata, archive=value)) elif option in ('-c', '--collect'): directory = check_directory(value) elif option in ('-C', '--check'): actions.append( functools.partial(check_package, archive=value, cache=cache)) elif option in ('-p', '--patch'): control_file = os.path.abspath(value) assert os.path.isfile( control_file), "Control file does not exist!" elif option in ('-s', '--set'): name, _, value = value.partition(':') control_fields[name] = value.strip() elif option in ('-b', '--build'): actions.append( functools.partial( build_package, check_directory(value), repository=tempfile.gettempdir(), )) elif option in ('-u', '--update-repo'): actions.append( functools.partial(update_repository, directory=check_directory(value), cache=cache)) elif option in ('-a', '--activate-repo'): actions.append( functools.partial(activate_repository, check_directory(value))) elif option in ('-d', '--deactivate-repo'): actions.append( functools.partial(deactivate_repository, check_directory(value))) elif option in ('-w', '--with-repo'): actions.append( functools.partial(with_repository_wrapper, directory=check_directory(value), command=arguments, cache=cache)) elif option in ('--gc', '--garbage-collect'): actions.append( functools.partial(cache.collect_garbage, force=True)) elif option in ('-y', '--yes'): prompt = False elif option in ('-v', '--verbose'): coloredlogs.increase_verbosity() elif option in ('-h', '--help'): usage(__doc__) return # We delay the patch_control_file() and collect_packages() partials # until all command line options have been parsed, to ensure that the # order of the command line options doesn't matter. if control_file: if not control_fields: raise Exception( "Please specify one or more control file fields to patch!") actions.append( functools.partial(patch_control_file, control_file, control_fields)) if directory: actions.append( functools.partial(collect_packages, archives=arguments, directory=directory, prompt=prompt, cache=cache)) except Exception as e: warning("Error: %s", e) sys.exit(1) # Execute the selected action. try: if actions: for action in actions: action() cache.collect_garbage() else: usage(__doc__) except Exception: logger.exception("An error occurred! Aborting..") sys.exit(1)