~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# Copyright 2009 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

__metaclass__ = type
__all__ = [
    'copy_and_close',
    'filechunks',
    'guess_librarian_encoding',
    'sha1_from_path',
    ]


import hashlib

MEGABYTE = 1024*1024


def filechunks(file, chunk_size=4*MEGABYTE):
    """Return an iterator which reads chunks of the given file."""
    return iter(lambda: file.read(chunk_size), '')


def copy_and_close(from_file, to_file):
    """Copy from_file to to_file and close both.

    It requires both arguments to be opened file-like objects.
    'filechunks' trick is used reduce the buffers memory demanded
    when handling large files.
    It's suitable to copy contents from ILibraryFileAlias instances to the
    local filesystem.
    Both file_descriptors are closed before return.
    """
    for chunk in filechunks(from_file):
        to_file.write(chunk)
    from_file.close()
    to_file.close()


def sha1_from_path(path):
    """Return the hexdigest SHA1 for the contents of the path."""
    the_file = open(path)
    the_hash = hashlib.sha1()

    for chunk in filechunks(the_file):
        the_hash.update(chunk)

    the_file.close()

    return the_hash.hexdigest()


def guess_librarian_encoding(filename, mimetype):
    """Return the appropriate encoding for the given filename and mimetype.

    Files with the following extensions will be served as
    'Content-Encoding: gzip' and 'Content-Type: text/plain',
    which indicates to browsers that, after being unzipped,
    their contents can be rendered inline.

    * 'txt.gz': gzipped sources buildlogs;
    * 'diff.gz': gzipped sources diffs;

    :param filename: string containing the filename to be guessed;
    :param mimetype: string containing the stored mimetype;

    :return: a tuple containing the appropriate 'encoding' and 'mimetype'
        that should be used to serve the file.
    """
    if filename.endswith('txt.gz'):
        encoding = 'gzip'
        mimetype = 'text/plain'
    elif filename.endswith('diff.gz'):
        encoding = 'gzip'
        mimetype = 'text/plain'
    else:
        encoding = None
        mimetype = mimetype.encode('ascii')

    return encoding, mimetype