21cadc3f52b1ebb4b89c6d951551e964bfc23922
[portage.git] / pym / portage / package / ebuild / digestcheck.py
1 # Copyright 2010-2011 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 __all__ = ['digestcheck']
5
6 import warnings
7
8 from portage import os, _encodings, _unicode_decode
9 from portage.exception import DigestException, FileNotFound
10 from portage.localization import _
11 from portage.manifest import Manifest
12 from portage.output import EOutput
13 from portage.util import writemsg
14
15 def digestcheck(myfiles, mysettings, strict=False, justmanifest=None):
16         """
17         Verifies checksums. Assumes all files have been downloaded.
18         @rtype: int
19         @returns: 1 on success and 0 on failure
20         """
21
22         if justmanifest is not None:
23                 warnings.warn("The justmanifest parameter of the " + \
24                         "portage.package.ebuild.digestcheck.digestcheck()" + \
25                         " function is now unused.",
26                         DeprecationWarning, stacklevel=2)
27                 justmanifest = None
28
29         if mysettings.get("EBUILD_SKIP_MANIFEST") == "1":
30                 return 1
31         allow_missing = "allow-missing-manifests" in mysettings.features
32         pkgdir = mysettings["O"]
33         manifest_path = os.path.join(pkgdir, "Manifest")
34         if not os.path.exists(manifest_path):
35                 if allow_missing:
36                         return 1
37                 writemsg(_("!!! Manifest file not found: '%s'\n") % manifest_path,
38                         noiselevel=-1)
39                 if strict:
40                         return 0
41                 else:
42                         return 1
43         mf = Manifest(pkgdir, mysettings["DISTDIR"])
44         manifest_empty = True
45         for d in mf.fhashdict.values():
46                 if d:
47                         manifest_empty = False
48                         break
49         if manifest_empty:
50                 writemsg(_("!!! Manifest is empty: '%s'\n") % manifest_path,
51                         noiselevel=-1)
52                 if strict:
53                         return 0
54                 else:
55                         return 1
56         eout = EOutput()
57         eout.quiet = mysettings.get("PORTAGE_QUIET", None) == "1"
58         try:
59                 if strict and "PORTAGE_PARALLEL_FETCHONLY" not in mysettings:
60                         eout.ebegin(_("checking ebuild checksums ;-)"))
61                         mf.checkTypeHashes("EBUILD")
62                         eout.eend(0)
63                         eout.ebegin(_("checking auxfile checksums ;-)"))
64                         mf.checkTypeHashes("AUX")
65                         eout.eend(0)
66                         eout.ebegin(_("checking miscfile checksums ;-)"))
67                         mf.checkTypeHashes("MISC", ignoreMissingFiles=True)
68                         eout.eend(0)
69                 for f in myfiles:
70                         eout.ebegin(_("checking %s ;-)") % f)
71                         ftype = mf.findFile(f)
72                         if ftype is None:
73                                 eout.eend(1)
74                                 writemsg(_("\n!!! Missing digest for '%s'\n") % (f,),
75                                         noiselevel=-1)
76                                 return 0
77                         mf.checkFileHashes(ftype, f)
78                         eout.eend(0)
79         except FileNotFound as e:
80                 eout.eend(1)
81                 writemsg(_("\n!!! A file listed in the Manifest could not be found: %s\n") % str(e),
82                         noiselevel=-1)
83                 return 0
84         except DigestException as e:
85                 eout.eend(1)
86                 writemsg(_("\n!!! Digest verification failed:\n"), noiselevel=-1)
87                 writemsg("!!! %s\n" % e.value[0], noiselevel=-1)
88                 writemsg(_("!!! Reason: %s\n") % e.value[1], noiselevel=-1)
89                 writemsg(_("!!! Got: %s\n") % e.value[2], noiselevel=-1)
90                 writemsg(_("!!! Expected: %s\n") % e.value[3], noiselevel=-1)
91                 return 0
92         if allow_missing:
93                 # In this case we ignore any missing digests that
94                 # would otherwise be detected below.
95                 return 1
96         # Make sure that all of the ebuilds are actually listed in the Manifest.
97         for f in os.listdir(pkgdir):
98                 pf = None
99                 if f[-7:] == '.ebuild':
100                         pf = f[:-7]
101                 if pf is not None and not mf.hasFile("EBUILD", f):
102                         writemsg(_("!!! A file is not listed in the Manifest: '%s'\n") % \
103                                 os.path.join(pkgdir, f), noiselevel=-1)
104                         if strict:
105                                 return 0
106         # epatch will just grab all the patches out of a directory, so we have to
107         # make sure there aren't any foreign files that it might grab.
108         filesdir = os.path.join(pkgdir, "files")
109
110         for parent, dirs, files in os.walk(filesdir):
111                 try:
112                         parent = _unicode_decode(parent,
113                                 encoding=_encodings['fs'], errors='strict')
114                 except UnicodeDecodeError:
115                         parent = _unicode_decode(parent,
116                                 encoding=_encodings['fs'], errors='replace')
117                         writemsg(_("!!! Path contains invalid "
118                                 "character(s) for encoding '%s': '%s'") \
119                                 % (_encodings['fs'], parent), noiselevel=-1)
120                         if strict:
121                                 return 0
122                         continue
123                 for d in dirs:
124                         d_bytes = d
125                         try:
126                                 d = _unicode_decode(d,
127                                         encoding=_encodings['fs'], errors='strict')
128                         except UnicodeDecodeError:
129                                 d = _unicode_decode(d,
130                                         encoding=_encodings['fs'], errors='replace')
131                                 writemsg(_("!!! Path contains invalid "
132                                         "character(s) for encoding '%s': '%s'") \
133                                         % (_encodings['fs'], os.path.join(parent, d)),
134                                         noiselevel=-1)
135                                 if strict:
136                                         return 0
137                                 dirs.remove(d_bytes)
138                                 continue
139                         if d.startswith(".") or d == "CVS":
140                                 dirs.remove(d_bytes)
141                 for f in files:
142                         try:
143                                 f = _unicode_decode(f,
144                                         encoding=_encodings['fs'], errors='strict')
145                         except UnicodeDecodeError:
146                                 f = _unicode_decode(f,
147                                         encoding=_encodings['fs'], errors='replace')
148                                 if f.startswith("."):
149                                         continue
150                                 f = os.path.join(parent, f)[len(filesdir) + 1:]
151                                 writemsg(_("!!! File name contains invalid "
152                                         "character(s) for encoding '%s': '%s'") \
153                                         % (_encodings['fs'], f), noiselevel=-1)
154                                 if strict:
155                                         return 0
156                                 continue
157                         if f.startswith("."):
158                                 continue
159                         f = os.path.join(parent, f)[len(filesdir) + 1:]
160                         file_type = mf.findFile(f)
161                         if file_type != "AUX" and not f.startswith("digest-"):
162                                 writemsg(_("!!! A file is not listed in the Manifest: '%s'\n") % \
163                                         os.path.join(filesdir, f), noiselevel=-1)
164                                 if strict:
165                                         return 0
166         return 1