d8cc22f5cec80e65bfb51462ab57193963138bb3
[~helmut/debian-dedup.git] / dedup / debpkg.py
1 from debian import deb822
2
3 from dedup.hashing import hash_file
4
5 def process_control(control_contents):
6     """Parses the contents of a control file from a control.tar.gz of a Debian
7     package and returns a dictionary containing the fields relevant to dedup.
8     @type control_contents: bytes
9     @rtype: {str: object}
10     """
11     control = deb822.Packages(control_contents)
12     package = control["package"].encode("ascii")
13     try:
14         source = control["source"].encode("ascii").split()[0]
15     except KeyError:
16         source = package
17     version = control["version"].encode("ascii")
18     architecture = control["architecture"].encode("ascii")
19
20     depends = set(dep[0]["name"].encode("ascii")
21                   for dep in control.relations.get("depends", ())
22                   if len(dep) == 1)
23     return dict(package=package, source=source, version=version,
24                 architecture=architecture, depends=depends)
25
26 class MultiHash(object):
27     def __init__(self, *hashes):
28         self.hashes = hashes
29
30     def update(self, data):
31         for hasher in self.hashes:
32             hasher.update(data)
33
34 def get_tar_hashes(tar, hash_functions):
35     """Given a TarFile read all regular files and compute all of the given hash
36     functions on each file.
37     @type tar: tarfile.TarFile
38     @param hash_functions: a sequence of parameter-less functions each creating a
39             new hashlib-like object
40     @rtype: gen((str, int, {str: str}}
41     @returns: an iterable of (filename, filesize, hashes) tuples where
42             hashes is a dict mapping hash function names to hash values
43     """
44
45     for elem in tar:
46         if not elem.isreg(): # excludes hard links as well
47             continue
48         hasher = MultiHash(*[func() for func in hash_functions])
49         hasher = hash_file(hasher, tar.extractfile(elem))
50         hashes = {}
51         for hashobj in hasher.hashes:
52             hashvalue = hashobj.hexdigest()
53             if hashvalue:
54                 hashes[hashobj.name] = hashvalue
55         yield (elem.name, elem.size, hashes)