]>
Commit | Line | Data |
---|---|---|
03861ee2 ER |
1 | #!/usr/bin/env python |
2 | # vi: encoding=utf-8 ts=8 sts=4 sw=4 et | |
3 | ||
c88699b9 | 4 | import sys, os, re |
66a58132 | 5 | import getopt |
03861ee2 ER |
6 | import subprocess |
7 | sys.path.insert(0, os.environ['HOME']+'/pld-ftp-admin/modules') | |
8 | import ftptree | |
9 | from common import checkdir | |
10 | import ftpio | |
11 | ||
66a58132 | 12 | try: |
cb260c8e | 13 | opts, args = getopt.getopt(sys.argv[1:], 'qso:', [ "quiet" ]) |
66a58132 ER |
14 | except getopt.GetoptError: |
15 | print >>sys.stderr, "ERR: options error" | |
16 | print >>sys.stderr, "rpmlint.py tree package1 [package2...]" | |
17 | sys.exit(1) | |
18 | ||
19 | quiet = False | |
413b382d | 20 | show = False |
cb260c8e | 21 | outstream = sys.stdout |
66a58132 ER |
22 | for o, a in opts: |
23 | if o == "-q" or o == "--quiet": | |
24 | quiet = True | |
413b382d ER |
25 | if o == "-s": |
26 | show = True | |
cb260c8e ER |
27 | if o == "-o": |
28 | outstream = open(a, 'w') | |
66a58132 ER |
29 | |
30 | if len(args) < 1: | |
31 | print >>sys.stderr, "ERR: missing tree name" | |
03861ee2 ER |
32 | print >>sys.stderr, "rpmlint.py tree package1 [package2...]" |
33 | sys.exit(1) | |
34 | ||
66a58132 ER |
35 | treename = args[0] |
36 | packages = args[1:] | |
37 | ||
38 | checkdir(treename) | |
03861ee2 ER |
39 | |
40 | ftpio.connect('rpmlint') | |
41 | ||
66a58132 ER |
42 | if not ftpio.lock(treename, True): |
43 | print >>sys.stderr, "ERR: %s tree already locked" % treename | |
03861ee2 ER |
44 | sys.exit(1) |
45 | ||
46 | files = [] | |
47 | try: | |
66a58132 | 48 | if len(packages) < 1: |
7e771c27 ER |
49 | loadall = True |
50 | else: | |
51 | loadall = False | |
52 | ||
53 | # if no files specified, grab whole tree contents | |
66a58132 | 54 | tree = ftptree.FtpTree(treename, loadall = loadall) |
413b382d | 55 | tree.do_checkbuild = False |
7e771c27 ER |
56 | if loadall: |
57 | # this is hack, should be a param, not access private .loadedpkgs element | |
58 | tree.mark4moving(tree.loadedpkgs) | |
59 | else: | |
66a58132 | 60 | tree.mark4moving(packages) |
03861ee2 ER |
61 | files = tree.rpmfiles(debugfiles = False, sourcefiles = False) |
62 | ||
5a13eb89 | 63 | except (ftptree.SomeError, KeyboardInterrupt), e: |
03861ee2 | 64 | # In case of problems we need to unlock the tree before exiting |
66a58132 | 65 | ftpio.unlock(treename) |
03861ee2 ER |
66 | sys.exit(1) |
67 | ||
66a58132 | 68 | ftpio.unlock(treename) |
03861ee2 | 69 | |
8d0f868f ER |
70 | class LintPkg: |
71 | def __init__(self, cachedir): | |
cb260c8e ER |
72 | self.outstream = sys.stdout |
73 | ||
8d0f868f ER |
74 | # for rpmlint stats |
75 | self.packages = self.specfiles = self.errors = self.warnings = 0 | |
76 | # 1 packages and 0 specfiles checked; 0 errors, 0 warnings. | |
77 | self.lintre = re.compile('(?P<packages>\d+) packages and (?P<specfiles>\d+) specfiles checked; (?P<errors>\d+) errors, (?P<warnings>\d+) warnings.') | |
78 | ||
79 | self._rpmlint = '/usr/bin/rpmlint' | |
80 | ||
81 | self.cachedir = os.path.expanduser(cachedir) | |
82 | if not os.path.isdir(self.cachedir): | |
83 | os.makedirs(self.cachedir) | |
84 | ||
85 | def cachefile(self, file): | |
86 | (dirname, filename) = os.path.split(file) | |
87 | return os.path.join(self.cachedir, filename+'.txt') | |
88 | ||
413b382d | 89 | def get_stats(self, file): |
8d0f868f | 90 | cachefile = self.cachefile(file) |
f809cdb0 ER |
91 | if not os.path.exists(cachefile): |
92 | return None | |
8d0f868f ER |
93 | |
94 | # show last line (that contains status) | |
95 | l = (open(cachefile, 'r').readlines())[-1] | |
96 | m = self.lintre.match(l) | |
97 | if not m: | |
413b382d | 98 | return None |
8d0f868f | 99 | |
413b382d ER |
100 | return { |
101 | 'packages': int(m.group('packages')), | |
102 | 'specfiles': int(m.group('specfiles')), | |
103 | 'errors': int(m.group('errors')), | |
104 | 'warnings': int(m.group('warnings')), | |
105 | } | |
106 | ||
107 | """ | |
108 | update stats from cachefile | |
109 | """ | |
110 | def update_stats(self, file): | |
111 | m = self.get_stats(file) | |
112 | if not m: | |
113 | return False | |
114 | self.packages += m['packages'] | |
115 | self.specfiles += m['specfiles'] | |
116 | self.errors += m['errors'] | |
117 | self.warnings += m['warnings'] | |
8d0f868f ER |
118 | return True |
119 | ||
120 | def print_stats(self, file = None): | |
121 | if file: | |
122 | (dirname, filename) = os.path.split(file) | |
cb260c8e | 123 | print >>self.outstream, "\r\033[0K%d packages and %d specfiles checked; %d errors, %d warnings. [%s]" % (self.packages, self.specfiles, self.errors, self.warnings, filename), |
8d0f868f | 124 | else: |
cb260c8e | 125 | print >>self.outstream, "\r\033[0K%d packages and %d specfiles checked; %d errors, %d warnings." % (self.packages, self.specfiles, self.errors, self.warnings) |
8d0f868f ER |
126 | sys.stdout.flush() |
127 | ||
f809cdb0 | 128 | def cat(self, file): |
cb260c8e | 129 | print >>self.outstream, "".join(open(file, 'r').readlines()) |
f809cdb0 | 130 | |
413b382d ER |
131 | def show_results(self, file): |
132 | m = self.get_stats(file) | |
133 | if not m: | |
134 | return False | |
135 | ||
136 | cachefile = self.cachefile(file) | |
f809cdb0 | 137 | if not os.path.exists(cachefile): |
cb260c8e | 138 | print >>self.outsteram, "MISSING: report: %s" % file |
f809cdb0 | 139 | |
413b382d | 140 | if m['errors'] > 0 or m['warnings'] > 0: |
cb260c8e ER |
141 | (dirname, filename) = os.path.split(file) |
142 | print >>self.outstream, "rpmlint: %s" % filename | |
f809cdb0 | 143 | self.cat(cachefile) |
413b382d | 144 | |
8d0f868f ER |
145 | def rpmlint(self, file): |
146 | cachefile = self.cachefile(file) | |
147 | ||
148 | rc = None | |
149 | if not os.path.exists(cachefile) or os.stat(file).st_mtime > os.stat(cachefile).st_mtime: | |
150 | cmd = [self._rpmlint, file] | |
151 | outfd = open(cachefile, 'w') | |
152 | try: | |
153 | rc = subprocess.call(cmd, stdin = subprocess.PIPE, stdout = outfd, stderr = outfd, close_fds = True) | |
154 | except KeyboardInterrupt: | |
155 | os.unlink(cachefile) | |
156 | raise | |
157 | outfd.close() | |
158 | if not self.update_stats(file): | |
f809cdb0 ER |
159 | # update failed, dump cache and remove it |
160 | self.cat(cachefile) | |
8095749f | 161 | os.unlink(cachefile) |
8d0f868f ER |
162 | rc = 1 |
163 | return rc == 0 | |
03861ee2 | 164 | |
ec7915aa ER |
165 | try: |
166 | lock = 'rpmlint:'+treename | |
167 | if not ftpio.lock(lock, True): | |
168 | print >>sys.stderr, "ERR: %s tree already locked for rpmlint" % treename | |
169 | sys.exit(1) | |
f0cc35ee | 170 | |
66a58132 | 171 | if not quiet: |
cb260c8e | 172 | print >>outstream, "rpmlint of %d files from %d packages" % (len(files), len(tree.loadedpkgs)) |
ec7915aa | 173 | lint = LintPkg("~/tmp/rpmlint") |
cb260c8e | 174 | lint.outstream = outstream |
ec7915aa ER |
175 | for file in files: |
176 | lint.rpmlint(file) | |
177 | if not quiet: | |
178 | lint.print_stats(file) | |
179 | if show: | |
180 | lint.show_results(file) | |
8d0f868f | 181 | |
ec7915aa ER |
182 | if not quiet: |
183 | lint.print_stats() | |
f0cc35ee | 184 | |
ec7915aa | 185 | ftpio.unlock(lock) |
cb260c8e | 186 | except (Exception, KeyboardInterrupt): |
ec7915aa ER |
187 | ftpio.unlock(lock) |
188 | raise |