root/releases/pkgcore-checks/0.3/pkgcore_checks/pkgdir_checks.py @ ferringb%2540gmail.com-20070207174621-yb3eqrqc6jtmdgse

Revision ferringb%2540gmail.com-20070207174621-yb3eqrqc6jtmdgse, 5.9 KB (checked in by Brian Harring <ferringb@…>, 2 years ago)

kill off to_str, no longer used; use short_desc and long_desc properties instead

Line 
1# Copyright: 2006 Brian Harring <ferringb@gmail.com>
2# License: GPL2
3
4from pkgcore.util.compatibility import any
5from collections import deque
6from pkgcore.util.demandload import demandload
7demandload(globals(), "pkgcore.util.xml:escape")
8import codecs, errno
9
10from pkgcore_checks.base import Result, Template, package_feed
11
12import os, stat
13pjoin = os.path.join
14
15
16allowed_filename_chars = "a-zA-Z0-9._-+:"
17allowed_filename_chars_set = set()
18allowed_filename_chars_set.update(chr(x) for x in xrange(ord('a'), ord('z')+1))
19allowed_filename_chars_set.update(chr(x) for x in xrange(ord('A'), ord('Z')+1))
20allowed_filename_chars_set.update(chr(x) for x in xrange(ord('0'), ord('9')+1))
21allowed_filename_chars_set.update([".", "-", "_", "+", ":"])
22
23
24class MissingFile(Result):
25    """pkg is missing an expected file entry"""
26
27    __slots__ = ("category", "package", "filename")
28
29    threshold = package_feed
30   
31    def __init__(self, pkg, filename):
32        Result.__init__(self)
33        self._store_cp(pkg)
34        self.filename = filename
35
36    @property
37    def short_desc(self):
38        return "required file %s doesn't exist" % self.filename
39   
40
41class ExecutableFile(Result):
42    """file has executable bit, but doesn't need it"""
43
44    __slots__ = ("category", "package", "filename")
45
46    threshold = package_feed
47   
48    def __init__(self, pkg, filename):
49        Result.__init__(self)
50        self._store_cp(pkg)
51        self.filename = filename
52   
53    @property
54    def short_desc(self):
55        return "file %s has unecessary executable bit" % self.filename
56   
57
58class SizeViolation(Result):
59    """filesdir, excluding digest/cvs, is too large"""
60
61    __slots__ = ("category", "package", "size")
62
63    threshold = package_feed
64   
65    def __init__(self, pkg, size):
66        Result.__init__(self)
67        self._store_cp(pkg)
68        self.size = size
69   
70    @property
71    def short_desc(self):
72        return "files directory exceeds 20k; %i bytes total" % self.size
73
74
75class Glep31Violation(Result):
76
77    """file doesn't abide by glep31 requirements"""
78   
79    __slots__ = ("category", "package", "filename")
80
81    threshold = package_feed
82   
83    def __init__(self, pkg, filename):
84        Result.__init__(self)
85        self._store_cp(pkg)
86        self.filename = filename
87   
88    @property
89    def short_desc(self):
90        return "file %s has char outside the allowed char ranges defined by " \
91            "glep31" % self.filename
92
93
94class InvalidUtf8(Result):
95
96    """file isn't utf8 compliant"""
97   
98    __slots__ = ("category", "package", "filename", "err")
99
100    threshold = package_feed
101   
102    def __init__(self, pkg, filename, err):
103        Result.__init__(self)
104        self._store_cp(pkg)
105        self.filename = filename
106        self.err = err
107   
108    @property
109    def short_desc(self):
110        return "file %s is not valid utf8- %s" % (self.filename, self.err)
111
112
113def utf8_check(pkg, base, filename, reporter):
114    try:
115        codecs.open(pjoin(base, filename), mode="rb",
116            encoding="utf8", buffering=8192).read()
117    except UnicodeDecodeError, e:
118        reporter.add_report(InvalidUtf8(pkg, filename, str(e)))
119        del e
120
121
122class PkgDirReport(Template):
123    """actual ebuild directory scans; file size, glep31 rule enforcement."""
124
125    feed_type = package_feed
126   
127    ignore_dirs = set(["cvs", ".svn", ".bzr"])
128    known_results = (MissingFile, ExecutableFile, SizeViolation,
129        Glep31Violation, InvalidUtf8)
130
131    def feed(self, pkgset, reporter):
132        base = os.path.dirname(pkgset[0].ebuild.get_path())
133        # note we don't use os.walk, we need size info also
134        for filename in os.listdir(base):
135            # while this may seem odd, written this way such that the
136            # filtering happens all in the genexp.  if the result was being
137            # handed to any, it's a frame switch each
138            # char, which adds up.
139           
140            if any(True for x in filename if
141                x not in allowed_filename_chars_set):
142                reporter.add_report(Glep31Violation(pkgset[0], filename))
143           
144            if filename.endswith(".ebuild") or filename in \
145                ("Manifest", "ChangeLog", "metadata.xml"):
146                if os.stat(pjoin(base, filename)).st_mode & 0111:
147                    reporter.add_report(ExecutableFile(pkgset[0], filename))
148           
149            if filename.endswith(".ebuild"):
150                utf8_check(pkgset[0], base, filename, reporter)
151
152        try:
153            utf8_check(pkgset[0], base, "ChangeLog", reporter)
154        except IOError, e:
155            if e.errno != errno.ENOENT:
156                raise
157            del e
158            reporter.add_report(MissingFile(pkgset[0], "ChangeLog"))
159               
160        if not os.path.exists(pjoin(base, "files")):
161            reporter.add_report(MissingFile(pkgset[0], "files"))
162            return
163                           
164        size = 0
165        unprocessed_dirs = deque(["files"])
166        while unprocessed_dirs:
167            cwd = unprocessed_dirs.pop()
168            for fn in os.listdir(pjoin(base, cwd)):
169                afn = pjoin(base, cwd, fn)
170                st = os.lstat(afn)
171
172                if stat.S_ISDIR(st.st_mode):
173                    if fn not in self.ignore_dirs:
174                        unprocessed_dirs.append(pjoin(cwd, fn))
175
176                elif stat.S_ISREG(st.st_mode):
177                    if st.st_mode & 0111:
178                        reporter.add_report(ExecutableFile(pkgset[0],
179                                                           pjoin(cwd, fn)))
180                    if not fn.startswith("digest-"):
181                        size += st.st_size
182                        if any(True for x in fn if
183                            x not in allowed_filename_chars_set):
184                            reporter.add_report(Glep31Violation(pkgset[0],
185                                pjoin(cwd, fn)))
186
187                # yes, we silently ignore others.
188        if size > 20480:
189            reporter.add_report(SizeViolation(pkgset[0], size))
Note: See TracBrowser for help on using the browser.