Exemple #1
0
    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()
Exemple #2
0
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)
Exemple #3
0
    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()
Exemple #4
0
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)
Exemple #5
0
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)
Exemple #6
0
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)