]> git.pld-linux.org Git - projects/pld-ftp-admin.git/blob - modules/ftptree.py
- check for signed packages when moving them between trees and tree configured as...
[projects/pld-ftp-admin.git] / modules / ftptree.py
1 # vi: encoding=utf-8 ts=8 sts=4 sw=4 et
2
3 import os, config, string, urllib, re, rpm
4 from common import fileexists, noarchcachedir
5 from baseftptree import BasePkg, BaseFtpTree
6 from sign import is_signed
7
8 errnum = 0
9 quietmode = False
10
11 class SomeError(Exception):
12     def __init__(self):
13         return
14
15     def __str__(self):
16         print "","An Error occured!"
17
18 def bailoutonerror():
19     if not errnum == 0:
20         print "%d error(s) encountered... aborting" % errnum
21         raise SomeError
22
23 def pinfo(msg):
24     print 'INFO: ' + msg
25
26 def perror(msg):
27     global errnum
28     errnum=errnum+1
29     print 'ERR: ' + msg
30
31 def pwarning(msg):
32     print 'WARN: ' + msg
33
34 def rm(file, test=False):
35     if test:
36         if not os.path.exists(file):
37             pinfo("TEST os.remove(%s): file doesn't exists" % file)
38     else:
39         try:
40             os.remove(file)
41         except OSError, e:
42             pinfo("os.remove(%s): %s" % (file, e))
43             #raise
44
45 def mv(src, dst, test=False):
46     fsrc = src
47     fdst = dst+'/'+src.split('/')[-1]
48     if test:
49         if not os.path.exists(src):
50             pinfo("TEST os.rename(%s, %s): source doesn't exists" % (fsrc, fdst))
51     else:
52         try:
53             os.rename(fsrc, fdst)
54         except OSError, e:
55             pinfo("os.rename(%s, %s): %s" % (fsrc, fdst, e))
56             raise
57
58 class Pkg(BasePkg):
59     def __init__(self, nvr, tree):
60         BasePkg.__init__(self, nvr, tree)
61         self.name = string.join(nvr.split('-')[:-2], '-')
62         self.version = nvr.split('-')[-2]
63         self.release = nvr.split('-')[-1]
64         self.marked4removal = False
65         self.marked4moving = False
66         self.marked4movingpool = []
67         self.errors = []
68         self.warnings = []
69
70     def __cmp__(self, pkg):
71         if self.name > pkg.name:
72             return 1
73         elif self.name < pkg.name:
74             return -1
75         else:
76             return rpm.labelCompare(('0', self.version, self.release),
77                                     ('0', pkg.version, pkg.release))
78
79
80     # unfortunately can't do new Pkg(NVR), and have no "tree" in this pkg context
81     # so this static function
82     def is_debuginfo(self, nvr):
83         """
84         returns true if NVR is debuginfo package and separate debuginfo is enabled
85         """
86         if not config.separate_debuginfo:
87             return False
88         pkg = nvr.split('-')[:-2]
89         return pkg[-1] == 'debuginfo'
90
91     def mark4moving(self):
92         if not self.marked4moving:
93             # Only one pkg in this pool can be marked for moving
94             for pkg in self.marked4movingpool:
95                 pkg.unmark4moving()
96             self.tree.marked4moving.append(self)
97             self.marked4moving=True
98
99     def unmark4moving(self):
100         if self.marked4moving:
101             self.tree.marked4moving.remove(self)
102             self.marked4moving=False
103
104     def mark4removal(self):
105         if not self.marked4removal:
106             self.tree.marked4removal.append(self)
107             self.marked4removal=True
108
109     def error(self, msg):
110         self.errors.append(msg)
111         if not quietmode:
112             perror('%s %s' % (self.nvr, msg))
113
114     def warning(self, msg):
115         self.warnings.append(msg)
116         if not quietmode:
117             pwarning('%s %s' % (self.nvr, msg))
118
119     def load(self, content=None):
120         BasePkg.load(self, content)
121         if self.info.has_key('move'):
122             self.mark4moving()
123
124     def writeinfo(self):
125         f = open(self.tree.basedir+'/SRPMS/.metadata/'+self.nvr+'.src.rpm.info', 'w')
126         for bid in self.build.keys():
127             f.write("info:build:%s:requester:%s\ninfo:build:%s:requester_email:%s\n" % (bid, self.build[bid].requester, bid, self.build[bid].requester_email))
128         for key in self.info.keys():
129             f.write("info:%s:%s\n" % (key, string.join(self.info[key], ':')))
130         for arch in self.files.keys():
131             for rpm in self.files[arch]:
132                 f.write("file:%s:%s\n" % (arch, rpm))
133         
134     def remove(self, test = False):
135         """
136         Remove package from ftp
137         """
138         for arch in self.files.keys():
139             for rpm in self.files[arch]:
140                 if self.is_debuginfo(rpm):
141                     rm(self.tree.basedir + '/' + arch + '/debuginfo/' + rpm, test)
142                 else:
143                     rm(self.tree.basedir + '/' + arch + '/RPMS/' + rpm, test)
144                 if arch == 'noarch':
145                     if fileexists(noarchcachedir + rpm + '.filelist'):
146                         rm(noarchcachedir + rpm + '.filelist', test)
147                     if fileexists(noarchcachedir + rpm + '.reqlist'):
148                         rm(noarchcachedir + rpm + '.reqlist', test)
149         rm(self.tree.basedir + '/SRPMS/.metadata/' + self.nvr + '.src.rpm.info', test)
150
151     def rpmfiles(self):
152         """
153         Return rpm files related to this package
154         """
155         files = []
156         for arch, rpms in self.files.items():
157             for nvr in rpms:
158                 if self.is_debuginfo(nvr):
159                     files.append(self.tree.basedir + '/' + arch + '/debuginfo/' + nvr)
160                 else:
161                     files.append(self.tree.basedir + '/' + arch + '/RPMS/' + nvr)
162         return files
163
164     def move(self, dsttree, test=False):
165         if dsttree.has_key(self.nvr):
166             movedany = False
167             for arch in self.files.keys():
168                 if arch in dsttree[self.nvr].files.keys():
169                     msg = ""
170                     if test:
171                         msg = "TEST "
172                     pinfo("%sArch %s for %s is already present in dest tree; removing from srctree" % (msg, arch, self.nvr))
173                     for rpm in self.files[arch]:
174                         if self.is_debuginfo(rpm):
175                             rm(self.tree.basedir + '/' + arch + '/debuginfo/' + rpm, test)
176                         else:
177                             rm(self.tree.basedir + '/' + arch + '/RPMS/' + rpm, test)
178                 else:
179                     movedany = True
180                     dsttree[self.nvr].files[arch] = self.files[arch]
181                     for rpm in self.files[arch]:
182                         if self.is_debuginfo(rpm):
183                             mv(self.tree.basedir + '/' + arch + '/debuginfo/' + rpm, dsttree.basedir + '/' + arch + '/debuginfo/', test)
184                         else:
185                             mv(self.tree.basedir + '/' + arch + '/RPMS/' + rpm, dsttree.basedir + '/' + arch + '/RPMS/', test)
186             if not test and  movedany:
187                 for bid in self.build.keys():
188                     dsttree[self.nvr].build[bid] = self.build[bid]
189                 dsttree[self.nvr].writeinfo()
190             rm(self.tree.basedir + '/SRPMS/.metadata/' + self.nvr + '.src.rpm.info', test)
191         else:
192             # move files
193             for arch in self.files.keys():
194                 for rpm in self.files[arch]:
195                     if self.is_debuginfo(rpm):
196                         mv(self.tree.basedir + '/' + arch + '/debuginfo/' + rpm, dsttree.basedir + '/' + arch + '/debuginfo/', test)
197                     else:
198                         mv(self.tree.basedir + '/' + arch + '/RPMS/' + rpm, dsttree.basedir + '/' + arch + '/RPMS/', test)
199
200             # move metadata
201             mv(self.tree.basedir + '/SRPMS/.metadata/' + self.nvr + '.src.rpm.info', dsttree.basedir + '/SRPMS/.metadata/', test)
202
203 class FtpTree(BaseFtpTree):
204     def __init__(self, tree, loadall=False):
205         BaseFtpTree.__init__(self, tree)
206         self.loadedpkgs = {}
207         self.marked4removal = []
208         self.marked4moving = []
209         self.pkgnames = []
210         self.__loadpkgnames()
211         if loadall:
212             for pkgname in self.pkgnames:
213                 self.loadedpkgs[pkgname] = Pkg(pkgname, self)
214         # Tests:
215         self.do_checkbuild = True
216
217     def __getitem__(self, key):
218         if self.loadedpkgs.has_key(key):
219             return self.loadedpkgs[key]
220         elif key in self.pkgnames:
221             pkg=Pkg(key, self)
222             self.loadedpkgs[key]=pkg
223             return pkg
224         else:
225             raise KeyError, key
226
227     def has_key(self, key):
228         if key in self.pkgnames:
229             return True
230         else:
231             return False
232
233     def keys(self):
234         return self.pkgnames
235
236     def values(self):
237         return self.loadedpkgs.values()
238
239     def checktree(self, dsttree):
240         self.__checkbuild(self.loadedpkgs.values())
241         self.__checkarchs(dsttree, self.loadedpkgs.values())
242
243     def testmove(self, dsttree):
244         self.__checkbuild(self.marked4moving)
245         self.__checkarchs(dsttree, self.marked4moving)
246
247         self.__checksigns(dsttree, self.marked4moving, test = True)
248         
249         self.__rmolderfromsrc(test = True)
250         self.__rmotherfromdst(dsttree, test = True)
251
252         for pkg in self.marked4moving:
253             pkg.move(dsttree, test = True)
254
255     def movepkgs(self, dsttree):
256         if self.do_checkbuild:
257             self.__checkbuild(self.marked4moving)
258         bailoutonerror()
259
260         self.__checkarchs(dsttree, self.marked4moving)
261         bailoutonerror()
262
263         self.__checksigns(dsttree, self.marked4moving)
264         bailoutonerror()
265
266         self.__rmolderfromsrc()
267         self.__rmotherfromdst(dsttree)
268
269         for pkg in self.marked4moving:
270             pkg.move(dsttree)
271
272     def rpmfiles(self):
273         if self.do_checkbuild:
274             self.__checkbuild(self.marked4moving)
275
276         files = []
277         for pkg in self.marked4moving:
278             files += pkg.rpmfiles()
279         return files
280
281     def removepkgs(self):
282         if self.do_checkbuild:
283             self.__checkbuild(self.marked4removal)
284         bailoutonerror()
285         for pkg in self.marked4removal:
286             pkg.remove()
287
288     def mark4removal(self, wannabepkgs):
289         self.__mark4something(wannabepkgs, Pkg.mark4removal)
290
291     def mark4moving(self, wannabepkgs):
292         self.__mark4something(wannabepkgs, Pkg.mark4moving)
293         
294
295     # Internal functions below
296
297     def __loadpkgnames(self):
298         def checkfiletype(name):
299             if name[-13:]=='.src.rpm.info':
300                 return True
301             else:
302                 return False
303         list = filter(checkfiletype, os.listdir(self.basedir+'/SRPMS/.metadata'))
304         self.pkgnames = map((lambda x: x[:-13]), list)
305
306     def __mark4something(self, wannabepkgs, markfunction):
307         def chopoffextension(pkg):
308             found=pkg.find('.src.rpm')
309             if found==-1:
310                 return pkg
311             else:
312                 return pkg[:found]
313         for wannabepkg in wannabepkgs:
314             pkgname=chopoffextension(wannabepkg)
315             if pkgname in self.pkgnames:
316                 if not pkgname in self.loadedpkgs.keys():
317                     self.loadedpkgs[pkgname]=Pkg(pkgname, self)
318                 markfunction(self.loadedpkgs[pkgname])
319             else:
320                 perror('%s not found in source tree' % pkgname)
321         bailoutonerror()
322
323     def __checkbuild(self, marked):
324         """
325         Checks queue file if all arches are built
326
327         Reads config.builderqueue to grab the info
328         """
329         f = urllib.urlopen(config.builderqueue)
330         requests = {}
331         reid = re.compile(r'^.*id=(.*) pri.*$')
332         regb = re.compile(r'^group:.*$|builders:.*$', re.M)
333         for i in re.findall(regb, f.read()):
334             if i[0] == 'g':
335                 id = reid.sub(r'\1', i)
336                 requests[id] = ""
337             elif i[0]=='b':
338                 requests[id] = requests[id] + i
339         f.close()
340
341         for pkg in marked:
342             for bid in pkg.build.keys():
343                 if requests.has_key(bid) and not requests[bid].find('?') == -1:
344                     pkg.error("(buildid %s) building not finished" % bid)
345
346     def __checkarchs(self, dsttree, marked):
347         """
348         Checks marked pkgs it is built on all archs.
349         """
350         for pkg in marked:
351             if len(pkg.files.keys()) <= 1:
352                 pkg.error('has only src.rpm built')
353                 continue
354             otherpkgnames = self.__find_other_pkgs(pkg, dsttree)
355
356             # check if we're not removing some archs
357             if otherpkgnames:
358                 curarchs = []
359                 missingarchs = []
360                 for somepkg in otherpkgnames:
361                     curarchs.extend(Pkg(somepkg, dsttree).files.keys())
362                 for arch in curarchs:
363                     if arch not in pkg.files.keys():
364                         missingarchs.append(arch)
365                 if missingarchs:
366                     pkg.error('moving would remove archs: %s' % missingarchs)
367             else:
368                 # warn if a package isn't built for all archs
369                 if (config.separate_noarch and 'noarch' in pkg.files.keys() and len(pkg.files.keys()) == 2):
370                     continue
371                 elif len(pkg.files.keys()) != len(config.ftp_archs) + 1:
372                     missingarchs = []
373                     for arch in config.ftp_archs:
374                         if arch not in pkg.files.keys():
375                             missingarchs.append(arch)
376                     pkg.warning('not built for archs: %s' % missingarchs)
377
378     def __rmolderfromsrc(self, test=False):
379         for pkg in self.marked4moving:
380             olderpkgnames = self.__find_older_pkgs(pkg)
381             for i in olderpkgnames:
382                 Pkg(i, self).remove(test)
383
384     def __rmotherfromdst(self, dsttree, test = False):
385         for pkg in self.marked4moving:
386             pkgnames = self.__find_other_pkgs(pkg, dsttree)
387             for i in pkgnames:
388                 Pkg(i, dsttree).remove(test)
389
390     # Used more than once filter functions
391     def __find_other_pkgs(self, pkg, tree):
392         escapedpkgname = pkg.name.replace('.', '\.').replace('+', '\+')
393         ziewre = re.compile(escapedpkgname + '-[^-]*-[^-]*$')
394         def filter_other_pkgs(x):
395             if ziewre.match(x) and not x == pkg.nvr:
396                 return True
397             else:
398                 return False
399         return filter(filter_other_pkgs, tree.pkgnames)
400
401     def __find_older_pkgs(self, pkg):
402         def filter_older_pkgs(x):
403             c = x.split('-')
404             rc = rpm.labelCompare(('0', pkg.version, pkg.release),
405                                                         ('0', c[-2], c[-1]))
406             if rc == 1: # pkg > x
407                 return True
408             else:
409                 return False
410         return filter(filter_older_pkgs, self.__find_other_pkgs(pkg, self))
411
412     def __checksigns(self, tree, pkgs, test = False):
413         """
414         Checks if pkgs in tree are all signed.
415
416         in case of test = true, error flag is set for unsigned packages
417         """
418         if not tree.treename in config.signed_trees:
419             return
420
421         for pkg in pkgs:
422             unsigned = 0
423             for file in pkg.rpmfiles():
424                 if not is_signed(file):
425                     unsigned += 1;
426
427             if unsigned != 0:
428                 if test == True:
429                     if not quietmode:
430                         pkg.warning('%d files not signed' % unsigned)
431                 else:
432                     pkg.error('%d files not signed' % unsigned)
This page took 0.07094 seconds and 3 git commands to generate.