You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

250 lines
11 KiB

  1. #!/usr/bin/python3
  2. # -*- python -*-
  3. # querybts - Examine the state of a debbugs server
  4. # Written by Chris Lawrence <lawrencc@debian.org>
  5. # (C) 1999-2008 Chris Lawrence
  6. # Copyright (C) 2008-2017 Sandro Tosi <morph@debian.org>
  7. #
  8. # This program is freely distributable per the following license:
  9. #
  10. # Permission to use, copy, modify, and distribute this software and its
  11. # documentation for any purpose and without fee is hereby granted,
  12. # provided that the above copyright notice appears in all copies and that
  13. # both that copyright notice and this permission notice appear in
  14. # supporting documentation.
  15. #
  16. # I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL I
  18. # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  19. # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  21. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. # SOFTWARE.
  23. import sys
  24. import os
  25. import optparse
  26. import re
  27. from reportbug import utils
  28. from reportbug.exceptions import (
  29. UINotImportable,
  30. NoPackage, NoBugs, NoReport, NoNetwork,
  31. )
  32. from reportbug import debbugs
  33. from reportbug import urlutils
  34. from reportbug.ui import AVAILABLE_UIS
  35. import reportbug.ui.text_ui as ui
  36. ui_mode = 'text'
  37. from reportbug import VERSION_NUMBER
  38. VERSION = "querybts %s" % VERSION_NUMBER
  39. def main():
  40. # default values for cli options
  41. defaults = dict(system='debian', archived=False,
  42. http_proxy='', interface='text',
  43. use_browser=False, source=False,
  44. mirrors=None, mbox=False, buglist=False,
  45. mbox_reader_cmd=None)
  46. # parse config file to update default options
  47. args = utils.parse_config_files()
  48. for option, arg in list(args.items()):
  49. if option in ('system', 'mirrors', 'interface', 'http_proxy',
  50. 'mbox_reader_cmd'):
  51. defaults[option] = arg
  52. # define the cli options parser
  53. parser = optparse.OptionParser(
  54. description='%prog - Examine the state of a debbugs server.',
  55. usage='%prog [options] {<package> | <report number> [report2] ...}',
  56. version=VERSION)
  57. # set the defaults
  58. parser.set_defaults(**defaults)
  59. # add the cli options
  60. parser.add_option('-A', '--archive', action='store_true', dest='archived',
  61. help='Browse archived bugs.')
  62. parser.add_option('-b', '--buglist', action='store_true', dest='buglist',
  63. help='Display a bugs list for the given package.')
  64. parser.add_option('-B', '--bts', dest='system',
  65. help='Specify an alternate debbugs BTS; available values: %s ' %
  66. ', '.join([k for k in debbugs.SYSTEMS if debbugs.SYSTEMS[k].get('btsroot')]))
  67. parser.add_option('-m', '--mbox', action='store_true', dest='mbox',
  68. help='generate mbox')
  69. parser.add_option('--proxy', '--http_proxy', dest='http_proxy',
  70. help='define the proxy to use')
  71. parser.add_option('-s', '--source', action='store_true', dest='source',
  72. help='Query for source packages rather than binary packages.')
  73. parser.add_option('--timeout', type="int", dest='timeout', default=60,
  74. help='Specify the network timeout, in seconds [default: %default].')
  75. parser.add_option('-u', '--ui', '--interface', dest='interface',
  76. help='Specify the user interface to use; available values: %s ' % ', '.join(list(AVAILABLE_UIS.keys())))
  77. parser.add_option('-w', '--web', action='store_true', dest='use_browser',
  78. help='Use a web browser instead of the internal interface.')
  79. parser.add_option('--mbox-reader-cmd', dest='mbox_reader_cmd',
  80. help="Specify the program to open the reports mbox.")
  81. parser.add_option('--latest-first', action='store_true', dest='latest_first', default=False,
  82. help='Order bugs to show the latest first')
  83. # parse cli options
  84. (options, args) = parser.parse_args()
  85. # check options for consistency
  86. # interface must be one of those supported
  87. if options.interface not in AVAILABLE_UIS:
  88. parser.error('Allowed arguments to --ui: \n' +
  89. '\n'.join([' %s (%s)' % (key, value) for key, value in AVAILABLE_UIS.items()]))
  90. else:
  91. # prepare the UI and import it
  92. global ui, ui_mode
  93. iface = '%s_ui' % options.interface
  94. try:
  95. lib_package = __import__('reportbug.ui', fromlist=[iface])
  96. ui = getattr(lib_package, iface)
  97. ui_mode = options.interface
  98. except UINotImportable as msg:
  99. ui.long_message('*** Unable to import %s interface: %s '
  100. 'Falling back to %s interface.\n',
  101. options.interface, msg, ui_mode)
  102. print()
  103. # initialize the selected UI
  104. ui.initialize()
  105. # system must be one of those supported
  106. if options.system not in [k for k in debbugs.SYSTEMS if debbugs.SYSTEMS[k].get('btsroot')]:
  107. parser.error('Allowed arguments to --bts: \n' +
  108. '\n'.join([' %s (%s)' % (k, debbugs.SYSTEMS[k]['name'])
  109. for k in debbugs.SYSTEMS if debbugs.SYSTEMS[k].get('btsroot')]))
  110. else:
  111. # set the system info to those of the one selected
  112. sysinfo = debbugs.SYSTEMS[options.system]
  113. # there should be at least one argument
  114. if len(args) == 0:
  115. parser.error('Please specify a package or one or more bug numbers. ' +
  116. 'Note: most shells consider # a comment character; however, a ' +
  117. 'leading # is not needed to specify a bug by number.')
  118. if options.use_browser:
  119. if options.buglist:
  120. parser.error("--web and --buglist can't work together, exiting.")
  121. package = args[0]
  122. m = re.match('^#?(\d+)$', package)
  123. if m:
  124. num = int(m.group(1))
  125. url = debbugs.get_report_url(options.system, num, options.mirrors, options.archived)
  126. else:
  127. url = debbugs.get_package_url(options.system, package, options.mirrors, options.source, options.archived)
  128. # launch the browser and exit
  129. urlutils.launch_browser(url)
  130. sys.exit()
  131. if options.mbox:
  132. if options.buglist:
  133. parser.error("--mbox and --buglist can't work together, exiting.")
  134. for bugnum in args:
  135. package = bugnum
  136. m = re.match('^#?(\d+)$', bugnum)
  137. if not m:
  138. mboxbuglist = ui.handle_bts_query(package, options.system, options.timeout, options.mirrors,
  139. options.http_proxy, queryonly=True, title=VERSION,
  140. archived=options.archived, source=options.source, mbox=options.mbox,
  141. latest_first=options.latest_first)
  142. for num in mboxbuglist:
  143. url = debbugs.get_report_url(options.system, num, options.archived, mbox=True)
  144. try:
  145. report = urlutils.open_url(url, timeout=options.timeout)
  146. sys.stdout.write(report.read())
  147. except urlutils.urllib2.URLError as ex:
  148. print("Error while accessing mbox report (%s)." % ex, file=sys.stderr)
  149. else:
  150. num = int(m.group(1))
  151. url = debbugs.get_report_url(options.system, num, options.archived, mbox=True)
  152. try:
  153. report = urlutils.open_url(url, timeout=options.timeout)
  154. sys.stdout.write(report.read())
  155. except urlutils.urllib2.URLError as ex:
  156. print("Error while accessing mbox report (%s)." % ex, file=sys.stderr)
  157. sys.exit(1)
  158. return
  159. reportre = re.compile(r'^#?(\d+)$')
  160. try:
  161. if len(args) > 1:
  162. bugs = []
  163. for report in args:
  164. match = reportre.match(report)
  165. if match:
  166. bugs.append(int(match.group(1)))
  167. package = bugs
  168. if not bugs:
  169. raise ui.NoBugs
  170. else:
  171. package = args[0]
  172. match = reportre.match(package)
  173. if match:
  174. report = int(match.group(1))
  175. while 1:
  176. retvalue = ui.show_report(report, options.system, options.mirrors,
  177. options.http_proxy, options.timeout,
  178. queryonly=True,
  179. title=VERSION,
  180. archived=options.archived,
  181. mbox_reader_cmd=options.mbox_reader_cmd)
  182. ui.long_message('This option is not available while using querybts alone.\n')
  183. x = ui.select_options('What do you want to do now?', 'Qb',
  184. {'q': 'Exit querybts.',
  185. 'b': 'Query BTS one more time.'})
  186. if x == 'q':
  187. ui.long_message('Exiting.\n')
  188. sys.exit(0)
  189. while 1:
  190. ui.handle_bts_query(package, options.system, options.timeout, options.mirrors, options.http_proxy,
  191. queryonly=True, title=VERSION, archived=options.archived,
  192. source=options.source, buglist=options.buglist,
  193. mbox_reader_cmd=options.mbox_reader_cmd, latest_first=options.latest_first)
  194. ui.long_message('This option is not available while using querybts alone.\n')
  195. x = ui.select_options('What do you want to do now?', 'Qb',
  196. {'q': 'Exit querybts.',
  197. 'b': 'Query BTS one more time.'})
  198. if x == 'q':
  199. ui.long_message('Exiting.\n')
  200. sys.exit(0)
  201. except NoPackage:
  202. ui.long_message('Package appears not to exist in the BTS.\n')
  203. except NoBugs:
  204. ui.long_message('No bug reports found.\n')
  205. except NoReport:
  206. ui.long_message('Exiting.\n')
  207. except NoNetwork:
  208. ui.long_message('Cannot connect to network.\n')
  209. if __name__ == '__main__':
  210. try:
  211. main()
  212. except KeyboardInterrupt:
  213. print("querybts: exiting due to user interrupt.")
  214. except debbugs.Error as x:
  215. print('error accessing BTS: ' + str(x))
  216. except SystemExit:
  217. pass
  218. except:
  219. raise