1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22
23 import os
24 import tempfile
25 from entropy.const import etpConst
26 from entropy.output import blue, darkgreen, red, darkred, bold, purple, brown
27 from entropy.exceptions import IncorrectParameter, PermissionDenied, \
28 SystemDatabaseError
29 from entropy.i18n import _
30 from entropy.core import SystemSettings
31
33
34 import entropy.tools as entropyTools
35 from entropy.misc import Lifo
37
38 self.Output = OutputInterface
39 self.SystemSettings = SystemSettings()
40
41 if not hasattr(self.Output, 'updateProgress'):
42 mytxt = _("Output interface has no updateProgress method")
43 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
44 elif not callable(self.Output.updateProgress):
45 mytxt = _("Output interface has no updateProgress method")
46 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
47
49
50 repo = self.SystemSettings['repositories']['default_repository']
51
52 scan_msg = blue(_("Now searching for broken depends"))
53 self.Output.updateProgress(
54 "[repo:%s] %s..." % (
55 darkgreen(repo),
56 scan_msg,
57 ),
58 importance = 1,
59 type = "info",
60 header = red(" @@ ")
61 )
62
63 broken = False
64
65 count = 0
66 maxcount = len(idpackages)
67 for idpackage in idpackages:
68 count += 1
69 atom = dbconn.retrieveAtom(idpackage)
70 scan_msg = "%s, %s:" % (
71 blue(_("scanning for broken depends")),
72 darkgreen(atom),
73 )
74 self.Output.updateProgress(
75 "[repo:%s] %s" % (
76 darkgreen(repo),
77 scan_msg,
78 ),
79 importance = 1,
80 type = "info",
81 header = blue(" @@ "),
82 back = True,
83 count = (count, maxcount,)
84 )
85 mydepends = dbconn.retrieveDepends(idpackage)
86 if not mydepends:
87 continue
88 for mydepend in mydepends:
89 myatom = dbconn.retrieveAtom(mydepend)
90 self.Output.updateProgress(
91 "[repo:%s] %s => %s" % (
92 darkgreen(repo),
93 darkgreen(atom),
94 darkred(myatom),
95 ),
96 importance = 0,
97 type = "info",
98 header = blue(" @@ "),
99 back = True,
100 count = (count, maxcount,)
101 )
102 mycontent = dbconn.retrieveContent(mydepend)
103 mybreakages = self.content_test(mycontent)
104 if not mybreakages:
105 continue
106 broken = True
107 self.Output.updateProgress(
108 "[repo:%s] %s %s => %s" % (
109 darkgreen(repo),
110 darkgreen(atom),
111 darkred(myatom),
112 bold(_("broken libraries detected")),
113 ),
114 importance = 1,
115 type = "warning",
116 header = purple(" @@ "),
117 count = (count, maxcount,)
118 )
119 for mylib in mybreakages:
120 self.Output.updateProgress(
121 "%s %s:" % (
122 darkgreen(mylib),
123 red(_("needs")),
124 ),
125 importance = 1,
126 type = "warning",
127 header = brown(" ## ")
128 )
129 for needed in mybreakages[mylib]:
130 self.Output.updateProgress(
131 "%s" % (
132 red(needed),
133 ),
134 importance = 1,
135 type = "warning",
136 header = purple(" # ")
137 )
138 return broken
139
140
141 - def scan_missing_dependencies(self, idpackages, dbconn, ask = True,
142 self_check = False, repo = None, black_list = None,
143 black_list_adder = None):
144
145 if repo == None:
146 repo = self.SystemSettings['repositories']['default_repository']
147
148 if not isinstance(black_list, set):
149 black_list = set()
150
151 taint = False
152 scan_msg = blue(_("Now searching for missing RDEPENDs"))
153 self.Output.updateProgress(
154 "[repo:%s] %s..." % (
155 darkgreen(repo),
156 scan_msg,
157 ),
158 importance = 1,
159 type = "info",
160 header = red(" @@ ")
161 )
162 scan_msg = blue(_("scanning for missing RDEPENDs"))
163 count = 0
164 maxcount = len(idpackages)
165 for idpackage in idpackages:
166 count += 1
167 atom = dbconn.retrieveAtom(idpackage)
168 if not atom:
169 continue
170 self.Output.updateProgress(
171 "[repo:%s] %s: %s" % (
172 darkgreen(repo),
173 scan_msg,
174 darkgreen(atom),
175 ),
176 importance = 1,
177 type = "info",
178 header = blue(" @@ "),
179 back = True,
180 count = (count, maxcount,)
181 )
182 missing_extended, missing = self.get_missing_rdepends(dbconn,
183 idpackage, self_check = self_check)
184 missing -= black_list
185 for item in missing_extended.keys():
186 missing_extended[item] -= black_list
187 if not missing_extended[item]:
188 del missing_extended[item]
189 if (not missing) or (not missing_extended):
190 continue
191 self.Output.updateProgress(
192 "[repo:%s] %s: %s %s:" % (
193 darkgreen(repo),
194 blue("package"),
195 darkgreen(atom),
196 blue(_("is missing the following dependencies")),
197 ),
198 importance = 1,
199 type = "info",
200 header = red(" @@ "),
201 count = (count, maxcount,)
202 )
203 for missing_data in missing_extended:
204 self.Output.updateProgress(
205 "%s:" % (brown(unicode(missing_data)),),
206 importance = 0,
207 type = "info",
208 header = purple(" ## ")
209 )
210 for dependency in missing_extended[missing_data]:
211 self.Output.updateProgress(
212 "%s" % (darkred(dependency),),
213 importance = 0,
214 type = "info",
215 header = blue(" # ")
216 )
217 if ask:
218 rc_ask = self.Output.askQuestion(_("Do you want to add them?"))
219 if rc_ask == "No":
220 continue
221 rc_ask = self.Output.askQuestion(_("Selectively?"))
222 if rc_ask == "Yes":
223 newmissing = set()
224 new_blacklist = set()
225 for dependency in missing:
226 self.Output.updateProgress(
227 "[repo:%s|%s] %s" % (
228 darkgreen(repo),
229 brown(atom),
230 blue(dependency),
231 ),
232 importance = 0,
233 type = "info",
234 header = blue(" @@ ")
235 )
236 rc_ask = self.Output.askQuestion(_("Want to add?"))
237 if rc_ask == "Yes":
238 newmissing.add(dependency)
239 else:
240 rc_ask = self.Output.askQuestion(
241 _("Want to blacklist?"))
242 if rc_ask == "Yes":
243 new_blacklist.add(dependency)
244 if new_blacklist and (black_list_adder != None):
245 black_list_adder(new_blacklist, repo = repo)
246 missing = newmissing
247 if missing:
248 taint = True
249 dbconn.insertDependencies(idpackage, missing)
250 dbconn.commitChanges()
251 self.Output.updateProgress(
252 "[repo:%s] %s: %s" % (
253 darkgreen(repo),
254 darkgreen(atom),
255 blue(_("missing dependencies added")),
256 ),
257 importance = 1,
258 type = "info",
259 header = red(" @@ "),
260 count = (count, maxcount,)
261 )
262
263 return taint
264
265 - def content_test(self, mycontent):
266
267 def is_contained(needed, content):
268 for item in content:
269 if os.path.basename(item) == needed:
270 return True
271 return False
272
273 mylibs = {}
274 for myfile in mycontent:
275 myfile = myfile.encode('raw_unicode_escape')
276 if not os.access(myfile, os.R_OK):
277 continue
278 if not os.path.isfile(myfile):
279 continue
280 if not self.entropyTools.is_elf_file(myfile):
281 continue
282 mylibs[myfile] = self.entropyTools.read_elf_dynamic_libraries(
283 myfile)
284
285 broken_libs = {}
286 for mylib in mylibs:
287 for myneeded in mylibs[mylib]:
288
289 if is_contained(myneeded, mycontent):
290 continue
291 found = self.resolve_dynamic_library(myneeded, mylib)
292 if found:
293 continue
294 if not broken_libs.has_key(mylib):
295 broken_libs[mylib] = set()
296 broken_libs[mylib].add(myneeded)
297
298 return broken_libs
299
301
302 def do_resolve(mypaths):
303 found_path = None
304 for mypath in mypaths:
305 mypath = os.path.join(etpConst['systemroot']+mypath, library)
306 if not os.access(mypath, os.R_OK):
307 continue
308 if os.path.isdir(mypath):
309 continue
310 if not self.entropyTools.is_elf_file(mypath):
311 continue
312 found_path = mypath
313 break
314 return found_path
315
316 mypaths = self.entropyTools.collect_linker_paths()
317 found_path = do_resolve(mypaths)
318
319 if not found_path:
320 mypaths = self.entropyTools.read_elf_linker_paths(
321 requiring_executable)
322 found_path = do_resolve(mypaths)
323
324 return found_path
325
327
328 rdepends = {}
329 rdepends_plain = set()
330 neededs = dbconn.retrieveNeeded(idpackage, extended = True)
331 ldpaths = set(self.entropyTools.collect_linker_paths())
332 deps_content = set()
333 dependencies = self.get_deep_dependency_list(dbconn, idpackage,
334 atoms = True)
335 scope_cache = set()
336
337 def update_depscontent(mycontent, dbconn, ldpaths):
338 return set( \
339 [x for x in mycontent if os.path.dirname(x) in ldpaths \
340 and (dbconn.isNeededAvailable(os.path.basename(x)) > 0) ])
341
342 def is_in_content(myneeded, content):
343 for item in content:
344 item = os.path.basename(item)
345 if myneeded == item:
346 return True
347 return False
348
349 for dependency in dependencies:
350 match = dbconn.atomMatch(dependency)
351 if match[0] != -1:
352 mycontent = dbconn.retrieveContent(match[0])
353 deps_content |= update_depscontent(mycontent, dbconn, ldpaths)
354 key, slot = dbconn.retrieveKeySlot(match[0])
355 scope_cache.add((key, slot))
356
357 key, slot = dbconn.retrieveKeySlot(idpackage)
358 mycontent = dbconn.retrieveContent(idpackage)
359 deps_content |= update_depscontent(mycontent, dbconn, ldpaths)
360 scope_cache.add((key, slot))
361
362 idpackages_cache = set()
363 idpackage_map = {}
364 idpackage_map_reverse = {}
365 for needed, elfclass in neededs:
366 data_solved = dbconn.resolveNeeded(needed, elfclass = elfclass,
367 extended = True)
368 data_size = len(data_solved)
369 data_solved = set([x for x in data_solved if x[0] \
370 not in idpackages_cache])
371 if not data_solved or (data_size != len(data_solved)):
372 continue
373
374 if self_check:
375 if is_in_content(needed, mycontent):
376 continue
377
378 found = False
379 for data in data_solved:
380 if data[1] in deps_content:
381 found = True
382 break
383 if not found:
384 for data in data_solved:
385 r_idpackage = data[0]
386 key, slot = dbconn.retrieveKeySlot(r_idpackage)
387 if (key, slot) not in scope_cache:
388 if not dbconn.isSystemPackage(r_idpackage):
389 if not rdepends.has_key((needed, elfclass)):
390 rdepends[(needed, elfclass)] = set()
391 if not idpackage_map.has_key((needed, elfclass)):
392 idpackage_map[(needed, elfclass)] = set()
393 keyslot = "%s:%s" % (key, slot,)
394 obj = idpackage_map_reverse.setdefault(
395 keyslot, set())
396 obj.add((needed, elfclass,))
397 rdepends[(needed, elfclass)].add(keyslot)
398 idpackage_map[(needed, elfclass)].add(r_idpackage)
399 rdepends_plain.add(keyslot)
400 idpackages_cache.add(r_idpackage)
401
402
403
404 r_deplist = set()
405 for key in idpackage_map:
406 r_idpackages = idpackage_map.get(key)
407 for r_idpackage in r_idpackages:
408 r_deplist |= dbconn.retrieveDependencies(r_idpackage)
409
410 r_keyslots = set()
411 for r_dep in r_deplist:
412 m_idpackage, m_rc = dbconn.atomMatch(r_dep)
413 if m_rc != 0:
414 continue
415 keyslot = dbconn.retrieveKeySlotAggregated(m_idpackage)
416 if keyslot in rdepends_plain:
417 r_keyslots.add(keyslot)
418
419 rdepends_plain -= r_keyslots
420 for r_keyslot in r_keyslots:
421 keys = [x for x in idpackage_map_reverse.get(keyslot, set()) if \
422 x in rdepends]
423 for key in keys:
424 rdepends[key].discard(r_keyslot)
425 if not rdepends[key]:
426 del rdepends[key]
427
428 return rdepends, rdepends_plain
429
431
432 mybuffer = self.Lifo()
433 matchcache = set()
434 depcache = set()
435 mydeps = dbconn.retrieveDependencies(idpackage)
436 for mydep in mydeps:
437 mybuffer.push(mydep)
438 mydep = mybuffer.pop()
439
440 while mydep:
441
442 if mydep in depcache:
443 mydep = mybuffer.pop()
444 continue
445
446 my_idpackage, my_rc = dbconn.atomMatch(mydep)
447 if atoms:
448 matchcache.add(mydep)
449 else:
450 matchcache.add(my_idpackage)
451
452 if my_idpackage != -1:
453 owndeps = dbconn.retrieveDependencies(my_idpackage)
454 for owndep in owndeps:
455 mybuffer.push(owndep)
456
457 depcache.add(mydep)
458 mydep = mybuffer.pop()
459
460
461 matchcache.discard(-1)
462 return matchcache
463
465
466 from entropy.db import LocalRepository, dbapi2
467 fd, tmp_path = tempfile.mkstemp()
468 extract_path = self.entropyTools.extract_edb(pkg_path, tmp_path)
469 if extract_path is None:
470 os.remove(tmp_path)
471 os.close(fd)
472 return False
473 try:
474 dbc = LocalRepository(
475 readOnly = False,
476 dbFile = tmp_path,
477 clientDatabase = True,
478 dbname = 'qa_testing',
479 xcache = False,
480 indexing = False,
481 OutputInterface = self.Output,
482 skipChecks = False
483 )
484 except dbapi2.Error:
485 os.remove(tmp_path)
486 os.close(fd)
487 return False
488
489 valid = True
490 try:
491 dbc.validateDatabase()
492 except SystemDatabaseError:
493 valid = False
494
495 if valid:
496 try:
497 for idpackage in dbc.listAllIdpackages():
498 dbc.retrieveContent(idpackage, extended = True,
499 formatted = True, insert_formatted = True)
500 except dbapi2.Error:
501 valid = False
502
503 dbc.closeDB()
504 os.remove(tmp_path)
505 os.close(fd)
506
507 return valid
508
510 qa_methods = [self.__analyze_package_edb]
511 for method in qa_methods:
512 qa_rc = method(package_path)
513 if not qa_rc:
514 return False
515 return True
516
517
519
520 import entropy.tools as entropyTools
522 from entropy.misc import MultipartPostHandler
523 import urllib2
524 self.url = post_url
525 self.opener = urllib2.build_opener(MultipartPostHandler)
526 self.generated = False
527 self.params = {}
528
529 sys_settings = SystemSettings()
530 proxy_settings = sys_settings['system']['proxy']
531 mydict = {}
532 if proxy_settings['ftp']:
533 mydict['ftp'] = proxy_settings['ftp']
534 if proxy_settings['http']:
535 mydict['http'] = proxy_settings['http']
536 if mydict:
537 mydict['username'] = proxy_settings['username']
538 mydict['password'] = proxy_settings['password']
539 self.entropyTools.add_proxy_opener(urllib2, mydict)
540 else:
541
542 urllib2._opener = None
543
544 - def prepare(self, tb_text, name, email, report_data = "", description = ""):
545
546 import sys
547 from entropy.tools import getstatusoutput
548 self.params['arch'] = etpConst['currentarch']
549 self.params['stacktrace'] = tb_text
550 self.params['name'] = name
551 self.params['email'] = email
552 self.params['version'] = etpConst['entropyversion']
553 self.params['errordata'] = report_data
554 self.params['description'] = description
555 self.params['arguments'] = ' '.join(sys.argv)
556 self.params['uid'] = etpConst['uid']
557 self.params['system_version'] = "N/A"
558 if os.access(etpConst['systemreleasefile'], os.R_OK):
559 f_rel = open(etpConst['systemreleasefile'], "r")
560 self.params['system_version'] = f_rel.readline().strip()
561 f_rel.close()
562
563 self.params['processes'] = getstatusoutput('ps auxf')[1]
564 self.params['lspci'] = getstatusoutput('/usr/sbin/lspci')[1]
565 self.params['dmesg'] = getstatusoutput('dmesg')[1]
566 self.params['locale'] = getstatusoutput('locale -v')[1]
567
568 self.generated = True
569
570
572 if self.generated:
573 result = self.opener.open(self.url, self.params).read()
574 if result.strip() == "1":
575 return True
576 return False
577 else:
578 mytxt = _("Not prepared yet")
579 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
580