bugreport.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #
  2. # bugreport module - object containing bug stuff for reporting
  3. # Written by Chris Lawrence <lawrencc@debian.org>
  4. # Copyright (C) 1999-2008 Chris Lawrence
  5. # Copyright (C) 2008-2016 Sandro Tosi <morph@debian.org>
  6. #
  7. # This program is freely distributable per the following license:
  8. #
  9. # Permission to use, copy, modify, and distribute this software and its
  10. # documentation for any purpose and without fee is hereby granted,
  11. # provided that the above copyright notice appears in all copies and that
  12. # both that copyright notice and this permission notice appear in
  13. # supporting documentation.
  14. #
  15. # I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  16. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL I
  17. # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  18. # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. # SOFTWARE.
  22. import os
  23. import utils
  24. import debbugs
  25. import commands
  26. from exceptions import *
  27. # to print errors
  28. import ui.text_ui as ui
  29. class bugreport(object):
  30. "Encapsulates a bug report into a convenient object we can pass around."
  31. # Default character set for str(x)
  32. charset = 'utf-8'
  33. def __init__(self, package, subject='', body='', system='debian',
  34. incfiles='', sysinfo=True,
  35. followup=False, type='debbugs', mode=utils.MODE_STANDARD,
  36. debsumsoutput=None, issource=False, **props):
  37. self.type = type
  38. for (k, v) in props.iteritems():
  39. setattr(self, k, v)
  40. self.package = package
  41. self.subject = subject
  42. # try to convert followup to int (if it's not already), TypeError if
  43. # the conversion is impossible
  44. if followup and not isinstance(followup, int):
  45. try:
  46. self.followup = followup.bug_num
  47. except:
  48. ui.long_message('Invalid value for followup, it must be a debianbts.Bugreport instance or an integer')
  49. raise TypeError
  50. else:
  51. self.followup = followup
  52. self.body = body
  53. self.mode = mode
  54. self.system = system
  55. self.incfiles = incfiles
  56. self.sysinfo = sysinfo
  57. self.debsumsoutput = debsumsoutput
  58. self.issource = issource
  59. def tset(self, value):
  60. if value not in ('debbugs', 'launchpad'):
  61. ui.long_message('invalid report type %s, defaulting to debbugs' %
  62. value)
  63. self.__type = 'debbugs'
  64. else:
  65. self.__type = value
  66. def tget(self):
  67. return self.__type
  68. type = property(tget, tset)
  69. def __unicode__(self):
  70. un = os.uname()
  71. debinfo = u''
  72. shellpath = utils.realpath('/bin/sh')
  73. init = utils.get_init_system()
  74. locinfo = []
  75. langsetting = os.environ.get('LANG', 'C')
  76. allsetting = os.environ.get('LC_ALL', '')
  77. for setting in ('LANG', 'LC_CTYPE'):
  78. if setting == 'LANG':
  79. env = langsetting
  80. else:
  81. env = '%s (charmap=%s)' % (os.environ.get(setting, langsetting), commands.getoutput("locale charmap"))
  82. if allsetting and env:
  83. env = "%s (ignored: LC_ALL set to %s)" % (env, allsetting)
  84. else:
  85. env = allsetting or env
  86. locinfo.append('%s=%s' % (setting, env))
  87. locinfo = ', '.join(locinfo)
  88. ph = getattr(self, 'pseudoheaders', None)
  89. if ph:
  90. headers = u'\n'.join(ph) + u'\n'
  91. else:
  92. headers = u''
  93. version = getattr(self, 'version', None)
  94. if version:
  95. headers += u'Version: %s\n' % version
  96. body = getattr(self, 'body', u'')
  97. body = body.decode('utf8')
  98. # add NEWBIELINE only if it's less than advanced and the package is not
  99. # one of the specials (f.e. those with a dedicated function) also
  100. # thinking about those systems that don't have 'specials' dict
  101. if self.mode < utils.MODE_ADVANCED and self.package not in \
  102. debbugs.SYSTEMS[self.system].get('specials', {}).keys():
  103. body = utils.NEWBIELINE + u'\n\n' + body
  104. elif not body:
  105. body = u'\n'
  106. if self.issource:
  107. reportto = 'Source'
  108. else:
  109. reportto = 'Package'
  110. if not self.followup:
  111. for (attr, name) in dict(severity='Severity',
  112. justification='Justification',
  113. tags='Tags',
  114. filename='File').iteritems():
  115. a = getattr(self, attr, None)
  116. if a:
  117. headers += u'%s: %s\n' % (name, a)
  118. report = u"%s: %s\n%s\n" % (reportto, self.package, headers)
  119. else:
  120. report = "Followup-For: Bug #%d\n%s: %s\n%s\n" % (
  121. self.followup, reportto, self.package, headers)
  122. infofunc = debbugs.SYSTEMS[self.system].get('infofunc', debbugs.generic_infofunc)
  123. if infofunc:
  124. debinfo += infofunc()
  125. if un[0] == 'GNU':
  126. # Use uname -v on Hurd
  127. uname_string = un[3]
  128. else:
  129. kern = un[0]
  130. if kern.startswith('GNU/'):
  131. kern = kern[4:]
  132. uname_string = '%s %s' % (kern, un[2])
  133. if kern == 'Linux':
  134. kinfo = []
  135. if 'SMP' in un[3]:
  136. cores = utils.get_cpu_cores()
  137. if cores > 1:
  138. kinfo += ['SMP w/%d CPU cores' % cores]
  139. elif cores == 1:
  140. kinfo += ['SMP w/1 CPU core']
  141. if 'PREEMPT' in un[3]:
  142. kinfo += ['PREEMPT']
  143. if kinfo:
  144. uname_string = '%s (%s)' % (uname_string, '; '.join(kinfo))
  145. if uname_string:
  146. debinfo += u'Kernel: %s\n' % uname_string
  147. if locinfo:
  148. debinfo += u'Locale: %s\n' % locinfo
  149. if shellpath != '/bin/sh':
  150. debinfo += u'Shell: /bin/sh linked to %s\n' % shellpath
  151. if init:
  152. debinfo += u'Init: %s\n' % init
  153. # Don't include system info for certain packages
  154. if self.sysinfo:
  155. report = u"%s%s%s\n-- System Information:\n%s" % (report, body, self.incfiles, debinfo)
  156. else:
  157. report = u"%s%s%s" % (report, body, self.incfiles)
  158. if hasattr(self, 'depinfo'):
  159. report += self.depinfo
  160. if hasattr(self, 'confinfo'):
  161. report += self.confinfo
  162. # add debsums output to the bug report
  163. if self.debsumsoutput:
  164. report += u"\n-- debsums errors found:\n%s\n" % self.debsumsoutput
  165. return report
  166. def __str__(self):
  167. return unicode(self).encode(charset, 'replace')
  168. def __repr__(self):
  169. params = ['%s=%s' % (k, self.k) for k in dir(self)]
  170. return 'bugreport(%s)' % ', '.join(params)