← Back to team overview

launchpad-reviewers team mailing list archive

Re: [Merge] lp:~cjwatson/launchpad/archive-file-model into lp:launchpad

 

Review: Approve code



Diff comments:

> 
> === added file 'lib/lp/soyuz/model/archivefile.py'
> --- lib/lp/soyuz/model/archivefile.py	1970-01-01 00:00:00 +0000
> +++ lib/lp/soyuz/model/archivefile.py	2016-03-17 14:39:54 +0000
> @@ -0,0 +1,143 @@
> +# Copyright 2016 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""A file in an archive."""
> +
> +from __future__ import absolute_import, print_function, unicode_literals
> +
> +__metaclass__ = type
> +__all__ = [
> +    'ArchiveFile',
> +    'ArchiveFileSet',
> +    ]
> +
> +import os.path
> +
> +import pytz
> +from storm.locals import (
> +    DateTime,
> +    Int,
> +    Reference,
> +    Storm,
> +    Unicode,
> +    )
> +from zope.component import getUtility
> +from zope.interface import implementer
> +
> +from lp.services.database.bulk import load_related
> +from lp.services.database.constants import UTC_NOW
> +from lp.services.database.decoratedresultset import DecoratedResultSet
> +from lp.services.database.interfaces import (
> +    IMasterStore,
> +    IStore,
> +    )
> +from lp.services.librarian.interfaces import ILibraryFileAliasSet
> +from lp.services.librarian.model import (
> +    LibraryFileAlias,
> +    LibraryFileContent,
> +    )
> +from lp.soyuz.interfaces.archivefile import (
> +    IArchiveFile,
> +    IArchiveFileSet,
> +    )
> +
> +
> +@implementer(IArchiveFile)
> +class ArchiveFile(Storm):
> +    """See `IArchiveFile`."""
> +
> +    __storm_table__ = 'ArchiveFile'
> +
> +    id = Int(primary=True)
> +
> +    archive_id = Int(name='archive', allow_none=False)
> +    archive = Reference(archive_id, 'Archive.id')
> +
> +    container = Unicode(name='container', allow_none=False)
> +
> +    path = Unicode(name='path', allow_none=False)
> +
> +    library_file_id = Int(name='library_file', allow_none=False)
> +    library_file = Reference(library_file_id, 'LibraryFileAlias.id')
> +
> +    scheduled_deletion_date = DateTime(
> +        name='scheduled_deletion_date', tzinfo=pytz.UTC, allow_none=True)
> +
> +    def __init__(self, archive, container, path, library_file):
> +        """Construct an `ArchiveFile`."""
> +        super(ArchiveFile, self).__init__()
> +        self.archive = archive
> +        self.container = container
> +        self.path = path
> +        self.library_file = library_file
> +        self.scheduled_deletion_date = None
> +
> +
> +@implementer(IArchiveFileSet)
> +class ArchiveFileSet:
> +    """See `IArchiveFileSet`."""
> +
> +    @staticmethod
> +    def new(archive, container, path, library_file):
> +        """See `IArchiveFileSet`."""
> +        archive_file = ArchiveFile(archive, container, path, library_file)
> +        IMasterStore(ArchiveFile).add(archive_file)
> +        return archive_file
> +
> +    @classmethod
> +    def newFromFile(cls, archive, container, root, path, size, content_type):

Should this take a file-like object rather than a root?

> +        with open(os.path.join(root, path), "rb") as f:
> +            library_file = getUtility(ILibraryFileAliasSet).create(
> +                os.path.basename(path), size, f, content_type,
> +                restricted=archive.private)
> +        return cls.new(archive, container, path, library_file)
> +
> +    @staticmethod
> +    def getByArchive(archive, container=None, eager_load=False):
> +        """See `IArchiveFileSet`."""
> +        clauses = [ArchiveFile.archive == archive]
> +        # XXX cjwatson 2016-03-15: We'll need some more sophisticated way to
> +        # match containers once we're using them for custom uploads.
> +        if container is not None:
> +            clauses.append(ArchiveFile.container == container)
> +        archive_files = IStore(ArchiveFile).find(ArchiveFile, *clauses)
> +
> +        def eager_load(rows):
> +            lfas = load_related(LibraryFileAlias, rows, ["library_file_id"])
> +            load_related(LibraryFileContent, lfas, ["contentID"])
> +
> +        if eager_load:
> +            return DecoratedResultSet(archive_files, pre_iter_hook=eager_load)
> +        else:
> +            return archive_files
> +
> +    @staticmethod
> +    def scheduleDeletion(archive_files, stay_of_execution):
> +        """See `IArchiveFileSet`."""
> +        archive_file_ids = set(
> +            archive_file.id for archive_file in archive_files)
> +        rows = IMasterStore(ArchiveFile).find(
> +            ArchiveFile, ArchiveFile.id.is_in(archive_file_ids))
> +        rows.set(scheduled_deletion_date=UTC_NOW + stay_of_execution)
> +
> +    @staticmethod
> +    def getContainersToReap(archive, container_prefix=None):
> +        clauses = [
> +            ArchiveFile.archive == archive,
> +            ArchiveFile.scheduled_deletion_date < UTC_NOW,
> +            ]
> +        if container_prefix is not None:
> +            clauses.append(ArchiveFile.container.startswith(container_prefix))
> +        return IStore(ArchiveFile).find(
> +            ArchiveFile.container, *clauses).group_by(ArchiveFile.container)
> +
> +    @staticmethod
> +    def reap(archive, container=None):
> +        """See `IArchiveFileSet`."""
> +        clauses = [
> +            ArchiveFile.archive == archive,
> +            ArchiveFile.scheduled_deletion_date < UTC_NOW,
> +            ]
> +        if container is not None:
> +            clauses.append(ArchiveFile.container == container)
> +        IMasterStore(ArchiveFile).find(ArchiveFile, *clauses).remove()


-- 
https://code.launchpad.net/~cjwatson/launchpad/archive-file-model/+merge/289376
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.


References