Ejemplo n.º 1
0
    def test_conversion_of_package_with_dependencies(self):
        """
        Convert a non trivial Python package with several dependencies.

        Converts deb-pkg-tools_ to a Debian package archive and sanity checks the
        result. Performs static checks on the metadata (dependencies) of the
        resulting package archive.

        .. _deb-pkg-tools: https://pypi.python.org/pypi/deb-pkg-tools
        """
        # Use a temporary directory as py2deb's repository directory so that we
        # can easily find the *.deb archive generated by py2deb.
        with TemporaryDirectory() as directory:
            # Run the conversion command.
            py2deb('--repository=%s' % directory, 'deb-pkg-tools==1.22')
            # Find the generated Debian package archives.
            archives = glob.glob('%s/*.deb' % directory)
            logger.debug("Found generated archive(s): %s", archives)
            # Make sure the expected dependencies have been converted.
            converted_dependencies = set(
                parse_filename(a).name for a in archives)
            expected_dependencies = set([
                'python-cached-property',
                'python-chardet',
                'python-coloredlogs',
                'python-deb-pkg-tools',
                'python-debian',
                'python-executor',
                'python-humanfriendly',
                'python-six',
            ])
            assert expected_dependencies.issubset(converted_dependencies)
            # Use deb-pkg-tools to inspect ... deb-pkg-tools :-)
            pathname = find_package_archive(archives, 'python-deb-pkg-tools')
            metadata, contents = inspect_package(pathname)
            logger.debug("Metadata of generated package: %s", dict(metadata))
            logger.debug("Contents of generated package: %s", dict(contents))
            # Make sure the dependencies defined in `stdeb.cfg' have been preserved.
            for configured_dependency in [
                    'apt', 'apt-utils', 'dpkg-dev', 'fakeroot', 'gnupg',
                    'lintian'
            ]:
                logger.debug("Checking configured dependency %s ..",
                             configured_dependency)
                assert metadata['Depends'].matches(
                    configured_dependency) is not None
            # Make sure the dependencies defined in `setup.py' have been preserved.
            expected_dependencies = [
                'python-chardet', 'python-coloredlogs', 'python-debian',
                'python-executor', 'python-humanfriendly'
            ]
            for python_dependency in expected_dependencies:
                logger.debug("Checking Python dependency %s ..",
                             python_dependency)
                assert metadata['Depends'].matches(
                    python_dependency) is not None
Ejemplo n.º 2
0
 def test_filename_parsing(self):
     # Test the happy path.
     filename = '/var/cache/apt/archives/python2.7_2.7.3-0ubuntu3.4_amd64.deb'
     components = parse_filename(filename)
     self.assertEqual(components.filename, filename)
     self.assertEqual(components.name, 'python2.7')
     self.assertEqual(components.version, '2.7.3-0ubuntu3.4')
     self.assertEqual(components.architecture, 'amd64')
     # Test the unhappy paths.
     self.assertRaises(ValueError, parse_filename, 'python2.7_2.7.3-0ubuntu3.4_amd64.not-a-deb')
     self.assertRaises(ValueError, parse_filename, 'python2.7.deb')
Ejemplo n.º 3
0
    def check_converted_pip_accel_packages(self, directory):
        """
        Check a group of packages converted with a custom name and installation prefix.

        Check the results of :func:`test_conversion_of_isolated_packages()` and
        :func:`test_conversion_with_configuration_file()`.
        """
        # Find the generated Debian package archives.
        archives = glob.glob('%s/*.deb' % directory)
        logger.debug("Found generated archive(s): %s", archives)
        # Make sure the expected dependencies have been converted.
        converted_dependencies = set(parse_filename(a).name for a in archives)
        expected_dependencies = set([
            'pip-accel',
            'pip-accel-coloredlogs-renamed',
            'pip-accel-humanfriendly',
            'pip-accel-pip',
        ])
        assert expected_dependencies.issubset(converted_dependencies)
        # Use deb-pkg-tools to inspect pip-accel.
        pathname = find_package_archive(archives, 'pip-accel')
        metadata, contents = inspect_package(pathname)
        logger.debug("Metadata of generated package: %s", dict(metadata))
        logger.debug("Contents of generated package: %s", dict(contents))
        # Make sure the dependencies defined in `setup.py' have been
        # preserved while their names have been converted.
        assert metadata['Depends'].matches('pip-accel-coloredlogs-renamed',
                                           '0.4.6')
        assert metadata['Depends'].matches('pip-accel-humanfriendly', '1.6')
        assert metadata['Depends'].matches('pip-accel-pip', '1.4')
        assert not metadata['Depends'].matches('pip-accel-pip', '1.3')
        assert not metadata['Depends'].matches('pip-accel-pip', '1.5')
        # Make sure the executable script has been installed and is marked as executable.
        pip_accel_executable = find_file(contents,
                                         '/usr/lib/pip-accel/bin/pip-accel')
        assert pip_accel_executable.permissions == '-rwxr-xr-x'
        # Verify the existence of some expected files (picked more or less at random).
        assert find_file(contents,
                         '/usr/lib/pip-accel/lib/pip_accel/__init__.py')
        assert find_file(contents,
                         '/usr/lib/pip-accel/lib/pip_accel/deps/debian.ini')
        assert find_file(
            contents,
            '/usr/lib/pip-accel/lib/pip_accel-0.12.6*.egg-info/PKG-INFO')
        # Verify that all files are installed in the custom installation
        # prefix. We have to ignore directories, otherwise we would start
        # complaining about the parent directories /, /usr, /usr/lib, etc.
        paths_to_ignore = ['/usr/share/lintian/overrides/pip-accel']
        for filename, properties in contents.items():
            if filename not in paths_to_ignore:
                is_directory = properties.permissions.startswith('d')
                in_isolated_directory = filename.startswith(
                    '/usr/lib/pip-accel/')
                assert is_directory or in_isolated_directory
Ejemplo n.º 4
0
 def test_filename_parsing(self):
     # Test the happy path.
     filename = '/var/cache/apt/archives/python2.7_2.7.3-0ubuntu3.4_amd64.deb'
     components = parse_filename(filename)
     self.assertEqual(components.filename, filename)
     self.assertEqual(components.name, 'python2.7')
     self.assertEqual(components.version, '2.7.3-0ubuntu3.4')
     self.assertEqual(components.architecture, 'amd64')
     # Test the unhappy paths.
     self.assertRaises(ValueError, parse_filename,
                       'python2.7_2.7.3-0ubuntu3.4_amd64.not-a-deb')
     self.assertRaises(ValueError, parse_filename, 'python2.7.deb')
Ejemplo n.º 5
0
 def test_filename_parsing(self):
     """Test filename parsing."""
     # Test the happy path.
     filename = '/var/cache/apt/archives/python2.7_2.7.3-0ubuntu3.4_amd64.deb'
     components = parse_filename(filename)
     assert components.filename == filename
     assert components.name == 'python2.7'
     assert components.version == '2.7.3-0ubuntu3.4'
     assert components.architecture == 'amd64'
     # Test the unhappy paths.
     self.assertRaises(ValueError, parse_filename, 'python2.7_2.7.3-0ubuntu3.4_amd64.not-a-deb')
     self.assertRaises(ValueError, parse_filename, 'python2.7.deb')
Ejemplo n.º 6
0
 def test_filename_parsing(self):
     """Test filename parsing."""
     # Test the happy path.
     filename = '/var/cache/apt/archives/python2.7_2.7.3-0ubuntu3.4_amd64.deb'
     components = parse_filename(filename)
     assert components.filename == filename
     assert components.name == 'python2.7'
     assert components.version == '2.7.3-0ubuntu3.4'
     assert components.architecture == 'amd64'
     # Test the unhappy paths.
     self.assertRaises(ValueError, parse_filename, 'python2.7_2.7.3-0ubuntu3.4_amd64.not-a-deb')
     self.assertRaises(ValueError, parse_filename, 'python2.7.deb')
Ejemplo n.º 7
0
    def test_conversion_of_package_with_dependencies(self):
        """
        Convert a non trivial Python package with several dependencies.

        Converts deb-pkg-tools_ to a Debian package archive and sanity checks the
        result. Performs static checks on the metadata (dependencies) of the
        resulting package archive.

        .. _deb-pkg-tools: https://pypi.python.org/pypi/deb-pkg-tools
        """
        # Use a temporary directory as py2deb's repository directory so that we
        # can easily find the *.deb archive generated by py2deb.
        with TemporaryDirectory() as directory:
            # Run the conversion command.
            py2deb('--repository=%s' % directory, 'deb-pkg-tools==1.22')
            # Find the generated Debian package archives.
            archives = glob.glob('%s/*.deb' % directory)
            logger.debug("Found generated archive(s): %s", archives)
            # Make sure the expected dependencies have been converted.
            converted_dependencies = set(parse_filename(a).name for a in archives)
            expected_dependencies = set([
                'python-cached-property',
                'python-chardet',
                'python-coloredlogs',
                'python-deb-pkg-tools',
                'python-debian',
                'python-executor',
                'python-humanfriendly',
                'python-six',
            ])
            assert expected_dependencies.issubset(converted_dependencies)
            # Use deb-pkg-tools to inspect ... deb-pkg-tools :-)
            pathname = find_package_archive(archives, 'python-deb-pkg-tools')
            metadata, contents = inspect_package(pathname)
            logger.debug("Metadata of generated package: %s", dict(metadata))
            logger.debug("Contents of generated package: %s", dict(contents))
            # Make sure the dependencies defined in `stdeb.cfg' have been preserved.
            for configured_dependency in ['apt', 'apt-utils', 'dpkg-dev', 'fakeroot', 'gnupg', 'lintian']:
                logger.debug("Checking configured dependency %s ..", configured_dependency)
                assert metadata['Depends'].matches(configured_dependency) is not None
            # Make sure the dependencies defined in `setup.py' have been preserved.
            expected_dependencies = [
                'python-chardet', 'python-coloredlogs', 'python-debian',
                'python-executor', 'python-humanfriendly'
            ]
            for python_dependency in expected_dependencies:
                logger.debug("Checking Python dependency %s ..", python_dependency)
                assert metadata['Depends'].matches(python_dependency) is not None
Ejemplo n.º 8
0
def collect_packages(archives, directory, prompt=True, cache=None):
    # Find all related packages.
    related_archives = set()
    for filename in archives:
        related_archives.add(parse_filename(filename))
        related_archives.update(collect_related_packages(filename,
                                                         cache=cache))
    # Ignore package archives that are already in the target directory.
    relevant_archives = set()
    for archive in related_archives:
        basename = os.path.basename(archive.filename)
        if not os.path.isfile(os.path.join(directory, basename)):
            relevant_archives.add(archive)
    # Interactively move the package archives.
    if relevant_archives:
        relevant_archives = sorted(relevant_archives)
        pluralized = pluralize(len(relevant_archives), "package archive",
                               "package archives")
        print("Found %s:" % pluralized)
        for file_to_collect in relevant_archives:
            print(" - %s" % format_path(file_to_collect.filename))
        try:
            if prompt:
                # Ask permission to copy the file(s).
                prompt = "Copy %s to %s? [Y/n] " % (pluralized,
                                                    format_path(directory))
                assert raw_input(prompt).lower() in ('', 'y', 'yes')
            # Copy the file(s).
            for file_to_collect in relevant_archives:
                copy_from = file_to_collect.filename
                copy_to = os.path.join(directory, os.path.basename(copy_from))
                logger.debug("Copying %s -> %s ..", format_path(copy_from),
                             format_path(copy_to))
                shutil.copy(copy_from, copy_to)
            logger.info("Done! Copied %s to %s.", pluralized,
                        format_path(directory))
        except (AssertionError, KeyboardInterrupt, EOFError) as e:
            if isinstance(e, KeyboardInterrupt):
                # Control-C interrupts the prompt without emitting a newline. We'll
                # print one manually so the console output doesn't look funny.
                sys.stderr.write('\n')
            logger.warning("Not copying archive(s) to %s! (aborted by user)",
                           format_path(directory))
            if isinstance(e, KeyboardInterrupt):
                # Maybe we shouldn't actually swallow Control-C, it can make
                # for a very unfriendly user experience... :-)
                raise
Ejemplo n.º 9
0
    def check_converted_pip_accel_packages(self, directory):
        """
        Check a group of packages converted with a custom name and installation prefix.

        Check the results of :py:func:`test_conversion_of_isolated_packages()` and
        :py:func:`test_conversion_with_configuration_file()`.
        """
        # Find the generated Debian package archives.
        archives = glob.glob('%s/*.deb' % directory)
        logger.debug("Found generated archive(s): %s", archives)
        # Make sure the expected dependencies have been converted.
        converted_dependencies = set(parse_filename(a).name for a in archives)
        expected_dependencies = set([
            'pip-accel',
            'pip-accel-coloredlogs-renamed',
            'pip-accel-humanfriendly',
            'pip-accel-pip',
        ])
        assert expected_dependencies.issubset(converted_dependencies)
        # Use deb-pkg-tools to inspect pip-accel.
        pathname = find_package_archive(archives, 'pip-accel')
        metadata, contents = inspect_package(pathname)
        logger.debug("Metadata of generated package: %s", dict(metadata))
        logger.debug("Contents of generated package: %s", dict(contents))
        # Make sure the dependencies defined in `setup.py' have been
        # preserved while their names have been converted.
        assert metadata['Depends'].matches('pip-accel-coloredlogs-renamed', '0.4.6')
        assert metadata['Depends'].matches('pip-accel-humanfriendly', '1.6')
        assert metadata['Depends'].matches('pip-accel-pip', '1.4')
        assert not metadata['Depends'].matches('pip-accel-pip', '1.3')
        assert not metadata['Depends'].matches('pip-accel-pip', '1.5')
        # Make sure the executable script has been installed and is marked as executable.
        pip_accel_executable = find_file(contents, '/usr/lib/pip-accel/bin/pip-accel')
        assert pip_accel_executable.permissions == '-rwxr-xr-x'
        # Verify the existence of some expected files (picked more or less at random).
        assert find_file(contents, '/usr/lib/pip-accel/lib/pip_accel/__init__.py')
        assert find_file(contents, '/usr/lib/pip-accel/lib/pip_accel/deps/debian.ini')
        assert find_file(contents, '/usr/lib/pip-accel/lib/pip_accel-0.12.6*.egg-info/PKG-INFO')
        # Verify that all files are installed in the custom installation
        # prefix. We have to ignore directories, otherwise we would start
        # complaining about the parent directories /, /usr, /usr/lib, etc.
        paths_to_ignore = ['/usr/share/lintian/overrides/pip-accel']
        for filename, properties in contents.items():
            if filename not in paths_to_ignore:
                is_directory = properties.permissions.startswith('d')
                in_isolated_directory = filename.startswith('/usr/lib/pip-accel/')
                assert is_directory or in_isolated_directory
Ejemplo n.º 10
0
def find_package_archive(available_archives, package_name):
    """
    Find the ``*.deb`` archive of a specific package.

    :param available_packages: The pathnames of the available package archives
                               (a list of strings).
    :param package_name: The name of the package whose archive file we're
                         interested in (a string).
    :returns: The pathname of the package archive (a string).
    :raises: :exc:`exceptions.AssertionError` if zero or more than one
             package archive is found.
    """
    matches = []
    for pathname in available_archives:
        if parse_filename(pathname).name == package_name:
            matches.append(pathname)
    assert len(matches) == 1, "Expected to match exactly one package archive!"
    return matches[0]
Ejemplo n.º 11
0
def find_package_archive(available_archives, package_name):
    """
    Find the ``*.deb`` archive of a specific package.

    :param available_packages: The pathnames of the available package archives
                               (a list of strings).
    :param package_name: The name of the package whose archive file we're
                         interested in (a string).
    :returns: The pathname of the package archive (a string).
    :raises: :py:exc:`exceptions.AssertionError` if zero or more than one
             package archive is found.
    """
    matches = []
    for pathname in available_archives:
        if parse_filename(pathname).name == package_name:
            matches.append(pathname)
    assert len(matches) == 1, "Expected to match exactly one package archive!"
    return matches[0]
Ejemplo n.º 12
0
def collect_packages(archives, directory, prompt=True, cache=None):
    # Find all related packages.
    related_archives = set()
    for filename in archives:
        related_archives.add(parse_filename(filename))
        related_archives.update(collect_related_packages(filename, cache=cache))
    # Ignore package archives that are already in the target directory.
    relevant_archives = set()
    for archive in related_archives:
        basename = os.path.basename(archive.filename)
        if not os.path.isfile(os.path.join(directory, basename)):
            relevant_archives.add(archive)
    # Interactively move the package archives.
    if relevant_archives:
        relevant_archives = sorted(relevant_archives)
        pluralized = pluralize(len(relevant_archives), "package archive", "package archives")
        print("Found %s:" % pluralized)
        for file_to_collect in relevant_archives:
            print(" - %s" % format_path(file_to_collect.filename))
        try:
            if prompt:
                # Ask permission to copy the file(s).
                prompt = "Copy %s to %s? [Y/n] " % (pluralized, format_path(directory))
                assert raw_input(prompt).lower() in ('', 'y', 'yes')
            # Copy the file(s).
            for file_to_collect in relevant_archives:
                copy_from = file_to_collect.filename
                copy_to = os.path.join(directory, os.path.basename(copy_from))
                logger.debug("Copying %s -> %s ..", format_path(copy_from), format_path(copy_to))
                shutil.copy(copy_from, copy_to)
            logger.info("Done! Copied %s to %s.", pluralized, format_path(directory))
        except (AssertionError, KeyboardInterrupt, EOFError) as e:
            if isinstance(e, KeyboardInterrupt):
                # Control-C interrupts the prompt without emitting a newline. We'll
                # print one manually so the console output doesn't look funny.
                sys.stderr.write('\n')
            logger.warning("Not copying archive(s) to %s! (aborted by user)", format_path(directory))
            if isinstance(e, KeyboardInterrupt):
                # Maybe we shouldn't actually swallow Control-C, it can make
                # for a very unfriendly user experience... :-)
                raise