Ejemplo n.º 1
0
 def __init__(self,
              release=None,
              origin=None,
              label=None,
              version=None,
              description=None,
              codename=None,
              components=None,
              architectures=None,
              upstream_url=None):
     if release is None:
         release = deb822.Release()
     else:
         release = deb822.Release(release)
     if architectures is None:
         architectures = ['amd64', 'i386']
     if components is None:
         components = []
     self.release = release
     self.release.setdefault('Architectures', ' '.join(architectures))
     self.release.setdefault('Components', ' '.join(components))
     codename = self.release.setdefault('Codename', codename or 'foo')
     self.release.setdefault('Suite', codename)
     default = codename.capitalize()
     self.release.setdefault('Description', description or default)
     origin = self.release.setdefault('Origin', origin or default)
     self.release.setdefault('Label', label or origin)
     self.release.setdefault('Version', version or REPO_VERSION)
     self.set_date()
     self._component_arch_binaries = []
     self.upstream_url = upstream_url
Ejemplo n.º 2
0
def get_releaseinfo(rurl):
    cache = AptListsCache()
    # root URL of the repository
    baseurl = '/'.join(rurl.split('/')[:-1])
    # get the release file from the cache
    release_file = cache.get(rurl)

    # create parser instance
    rp = deb822.Release(release_file)

    # architectures on this dist
    archs = rp['Architectures'].split()
    components = rp['Components'].split()
    # compile a new codename that also considers the repository label
    # to distinguish between official and unofficial repos.
    label = rp['Label']
    origin = rp['Origin']
    codename = rp['Codename']
    labelcode = '_'.join([rp['Label'], rp['Codename']])

    # cleanup
    release_file.close()

    return {
        'baseurl': baseurl,
        'archs': archs,
        'components': components,
        'codename': codename,
        'label': label,
        'labelcode': labelcode,
        'origin': origin
    }
    def get_repository(self, connection, repository_data, arch, consumer):
        url = utils.normalize_repository_url(repository_data['uri'])
        suite = repository_data['suite']
        components = repository_data.get('section')
        path = repository_data.get('path')
        name = repository_data.get('name')

        # TODO(bgaifullin) implement support for flat repisotory format [1]
        # [1] https://wiki.debian.org/RepositoryFormat#Flat_Repository_Format
        if components is None:
            raise ValueError("The flat format does not supported.")

        for component in components:
            release = self._get_url_of_metafile((url, suite, component, arch),
                                                "Release")
            try:
                deb_release = deb822.Release(connection.open_stream(release))
            except connection.HTTPError as e:
                if e.code != 404:
                    raise
                # some repositories does not contain release file
                deb_release = {"origin": ""}

            consumer(
                Repository(name=name,
                           architecture=arch,
                           origin=deb_release["origin"],
                           url=url,
                           section=(suite, component),
                           path=path,
                           priority=self.get_priority(repository_data)))
Ejemplo n.º 4
0
 def __init__(self,
              publication,
              codename,
              components,
              architectures,
              label=None,
              description=None):
     self.publication = publication
     self.release = deb822.Release()
     self.release["Codename"] = codename
     self.release["Architectures"] = " ".join(architectures)
     if label:
         self.release["Label"] = label
     if description:
         self.release["Description"] = description
     self.release["MD5sum"] = []
     self.release["SHA1"] = []
     self.release["SHA256"] = []
     self.release["SHA512"] = []
     self.architectures = architectures
     self.components = {
         name: _ComponentHelper(self, name)
         for name in components
     }
     self.signing_service = publication.signing_service
Ejemplo n.º 5
0
    async def run(self):
        """
        Parse Release content units.

        Update release content with information obtained from its artifact.
        """
        with ProgressReport(message="Update Release units",
                            code="update.release") as pb:
            async for d_content in self.items():
                if isinstance(d_content.content, Release):
                    release = d_content.content
                    release_artifact = d_content.d_artifacts[0].artifact
                    release.sha256 = release_artifact.sha256
                    release_dict = deb822.Release(release_artifact.file)
                    release.codename = release_dict["Codename"]
                    release.suite = release_dict["Suite"]
                    # TODO split of extra stuff e.g. : 'updates/main' -> 'main'
                    release.components = _filter_ssl(
                        release_dict["Components"], self.components)
                    release.architectures = _filter_ssl(
                        release_dict["Architectures"], self.architectures)
                    log.debug("Codename: {}".format(release.codename))
                    log.debug("Components: {}".format(release.components))
                    log.debug("Architectures: {}".format(
                        release.architectures))
                    pb.increment()
                await self.put(d_content)
Ejemplo n.º 6
0
    def test_create_repo(self):
        files = []
        for root, _, fl in os.walk(self.pool_dir):
            for f in fl:
                if f.endswith('.deb'):
                    files.append(os.path.join(root, f))

        repo = create_repo(self.new_repo_dir,
                           files,
                           codename=self.repo_codename,
                           arches=self.repo_arches,
                           components=[self.repo_component],
                           desc=self.repo_description,
                           origin=self.repo_name)

        release_file = repo.metadata.release_path(repo.base_path)

        with open(release_file, 'r') as fh:
            release_data = fh.read()

        release_822 = deb822.Release(release_data)
        self.assertEqual(release_822.get('Origin'), self.repo_name)
        self.assertEqual(release_822.get('Label'), self.repo_name)
        self.assertEqual(release_822.get('Description'), self.repo_description)
        # Test handling of Architectures
        self.assertEqual(release_822.get('Architectures'), u'i386 amd64')
        self.assertEqual(repo.metadata.architectures, ['i386', 'amd64'])
        # Test package paths
        packagefile_paths_256 = [x['name'] for x in release_822['SHA256']]
        packagefile_paths_1 = [x['name'] for x in release_822['SHA1']]
        self.assertEqual(packagefile_paths_256, self.packagefile_paths)
        self.assertEqual(packagefile_paths_1, self.packagefile_paths)
Ejemplo n.º 7
0
def create_cache(repository_root, cache_dir_path):
    """

    Creates the cache and all other necessary directories to organize the
    control files pulled from the repository.

    :param repository_root: url of the repository from which the control files
                            files will be pulled.
    :param cache_dir_path: path where the cache will be created.

    .. versionadded:: 0.1

    """

    if not os.path.isdir(cache_dir_path):
        os.makedirs(cache_dir_path)

    branches = (branch.split() for branch in readconfig(
        os.path.join(repository_root, 'distributions')))
    for name, release_path in branches:
        release_path = os.path.join(repository_root, release_path)
        try:
            md5list = deb822.Release(
                urllib.urlopen(release_path)).get('MD5sum')
        except urllib2.URLError, e:
            logger.warning(
                'Could not read release file in %s, error code #%s' %
                (release_path, e.code))
        else:
            for control_file_data in md5list:
                if re.match('[\w]*-?[\w]*/[\w]*-[\w]*/Packages.gz$',
                            control_file_data['name']):
                    component, architecture, _ = control_file_data[
                        'name'].split('/')
                    remote_file = os.path.join(repository_root, 'dists', name,
                                               control_file_data['name'])
                    local_name = '_'.join(
                        [name, component,
                         architecture.replace('binary-', '')])
                    f = os.path.join(cache_dir_path, local_name + '.gz')

                    if not os.path.isfile(f):
                        try:
                            urllib.urlretrieve(remote_file, f)
                        except urllib2.URLError, e:
                            logger.error('Could not get %s, error code #%s' %
                                         (remote_file, e.code))
                    else:
                        if md5Checksum(f) != control_file_data['md5sum']:
                            os.remove(f)
                            try:
                                urllib.urlretrieve(remote_file, f)
                            except urllib2.URLError, e:
                                logger.error(
                                    'Could not get %s, error code #%s' %
                                    (remote_file, e.code))
Ejemplo n.º 8
0
 def __init__(self, release=None, packages=None, meta=None, dist=None):
     if release is None:
         release = deb822.Release()
     if meta is None:
         meta = dict()
     for k, v in meta.items():
         release.setdefault(k.capitalize(), v)
     self.release = release
     self._packages = packages
     self._packages_file = None
     self.dist = dist
Ejemplo n.º 9
0
    def test_metadata_not_shared(self):
        # Make sure defaults are not shared between objects
        rel = deb822.Release(dict(Architectures="amd64 i386 aarch64"))
        md1 = AptRepoMeta(rel)
        self.assertEqual(['amd64', 'i386', 'aarch64'], md1.architectures)

        md1.architectures = ['amd64']
        self.assertEqual(['amd64'], md1.architectures)

        md2 = AptRepoMeta(rel)
        self.assertEqual(['amd64', 'i386', 'aarch64'], md2.architectures)
Ejemplo n.º 10
0
    def test_metadata(self, _strftime):
        _strftime.return_value = "ABCDE"
        repo_meta = AptRepoMeta(**self.defaults)

        release_path = os.path.join(self.test_dir, 'dists', 'stable',
                                    'Release')
        self.assertEqual(release_path, repo_meta.release_path(self.test_dir))
        repo_meta.write_release(self.test_dir)

        expected = dict(self.repo_release_data, Date="ABCDE")
        self.assertEqual(expected,
                         deb822.Release(open(release_path, "rb").read()))

        comp_binary = repo_meta.get_component_arch_binary('main', 'amd64')
        release_path = os.path.join(self.test_dir, 'dists', 'stable', 'main',
                                    'binary-amd64', 'Release')
        self.assertEqual(release_path, comp_binary.release_path(self.test_dir))
        comp_binary.write_release(self.test_dir)
        expected = self.release_data
        self.assertEqual(expected,
                         deb822.Release(open(release_path, "rb").read()))
Ejemplo n.º 11
0
def sync_cache(repository_root, cache_dir_path):
    """

    Synchronizes the existing control files in the cache,
    comparing the the ones in the repository with the local copies.
    If there are differences in the MD5sum field then the local
    copies are deleted and copied again from the repository.
    It is assumed that the cache directory was created previously.

    :param repository_root: url of the repository from which the Packages
                            files will be updated.
    :param cache_dir_path: path to the desired cache directory.

    .. versionadded:: 0.1

    """
    branches = (branch.split() for branch in readconfig(
        os.path.join(repository_root, 'distributions')))
    changes = []
    for branch, _ in branches:
        remote_branch_path = os.path.join(repository_root, 'dists', branch)
        release_path = os.path.join(remote_branch_path, 'Release')
        try:
            md5list = deb822.Release(
                urllib.urlopen(release_path)).get('MD5sum')
        except urllib2.URLError, e:
            logger.warning(
                'Could not read release file in %s, error code #%s' %
                (remote_branch_path, e.code))
        else:
            for package_control_file in md5list:
                if re.match('[\w]*-?[\w]*/[\w]*-[\w]*/Packages.gz$',
                            package_control_file['name']):
                    component, architecture, _ = package_control_file[
                        'name'].split('/')
                    remote_package_path = os.path.join(
                        remote_branch_path, package_control_file['name'])
                    local_name = '_'.join([
                        branch, component,
                        architecture.replace('binary-', '')
                    ])
                    f = os.path.join(cache_dir_path, local_name + '.gz')
                    if package_control_file['md5sum'] != md5Checksum(f):
                        if os.path.exists(f):
                            os.remove(f)
                        try:
                            urllib.urlretrieve(remote_package_path, f)
                            changes.append(os.path.basename(f))
                        except urllib2.URLError, e:
                            logger.error('Could not get %s, error code #%s' %
                                         (remote_package_path, e.code))
                    else:
                        logger.info('There are no changes in %s' % f)
Ejemplo n.º 12
0
    def test_AptRepo_create(self):
        test_dir = os.path.join(self.test_dir, self.repo_name, '_2001')

        packagefile_paths = [
            u'main/binary-amd64/Packages', u'main/binary-amd64/Packages.gz',
            u'main/binary-amd64/Packages.bz2'
        ]
        files = []
        for root, _, fl in os.walk(self.pool_dir):
            for f in fl:
                if f.endswith('.deb'):
                    files.append(os.path.join(root, f))
        arch = 'amd64'
        codename = 'stable'
        component = 'main'
        repometa = AptRepoMeta(codename=codename,
                               components=[component],
                               architectures=[arch])

        repo = AptRepo(test_dir,
                       repo_name=self.repo_name,
                       metadata=repometa,
                       gpg_sign_options=None)

        # Looking for bad behavior in defaults
        repo.create(files,
                    component=component,
                    architecture=arch,
                    with_symlinks=True)

        release_file = repo.metadata.release_path(repo.base_path)

        with open(release_file, 'r') as fh:
            release_data = fh.read()

        release_822 = deb822.Release(release_data)

        # Test defaults for Origin, Label, Description
        expected_default_origin = codename.capitalize()
        self.assertEqual(release_822.get('Origin'), expected_default_origin)
        self.assertEqual(release_822.get('Label'), expected_default_origin)
        self.assertEqual(release_822.get('Description'),
                         expected_default_origin)
        # Test default for Suite
        self.assertEqual(release_822.get('Suite'), codename)
        # Test handling of Architectures
        self.assertEqual(release_822.get('Architectures'), arch)
        self.assertEqual(repo.metadata.architectures, [arch])
        packagefile_paths_256 = [x['name'] for x in release_822['SHA256']]
        packagefile_paths_1 = [x['name'] for x in release_822['SHA1']]
        self.assertEqual(packagefile_paths_256, packagefile_paths)
        self.assertEqual(packagefile_paths_1, packagefile_paths)
Ejemplo n.º 13
0
 async def _handle_distribution(self, distribution):
     log.info(
         _('Downloading Release file for distribution: "{}"').format(
             distribution))
     # Create release_file
     if distribution[-1] == "/":
         release_file_dir = distribution.strip("/")
     else:
         release_file_dir = os.path.join("dists", distribution)
     release_file_dc = DeclarativeContent(
         content=ReleaseFile(distribution=distribution),
         d_artifacts=[
             self._to_d_artifact(os.path.join(release_file_dir, filename))
             for filename in ["Release", "InRelease", "Release.gpg"]
         ],
     )
     release_file = await self._create_unit(release_file_dc)
     if release_file is None:
         return
     # Create release object
     release_unit = Release(codename=release_file.codename,
                            suite=release_file.suite,
                            distribution=distribution)
     release_dc = DeclarativeContent(content=release_unit)
     release = await self._create_unit(release_dc)
     # Create release architectures
     architectures = _filter_split_architectures(release_file.architectures,
                                                 self.remote.architectures,
                                                 distribution)
     for architecture in architectures:
         release_architecture_dc = DeclarativeContent(
             content=ReleaseArchitecture(architecture=architecture,
                                         release=release))
         await self.put(release_architecture_dc)
     # Parse release file
     log.info(
         _('Parsing Release file at distribution="{}"').format(
             distribution))
     release_artifact = await _get_main_artifact_blocking(release_file)
     release_file_dict = deb822.Release(release_artifact.file)
     # collect file references in new dict
     file_references = defaultdict(deb822.Deb822Dict)
     for digest_name in ["SHA512", "SHA256", "SHA1", "MD5sum"]:
         if digest_name in release_file_dict:
             for unit in release_file_dict[digest_name]:
                 file_references[unit["Name"]].update(unit)
     await asyncio.gather(*[
         self._handle_component(component, release, release_file,
                                file_references, architectures)
         for component in _filter_split_components(
             release_file.components, self.remote.components, distribution)
     ])
Ejemplo n.º 14
0
def create_cache_alt(repository_root, cache_dir_path, debug=True):
    branches = ['aponwao', 'auyantepui', 'roraima', 'kerepakupai', 'kukenan']

    for branch in branches:
        remote_branch_path = os.path.join(repository_root, "dists", branch)
        local_branch_path = os.path.join(cache_dir_path, branch)

        release_data = urllib.urlopen(
            os.path.join(remote_branch_path, "Release"))
        release_control_file = deb822.Release(release_data)

        archs = release_control_file.get('Architectures').split()
        comps = release_control_file.get('Components').split()
        md5sums = release_control_file.get('MD5Sum')

        for comp in comps:
            for arch in archs:
                remote_file_path = os.path.join(remote_branch_path, comp,
                                                'binary-' + arch)
                local_file_path = os.path.join(local_branch_path, comp, arch)
                if not os.path.isdir(local_file_path):
                    os.makedirs(local_file_path)
                remote_control_file_path = os.path.join(
                    remote_file_path, "Packages.gz")
                local_control_file_path = os.path.join(local_file_path,
                                                       "Packages.gz")
                if not os.path.isfile(local_control_file_path):
                    try:
                        urllib.urlretrieve(remote_control_file_path,
                                           local_control_file_path)
                    # Agregar tipo de excepcion
                    except:
                        logger.error(
                            'There has been an error trying to get %s' %
                            remote_control_file_path)
                else:
                    for md5sum in md5sums:
                        if md5sum.get('name') == os.path.join(
                                comp, 'binary-' + arch, 'Packages.gz'):
                            if md5Checksum(local_control_file_path
                                           ) != md5sum.get('md5sum'):
                                os.remove(local_control_file_path)
                                try:
                                    urllib.urlretrieve(
                                        remote_control_file_path,
                                        local_control_file_path)
                                # Agregar tipo de excepcion
                                except:
                                    logger.error(
                                        'There has been an error trying to get %s'
                                        % remote_control_file_path)
Ejemplo n.º 15
0
def update_cache(repository_root, cache_dir_path):
    '''
    Updates the control files existent in the cache,
    comparing the the ones in the repository with its local copies.
    If there are differences in the MD5sum field then the local
    copies are deleted and copied again from the repository. 
    It is assumed that the cache directory was created previously.
    
    :param repository_root: url of the repository from which the Packages files will be updated.

    :param cache_dir_path: path to the desired cache directory

    .. versionadded:: 0.1
    '''

    local_branches = (branch.split() for branch in readconfig(
        os.path.join(repository_root, "distributions")))
    for branch, _ in local_branches:
        remote_branch_path = os.path.join(repository_root, "dists", branch)
        local_branch_path = os.path.join(cache_dir_path, branch)
        release_path = os.path.join(remote_branch_path, "Release")
        try:
            md5list = deb822.Release(
                urllib.urlopen(release_path)).get('MD5sum')
        except urllib2.URLError, e:
            logger.warning(
                'Could not read release file in %s, error code #%s' %
                (remote_branch_path, e.code))
        else:
            for package_control_file in md5list:
                if re.match("[\w]*-?[\w]*/[\w]*-[\w]*/Packages.gz$",
                            package_control_file['name']):
                    _, architecture, _ = package_control_file['name'].split(
                        "/")
                    # BUSCAR UNA FORMA MENOS PROPENSA A ERRORES PARA HACER ESTO
                    architecture = architecture.split("-")[1]
                    remote_package_path = os.path.join(
                        remote_branch_path, package_control_file['name'])
                    local_package_path = os.path.join(
                        local_branch_path, package_control_file['name'])
                    if package_control_file['md5sum'] != md5Checksum(
                            local_package_path):
                        os.remove(local_package_path)
                        urllib.urlretrieve(remote_package_path,
                                           local_package_path)
                        update_package_list(local_package_path, branch,
                                            architecture)
                    else:
                        logger.info('There are no changes in %s' %
                                    local_package_path)
Ejemplo n.º 16
0
    def __init__(
        self,
        publication,
        codename,
        distribution,
        components,
        architectures,
        label,
        version,
        description=None,
        suite=None,
    ):
        self.publication = publication
        self.distribution = distribution
        self.dists_subfolder = distribution.strip(
            "/") if distribution != "/" else "flat-repo"
        if distribution[-1] == "/":
            message = "Using dists subfolder '{}' for structured publish of originally flat repo!"
            log.info(_(message).format(self.dists_subfolder))
        # Note: The order in which fields are added to self.release is retained in the
        # published Release file. As a "nice to have" for human readers, we try to use
        # the same order of fields that official Debian repositories use.
        self.release = deb822.Release()
        self.release["Origin"] = "Pulp 3"
        self.release["Label"] = label
        if suite:
            self.release["Suite"] = suite
        self.release["Version"] = version
        if not codename:
            codename = distribution.split(
                "/")[0] if distribution != "/" else "flat-repo"
        self.release["Codename"] = codename
        self.release["Date"] = datetime.now(
            tz=timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")
        self.release["Architectures"] = " ".join(architectures)
        self.release["Components"] = ""  # Will be set later
        if description:
            self.release["Description"] = description

        for checksum_type, deb_field in CHECKSUM_TYPE_MAP.items():
            if checksum_type in settings.ALLOWED_CONTENT_CHECKSUMS:
                self.release[deb_field] = []

        self.architectures = architectures
        self.components = {
            component: _ComponentHelper(self, component)
            for component in components
        }
        self.signing_service = publication.signing_service
Ejemplo n.º 17
0
 def get_packages_gz(self):
     '''
     '''
     remote_branch_path = os.path.join(self.repo, "dists", self.branch)
     release_path = os.path.join(remote_branch_path, "Release")
     changes = []
     try:
         # TODO: Use tmpfile library here
         tmp = "/tmp/Release"
         download_file(release_path, tmp)
         rls_file = open(tmp, "r")
         md5list = deb822.Release(rls_file).get('MD5sum')
         rls_file.close()
     except urllib2.URLError, e:
         print 'Could not read release file in %s, error code #%s' % (
             remote_branch_path, e.code)
Ejemplo n.º 18
0
def init_sample_packages(repository_root, samples_dir):
    """

    Creates a directory structure to store packages for its later use
    in a test package repository.

    :param repository_root: url of the repository used.

    :param samples_dir: directory that will be used to store the examples for
                        the repository.

    .. versionadded:: 0.1

    """

    if not os.path.isdir(samples_dir):
        os.makedirs(samples_dir)

    # Puede que exista una forma mas sencilla de obtener los nombres
    dist_releases = (branch.split() for branch in readconfig(
        os.path.join(repository_root, "distributions")))
    for release, _ in dist_releases:
        release_path = os.path.join(repository_root, "dists", release,
                                    "Release")
        try:
            # Riesgo poco probable de que el Release no tenga MD5sum
            md5list = deb822.Release(
                urllib.urlopen(release_path)).get('MD5sum')
            print md5list
        except urllib2.URLError, e:
            logger.warning(
                'Could not read release file in %s, error code #%s' %
                (release_path, e.code))
        else:
            for l in md5list:
                if re.match("[\w]*-?[\w]*/[\w]*-[\w]*/Packages.gz$",
                            l['name']):
                    list_dir = os.path.join(samples_dir, release,
                                            os.path.dirname(l['name']))
                    if not os.path.isdir(list_dir):
                        os.makedirs(list_dir)
                    list_path = os.path.join(list_dir, "list")
                    if not os.path.isfile(list_path):
                        control_f_path = os.path.join(repository_root, "dists",
                                                      release, l['name'])
                        select_sample_packages(control_f_path, list_path,
                                               samples_dir, False)
    def _create_repository_structure(self, repository):
        packages_file = utils.get_path_from_url(
            self._get_url_of_metafile(repository, "Packages"))
        release_file = utils.get_path_from_url(
            self._get_url_of_metafile(repository, "Release"))
        utils.ensure_dir_exist(os.path.dirname(release_file))

        release = deb822.Release()
        release["Origin"] = repository.origin
        release["Label"] = repository.origin
        release["Archive"] = repository.section[0]
        release["Component"] = repository.section[1]
        release["Architecture"] = _ARCHITECTURES[repository.architecture]
        with open(release_file, "wb") as fd:
            release.dump(fd)

        open(packages_file, "ab").close()
        gzip.open(packages_file + ".gz", "ab").close()
Ejemplo n.º 20
0
    async def run(self):
        """
        Parse ReleaseFile content units.

        Update release content with information obtained from its artifact.
        """
        with ProgressReport(message="Update ReleaseFile units",
                            code="update.release_file") as pb:
            async for d_content in self.items():
                if isinstance(d_content.content, ReleaseFile):
                    release_file = d_content.content
                    da_names = {
                        os.path.basename(da.relative_path): da
                        for da in d_content.d_artifacts
                    }
                    if "InRelease" in da_names:
                        release_file_artifact = da_names["InRelease"].artifact
                        release_file.relative_path = da_names[
                            "InRelease"].relative_path
                    elif "Release" in da_names:
                        release_file_artifact = da_names["Release"].artifact
                        release_file.relative_path = da_names[
                            "Release"].relative_path
                    else:
                        # No (proper) artifacts left -> drop it
                        d_content.content = None
                        d_content.resolve()
                        continue
                    release_file.sha256 = release_file_artifact.sha256
                    release_file_dict = deb822.Release(
                        release_file_artifact.file)
                    release_file.codename = release_file_dict["Codename"]
                    release_file.suite = release_file_dict["Suite"]
                    # TODO split of extra stuff e.g. : 'updates/main' -> 'main'
                    release_file.components = release_file_dict["Components"]
                    release_file.architectures = release_file_dict[
                        "Architectures"]
                    log.debug("Codename: {}".format(release_file.codename))
                    log.debug("Components: {}".format(release_file.components))
                    log.debug("Architectures: {}".format(
                        release_file.architectures))
                    pb.increment()
                await self.put(d_content)
Ejemplo n.º 21
0
    def __init__(
        self,
        publication,
        codename,
        distribution,
        components,
        architectures,
        label,
        version,
        description=None,
        suite=None,
    ):
        self.publication = publication
        self.distribution = distribution
        # Note: The order in which fields are added to self.release is retained in the
        # published Release file. As a "nice to have" for human readers, we try to use
        # the same order of fields that official Debian repositories use.
        self.release = deb822.Release()
        self.release["Origin"] = "Pulp 3"
        self.release["Label"] = label
        if suite:
            self.release["Suite"] = suite
        self.release["Version"] = version
        self.release["Codename"] = codename
        self.release["Date"] = datetime.now(
            tz=timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")
        self.release["Architectures"] = " ".join(architectures)
        self.release["Components"] = ""  # Will be set later
        if description:
            self.release["Description"] = description
        self.release["MD5sum"] = []
        self.release["SHA1"] = []
        self.release["SHA256"] = []
        self.release["SHA512"] = []

        self.architectures = architectures
        self.components = {
            component: _ComponentHelper(self, component)
            for component in components
        }
        self.signing_service = publication.signing_service
Ejemplo n.º 22
0
    def addRelease(self, cache_path, file_path):
        """Add a Release file's info to the list of index files.
        
        Dirty hack until python-apt supports apt-pkg/indexrecords.h
        (see Bug #456141)
        """
        self.indexrecords[cache_path] = {}

        read_packages = False
        f = file_path.open('r')

        # Use python-debian routines to parse the file for hashes
        rel = deb822.Release(f, fields=['MD5Sum', 'SHA1', 'SHA256'])
        for hash_type in rel:
            for file in rel[hash_type]:
                self.indexrecords[cache_path].setdefault(
                    str(file['name']),
                    {})[hash_type.upper()] = (str(file[hash_type]),
                                              file['size'])

        f.close()
    def _update_suite_index(self, repository):
        """Updates the Release file in the suite."""
        path = os.path.join(utils.get_path_from_url(repository.url), "dists",
                            repository.section[0])
        release_path = os.path.join(path, "Release")
        self.logger.info("added repository suite release file: %s",
                         release_path)
        with open(release_path, "a+b") as fd:
            fcntl.flock(fd.fileno(), fcntl.LOCK_EX)
            try:
                fd.seek(0)
                release = deb822.Release(fd)
                self._add_to_release(release, repository)
                for m in _CHECKSUM_METHODS:
                    release.setdefault(m, [])

                self._add_files_to_release(release, path,
                                           self._get_metafiles(repository))

                fd.truncate(0)
                release.dump(fd)
            finally:
                fcntl.flock(fd.fileno(), fcntl.LOCK_UN)
Ejemplo n.º 24
0
    async def run(self):
        """
        Parse ReleaseFile content units.

        Update release content with information obtained from its artifact.
        """
        async with ProgressReport(message="Update ReleaseFile units",
                                  code="update.release_file") as pb:
            async for d_content in self.items():
                if isinstance(d_content.content, ReleaseFile):
                    release_file = d_content.content
                    da_names = {
                        os.path.basename(da.relative_path): da
                        for da in d_content.d_artifacts
                    }
                    if "Release" in da_names:
                        if "Release.gpg" in da_names:
                            if self.gpgkey:
                                with NamedTemporaryFile() as tmp_file:
                                    tmp_file.write(da_names["Release"].
                                                   artifact.file.read())
                                    tmp_file.flush()
                                    verified = self.gpg.verify_file(
                                        da_names["Release.gpg"].artifact.file,
                                        tmp_file.name)
                                if verified.valid:
                                    log.info(
                                        _("Verification of Release successful."
                                          ))
                                    release_file_artifact = da_names[
                                        "Release"].artifact
                                    release_file.relative_path = da_names[
                                        "Release"].relative_path
                                else:
                                    log.warning(
                                        _("Verification of Release failed. Dropping it."
                                          ))
                                    d_content.d_artifacts.remove(
                                        da_names.pop("Release"))
                                    d_content.d_artifacts.remove(
                                        da_names.pop("Release.gpg"))
                            else:
                                release_file_artifact = da_names[
                                    "Release"].artifact
                                release_file.relative_path = da_names[
                                    "Release"].relative_path
                        else:
                            if self.gpgkey:
                                d_content.d_artifacts.delete(
                                    da_names["Release"])
                            else:
                                release_file_artifact = da_names[
                                    "Release"].artifact
                                release_file.relative_path = da_names[
                                    "Release"].relative_path
                    else:
                        if "Release.gpg" in da_names:
                            # No need to keep the signature without "Release"
                            d_content.d_artifacts.remove(
                                da_names.pop("Release.gpg"))

                    if "InRelease" in da_names:
                        if self.gpgkey:
                            verified = self.gpg.verify_file(
                                da_names["InRelease"].artifact.file)
                            if verified.valid:
                                log.info(
                                    _("Verification of InRelease successful."))
                                release_file_artifact = da_names[
                                    "InRelease"].artifact
                                release_file.relative_path = da_names[
                                    "InRelease"].relative_path
                            else:
                                log.warning(
                                    _("Verification of InRelease failed. Dropping it."
                                      ))
                                d_content.d_artifacts.remove(
                                    da_names.pop("InRelease"))
                        else:
                            release_file_artifact = da_names[
                                "InRelease"].artifact
                            release_file.relative_path = da_names[
                                "InRelease"].relative_path

                    if not d_content.d_artifacts:
                        # No (proper) artifacts left -> distribution not found
                        raise NoReleaseFile(
                            distribution=release_file.distribution)

                    release_file.sha256 = release_file_artifact.sha256
                    release_file_dict = deb822.Release(
                        release_file_artifact.file)
                    if "codename" in release_file_dict:
                        release_file.codename = release_file_dict["Codename"]
                    if "suite" in release_file_dict:
                        release_file.suite = release_file_dict["Suite"]

                    if "components" in release_file_dict:
                        release_file.components = release_file_dict[
                            "Components"]
                    elif release_file.distribution[-1] == "/":
                        message = (
                            "The Release file for distribution '{}' contains no 'Components' "
                            "field, but since we are dealing with a flat repo, we can continue "
                            "regardless.")
                        log.warning(
                            _(message).format(release_file.distribution))
                        # TODO: Consider not setting the field at all (requires migrations).
                        release_file.components = ""
                    else:
                        raise MissingReleaseFileField(
                            release_file.distribution, "Components")

                    if "architectures" in release_file_dict:
                        release_file.architectures = release_file_dict[
                            "Architectures"]
                    elif release_file.distribution[-1] == "/":
                        message = (
                            "The Release file for distribution '{}' contains no 'Architectures' "
                            "field, but since we are dealing with a flat repo, we can extract them "
                            "from the repos single Package index later.")
                        log.warning(
                            _(message).format(release_file.distribution))
                        release_file.architectures = ""
                    else:
                        raise MissingReleaseFileField(
                            release_file.distribution, "Architectures")

                    log.debug(_("Codename: {}").format(release_file.codename))
                    log.debug(
                        _("Components: {}").format(release_file.components))
                    log.debug(
                        _("Architectures: {}").format(
                            release_file.architectures))
                    await pb.aincrement()
                await self.put(d_content)
Ejemplo n.º 25
0
    async def run(self):
        """
        Build and emit `DeclarativeContent` from the Release data.
        """
        # TODO Merge into one list of futures
        future_releases = []
        future_package_indices = []
        future_installer_file_indices = []
        with ProgressReport(
                message="Creating download requests for Release files",
                code="download.release",
                total=self.num_distributions,
        ) as pb:
            for distribution in self.distributions:
                log.info(
                    'Downloading Release file for distribution: "{}"'.format(
                        distribution))
                release_relpath = os.path.join("dists", distribution,
                                               "Release")
                release_path = os.path.join(self.parsed_url.path,
                                            release_relpath)
                release_da = DeclarativeArtifact(
                    Artifact(),
                    urlunparse(self.parsed_url._replace(path=release_path)),
                    release_relpath,
                    self.remote,
                    deferred_download=False,
                )
                release_gpg_relpath = os.path.join("dists", distribution,
                                                   "Release.gpg")
                release_gpg_path = os.path.join(self.parsed_url.path,
                                                release_gpg_relpath)
                release_gpg_da = DeclarativeFailsafeArtifact(
                    Artifact(),
                    urlunparse(
                        self.parsed_url._replace(path=release_gpg_path)),
                    release_gpg_relpath,
                    self.remote,
                    deferred_download=False,
                )
                inrelease_relpath = os.path.join("dists", distribution,
                                                 "InRelease")
                inrelease_path = os.path.join(self.parsed_url.path,
                                              inrelease_relpath)
                inrelease_da = DeclarativeFailsafeArtifact(
                    Artifact(),
                    urlunparse(self.parsed_url._replace(path=inrelease_path)),
                    inrelease_relpath,
                    self.remote,
                    deferred_download=False,
                )
                release_unit = Release(distribution=distribution,
                                       relative_path=release_relpath)
                release_dc = DeclarativeContent(
                    content=release_unit,
                    d_artifacts=[release_da, release_gpg_da, inrelease_da],
                    does_batch=False,
                )
                future_releases.append(release_dc.get_or_create_future())
                await self.put(release_dc)
                pb.increment()

        with ProgressReport(message="Parsing Release files",
                            code="parsing.release",
                            total=self.num_distributions) as pb:
            for release_future in asyncio.as_completed(future_releases):
                release = await release_future
                if release is None:
                    continue
                log.info('Parsing Release file for release: "{}"'.format(
                    release.codename))
                release_artifact = release._artifacts.get(
                    sha256=release.sha256)
                release_dict = deb822.Release(release_artifact.file)
                async for d_content in self._read_release_file(
                        release, release_dict):
                    if isinstance(d_content.content, PackageIndex):
                        future_package_indices.append(
                            d_content.get_or_create_future())
                    if isinstance(d_content.content, InstallerFileIndex):
                        future_installer_file_indices.append(
                            d_content.get_or_create_future())
                    await self.put(d_content)
                pb.increment()

        with ProgressReport(message="Parsing package index files",
                            code="parsing.packageindex") as pb:
            for package_index_future in asyncio.as_completed(
                    future_package_indices):
                package_index = await package_index_future
                if package_index is None:
                    continue
                package_index_artifact = package_index.main_artifact
                log.debug("Parsing package index for {}:{}.".format(
                    package_index.component, package_index.architecture))
                async for package_dc in self._read_package_index(
                        package_index_artifact.file):
                    await self.put(package_dc)
                pb.increment()

        with ProgressReport(message="Parsing installer file index files",
                            code="parsing.installer") as pb:
            for installer_file_index_future in asyncio.as_completed(
                    future_installer_file_indices):
                installer_file_index = await installer_file_index_future
                if installer_file_index is None:
                    continue
                log.debug("Parsing installer file index for {}:{}.".format(
                    installer_file_index.component,
                    installer_file_index.architecture))
                async for d_content in self._read_installer_file_index(
                        installer_file_index):
                    await self.put(d_content)
                pb.increment()
Ejemplo n.º 26
0
def publish(publisher_pk, repository_version_pk):
    """
    Use provided publisher to create a Publication based on a RepositoryVersion.

    Args:
        publisher_pk (str): Use the publish settings provided by this publisher.
        repository_version_pk (str): Create a publication from this repository version.
    """
    publisher = DebPublisher.objects.get(pk=publisher_pk)
    repository_version = RepositoryVersion.objects.get(
        pk=repository_version_pk)

    log.info(
        _('Publishing: repository={repo}, version={ver}, publisher={pub}').
        format(repo=repository_version.repository.name,
               ver=repository_version.number,
               pub=publisher.name))
    with WorkingDirectory():
        with Publication.create(repository_version,
                                publisher,
                                pass_through=False) as publication:
            if publisher.simple:
                repository = repository_version.repository
                release = deb822.Release()
                # TODO: release['Label']
                release['Codename'] = 'default'
                release['Components'] = 'all'
                release['Architectures'] = ''
                if repository.description:
                    release['Description'] = repository.description
                release['MD5sum'] = []
                release['SHA1'] = []
                release['SHA256'] = []
                release['SHA512'] = []
                package_index_files = {}
                for package in Package.objects.filter(
                        pk__in=repository_version.content.order_by(
                            '-_created')):
                    published_artifact = PublishedArtifact(
                        relative_path=package.filename(),
                        publication=publication,
                        content_artifact=package.contentartifact_set.get(),
                    )
                    published_artifact.save()
                    if package.architecture not in package_index_files:
                        package_index_path = os.path.join(
                            'dists',
                            'default',
                            'all',
                            'binary-{}'.format(package.architecture),
                            'Packages',
                        )
                        os.makedirs(os.path.dirname(package_index_path),
                                    exist_ok=True)
                        package_index_files[package.architecture] = (open(
                            package_index_path, 'wb'), package_index_path)
                    package.to822('all').dump(
                        package_index_files[package.architecture][0])
                    package_index_files[package.architecture][0].write(b'\n')
                for package_index_file, package_index_path in package_index_files.values(
                ):
                    package_index_file.close()
                    gz_package_index_path = _zip_file(package_index_path)
                    _add_to_release(release, package_index_path)
                    _add_to_release(release, gz_package_index_path)

                    package_index = PublishedMetadata(
                        relative_path=package_index_path,
                        publication=publication,
                        file=File(open(package_index_path, 'rb')),
                    )
                    package_index.save()
                    gz_package_index = PublishedMetadata(
                        relative_path=gz_package_index_path,
                        publication=publication,
                        file=File(open(gz_package_index_path, 'rb')),
                    )
                    gz_package_index.save()
                release['Architectures'] = ', '.join(
                    package_index_files.keys())
                release_path = os.path.join('dists', 'default', 'Release')
                os.makedirs(os.path.dirname(release_path), exist_ok=True)
                with open(release_path, 'wb') as release_file:
                    release.dump(release_file)
                release_metadata = PublishedMetadata(
                    relative_path=release_path,
                    publication=publication,
                    file=File(open(release_path, 'rb')),
                )
                release_metadata.save()

            if publisher.structured:
                raise NotImplementedError(
                    "Structured publishing is not yet implemented.")

    log.info(
        _('Publication: {publication} created').format(
            publication=publication.pk))
Ejemplo n.º 27
0
def publish(repository_version_pk, simple=False, structured=False):
    """
    Use provided publisher to create a Publication based on a RepositoryVersion.

    Args:
        repository_version_pk (str): Create a publication from this repository version.
        simple (bool): Create a simple publication with all packages contained in default/all.
        structured (bool): Create a structured publication with releases and components.
            (Not yet implemented)

    """
    repo_version = RepositoryVersion.objects.get(pk=repository_version_pk)

    log.info(
        _("Publishing: repository={repo}, version={ver}, simple={simple}, structured={structured}"
          ).format(  # noqa
              repo=repo_version.repository.name,
              ver=repo_version.number,
              simple=simple,
              structured=structured,
          ))
    with WorkingDirectory():
        with DebPublication.create(repo_version,
                                   pass_through=False) as publication:
            publication.simple = simple
            publication.structured = structured
            if simple:
                repository = repo_version.repository
                release = deb822.Release()
                # TODO: release['Label']
                release["Codename"] = "default"
                release["Components"] = "all"
                release["Architectures"] = ""
                if repository.description:
                    release["Description"] = repository.description
                release["MD5sum"] = []
                release["SHA1"] = []
                release["SHA256"] = []
                release["SHA512"] = []
                package_index_files = {}
                for package in Package.objects.filter(
                        pk__in=repo_version.content.order_by("-pulp_created")):
                    published_artifact = PublishedArtifact(
                        relative_path=package.filename(),
                        publication=publication,
                        content_artifact=package.contentartifact_set.get(),
                    )
                    published_artifact.save()
                    if package.architecture not in package_index_files:
                        package_index_path = os.path.join(
                            "dists",
                            "default",
                            "all",
                            "binary-{}".format(package.architecture),
                            "Packages",
                        )
                        os.makedirs(os.path.dirname(package_index_path),
                                    exist_ok=True)
                        package_index_files[package.architecture] = (
                            open(package_index_path, "wb"),
                            package_index_path,
                        )
                    package_serializer = Package822Serializer(
                        package, context={"request": None})
                    package_serializer.to822("all").dump(
                        package_index_files[package.architecture][0])
                    package_index_files[package.architecture][0].write(b"\n")
                for (package_index_file,
                     package_index_path) in package_index_files.values():
                    package_index_file.close()
                    gz_package_index_path = _zip_file(package_index_path)
                    _add_to_release(release, package_index_path)
                    _add_to_release(release, gz_package_index_path)

                    package_index = PublishedMetadata.create_from_file(
                        publication=publication,
                        file=File(open(package_index_path, "rb")))
                    package_index.save()
                    gz_package_index = PublishedMetadata.create_from_file(
                        publication=publication,
                        file=File(open(gz_package_index_path, "rb")))
                    gz_package_index.save()
                release["Architectures"] = ", ".join(
                    package_index_files.keys())
                release_path = os.path.join("dists", "default", "Release")
                os.makedirs(os.path.dirname(release_path), exist_ok=True)
                with open(release_path, "wb") as release_file:
                    release.dump(release_file)
                release_metadata = PublishedMetadata.create_from_file(
                    publication=publication,
                    file=File(open(release_path, "rb")))
                release_metadata.save()

            if structured:
                raise NotImplementedError(
                    "Structured publishing is not yet implemented.")

    log.info(
        _("Publication: {publication} created").format(
            publication=publication.pk))
Ejemplo n.º 28
0
    async def run(self):
        """
        Parse ReleaseFile content units.

        Update release content with information obtained from its artifact.
        """
        with ProgressReport(message="Update ReleaseFile units",
                            code="update.release_file") as pb:
            async for d_content in self.items():
                if isinstance(d_content.content, ReleaseFile):
                    release_file = d_content.content
                    da_names = {
                        os.path.basename(da.relative_path): da
                        for da in d_content.d_artifacts
                    }
                    if "Release" in da_names:
                        if "Release.gpg" in da_names:
                            if self.gpgkey:
                                with NamedTemporaryFile() as tmp_file:
                                    tmp_file.write(da_names["Release"].
                                                   artifact.file.read())
                                    tmp_file.flush()
                                    verified = self.gpg.verify_file(
                                        da_names["Release.gpg"].artifact.file,
                                        tmp_file.name)
                                if verified.valid:
                                    log.info(
                                        "Verification of Release successful.")
                                    release_file_artifact = da_names[
                                        "Release"].artifact
                                    release_file.relative_path = da_names[
                                        "Release"].relative_path
                                else:
                                    log.warn(
                                        "Verification of Release failed. Dropping it."
                                    )
                                    d_content.d_artifacts.remove(
                                        da_names.pop("Release"))
                                    d_content.d_artifacts.remove(
                                        da_names.pop("Release.gpg"))
                            else:
                                release_file_artifact = da_names[
                                    "Release"].artifact
                                release_file.relative_path = da_names[
                                    "Release"].relative_path
                        else:
                            if self.gpgkey:
                                d_content.d_artifacts.delete(
                                    da_names["Release"])
                            else:
                                release_file_artifact = da_names[
                                    "Release"].artifact
                                release_file.relative_path = da_names[
                                    "Release"].relative_path
                    else:
                        if "Release.gpg" in da_names:
                            # No need to keep the signature without "Release"
                            d_content.d_artifacts.remove(
                                da_names.pop("Release.gpg"))

                    if "InRelease" in da_names:
                        if self.gpgkey:
                            verified = self.gpg.verify_file(
                                da_names["InRelease"].artifact.file)
                            if verified.valid:
                                log.info(
                                    "Verification of InRelease successful.")
                                release_file_artifact = da_names[
                                    "InRelease"].artifact
                                release_file.relative_path = da_names[
                                    "InRelease"].relative_path
                            else:
                                log.warn(
                                    "Verification of InRelease failed. Dropping it."
                                )
                                d_content.d_artifacts.remove(
                                    da_names.pop("InRelease"))
                        else:
                            release_file_artifact = da_names[
                                "InRelease"].artifact
                            release_file.relative_path = da_names[
                                "InRelease"].relative_path

                    if not d_content.d_artifacts:
                        # No (proper) artifacts left -> distribution not found
                        raise NoReleaseFile(
                            distribution=release_file.distribution)

                    release_file.sha256 = release_file_artifact.sha256
                    release_file_dict = deb822.Release(
                        release_file_artifact.file)
                    release_file.codename = release_file_dict["Codename"]
                    if "suite" in release_file_dict:
                        release_file.suite = release_file_dict.get("Suite")
                    # TODO split of extra stuff e.g. : 'updates/main' -> 'main'
                    release_file.components = release_file_dict["Components"]
                    release_file.architectures = release_file_dict[
                        "Architectures"]
                    log.debug("Codename: {}".format(release_file.codename))
                    log.debug("Components: {}".format(release_file.components))
                    log.debug("Architectures: {}".format(
                        release_file.architectures))
                    pb.increment()
                await self.put(d_content)
Ejemplo n.º 29
0
def write_release_file(path, meta_data, release_meta_files):
    """
    Writes a 'Release' file for an apt repository.
    This function assumes the file ":path:/Release" does not exist.

    :param path: the path to the folder where the 'Release' file will be placed
    :param meta_data: a dict containing the needed meta data
    :param release_meta_files: a list of paths to files to be included
    :returns: the path to the 'Release' file
    """
    output_file_path = os.path.join(path, 'Release')

    # Ordered list of supported non-checksum fields (tuples):
    # Known to exist but currently unsupported fields include:
    # "Acquire-By-Hash" (after 'date')
    fields = [
        ('origin', 'Origin'),
        ('label', 'Label'),
        ('suite', 'Suite'),
        ('version', 'Version'),
        ('codename', 'Codename'),
        ('changelogs', 'Changelogs'),
        ('date', 'Date'),
        ('architectures', 'Architectures'),
        ('components', 'Components'),
        ('description', 'Description'),
    ]
    # Ordered list of supported checksum fields (tuples):
    checksum_fields = [
        ('md5sum', 'MD5sum'),
        ('sha1', 'SHA1'),
        ('sha256', 'SHA256'),
    ]

    # Amend or add incomplete fields:
    meta_data['architectures'] = " ".join(meta_data['architectures'])
    meta_data['components'] = " ".join(meta_data['components'])
    meta_data['date'] = strftime('%a, %d %b %Y %H:%M:%S +0000', gmtime())

    # Initialize deb822 object:
    release = deb822.Release()

    # Translate meta_data to deb822 for all fields (without checksum_fields):
    for field in fields:
        if field[0] in meta_data:
            release[field[1]] = meta_data[field[0]]

    # Initialize the needed deb822 checksum fields:
    release['MD5sum'] = []
    release['SHA1'] = []
    release['SHA256'] = []

    # Add the checksum fields to the deb822 object:
    for file_path in release_meta_files:
        checksums = DebPackage.calculate_deb_checksums(file_path)
        file_size = os.path.getsize(file_path)
        relative_path = os.path.relpath(file_path, path)
        for checksum_type in checksum_fields:
            release[checksum_type[1]].append({checksum_type[0]: checksums[checksum_type[0]],
                                              'size': file_size,
                                              'name': relative_path})

    # Write the deb822 object to a file:
    with open(output_file_path, "wb") as release_file:
        release.dump(release_file)

    return output_file_path
Ejemplo n.º 30
0
    async def _handle_distribution(self, distribution):
        log.info(
            _('Downloading Release file for distribution: "{}"').format(
                distribution))
        # Create release_file
        if distribution[-1] == "/":
            release_file_dir = distribution.strip("/")
        else:
            release_file_dir = os.path.join("dists", distribution)
        release_file_dc = DeclarativeContent(
            content=ReleaseFile(distribution=distribution),
            d_artifacts=[
                self._to_d_artifact(os.path.join(release_file_dir, filename))
                for filename in ["Release", "InRelease", "Release.gpg"]
            ],
        )
        release_file = await self._create_unit(release_file_dc)
        if release_file is None:
            return
        # Create release object
        release_unit = Release(codename=release_file.codename,
                               suite=release_file.suite,
                               distribution=distribution)
        release_dc = DeclarativeContent(content=release_unit)
        release = await self._create_unit(release_dc)
        # Create release architectures
        if release_file.architectures:
            architectures = _filter_split_architectures(
                release_file.architectures, self.remote.architectures,
                distribution)
        elif distribution[-1] == "/":
            message = (
                "The ReleaseFile content unit architecrures are unset for the flat repo with "
                "distribution '{}'. ReleaseArchitecture content creation is deferred!"
            )
            log.warning(_(message).format(distribution))
            architectures = []

        for architecture in architectures:
            release_architecture_dc = DeclarativeContent(
                content=ReleaseArchitecture(architecture=architecture,
                                            release=release))
            await self.put(release_architecture_dc)
        # Parse release file
        log.info(
            _('Parsing Release file at distribution="{}"').format(
                distribution))
        release_artifact = await _get_main_artifact_blocking(release_file)
        release_file_dict = deb822.Release(release_artifact.file)

        # Retrieve and interpret any 'No-Support-for-Architecture-all' value:
        # We will refer to the presence of 'No-Support-for-Architecture-all: Packages' in a Release
        # file as indicating "hybrid format". For more info, see:
        # https://wiki.debian.org/DebianRepository/Format#No-Support-for-Architecture-all
        no_support_for_arch_all = release_file_dict.get(
            "No-Support-for-Architecture-all", "")
        if no_support_for_arch_all.strip() == "Packages":
            hybrid_format = True
        elif not no_support_for_arch_all:
            hybrid_format = False
        else:
            raise UnknownNoSupportForArchitectureAllValue(
                release_file.relative_path, no_support_for_arch_all)

        # collect file references in new dict
        file_references = defaultdict(deb822.Deb822Dict)
        for digest_name in ["SHA512", "SHA256", "SHA1", "MD5sum"]:
            if digest_name in release_file_dict:
                for unit in release_file_dict[digest_name]:
                    file_references[unit["Name"]].update(unit)

        if distribution[-1] == "/":
            # Handle flat repo
            sub_tasks = [
                self._handle_flat_repo(file_references, release_file, release)
            ]
        else:
            # Handle components
            sub_tasks = [
                self._handle_component(
                    component,
                    release,
                    release_file,
                    file_references,
                    architectures,
                    hybrid_format,
                ) for component in _filter_split_components(
                    release_file.components, self.remote.components,
                    distribution)
            ]
        await asyncio.gather(*sub_tasks)