Advertisement
Guest User

Untitled

a guest
Jul 17th, 2018
174
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.13 KB | None | 0 0
  1. #!/usr/bin/python3
  2. # vim:set fileencoding=utf-8 et ts=4 sts=4 sw=4:
  3. #
  4. # apt-listchanges - Show changelog entries between the installed versions
  5. # of a set of packages and the versions contained in
  6. # corresponding .deb files
  7. #
  8. # Copyright (C) 2000-2006 Matt Zimmerman <mdz@debian.org>
  9. # Copyright (C) 2006 Pierre Habouzit <madcoder@debian.org>
  10. # Copyright (C) 2016 Robert Luberda <robert@debian.org>
  11. #
  12. # This program is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # This program is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public
  23. # License along with this program; if not, write to the Free
  24. # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25. # MA 02111-1307 USA
  26. #
  27.  
  28. import sys, os, os.path
  29. import apt_pkg
  30. import signal
  31. import subprocess
  32. import traceback
  33.  
  34. sys.path += [os.path.dirname(sys.argv[0]) + '/apt-listchanges', '/usr/share/apt-listchanges']
  35. import ALCLog
  36. from ALChacks import _
  37. import apt_listchanges, DebianFiles, ALCApt, ALCConfig, ALCSeenDb
  38.  
  39. def main(config):
  40. config.read('/etc/apt/listchanges.conf')
  41. debs = config.getopt(sys.argv)
  42.  
  43. if config.dump_seen:
  44. ALCSeenDb.make_seen_db(config, True).dump()
  45. sys.exit(0);
  46.  
  47. apt_pkg.init_system()
  48.  
  49. if config.apt_mode:
  50. debs = ALCApt.AptPipeline(config).read()
  51. if not debs:
  52. sys.exit(0)
  53.  
  54. # Force quiet (loggable) mode if not running interactively
  55. if not sys.stdout.isatty() and not config.quiet:
  56. config.quiet = 1
  57.  
  58. try:
  59. frontend = apt_listchanges.make_frontend(config, len(debs))
  60. except apt_listchanges.EUnknownFrontend:
  61. ALCLog.error(_("Unknown frontend: %s") % config.frontend)
  62. sys.exit(1)
  63.  
  64. if frontend == None:
  65. sys.exit(0)
  66.  
  67. if frontend.needs_tty_stdin() and not sys.stdin.isatty():
  68. try:
  69. # Give any forked processes (eg. lynx) a normal stdin;
  70. # See Debian Bug #343423. (Note: with $APT_HOOK_INFO_FD
  71. # support introduced in version 3.2, stdin should point to
  72. # a terminal already, so there should be no need to reopen it).
  73. tty = open('/dev/tty', 'rb+', buffering=0)
  74. os.close(0)
  75. os.dup2(tty.fileno(), 0)
  76. tty.close()
  77. except Exception as ex:
  78. ALCLog.warning(_("Cannot reopen /dev/tty for stdin: %s") % str(ex))
  79.  
  80. if not config.show_all:
  81. status = DebianFiles.ControlParser()
  82. status.readfile('/var/lib/dpkg/status')
  83. status.makeindex('Package')
  84.  
  85. seen_db = ALCSeenDb.make_seen_db(config)
  86.  
  87. all_news = {}
  88. all_changelogs = {}
  89. all_binnmus = {}
  90. notes = []
  91.  
  92. # Mapping of source->binary packages
  93. source_packages = {}
  94.  
  95. # Flag for each source package, only set if changelogs were actually found
  96. found = {}
  97.  
  98.  
  99. # Main loop
  100. for deb in debs:
  101. pkg = DebianFiles.Package(deb)
  102. binpackage = pkg.binary
  103. srcpackage = pkg.source
  104. srcversion = pkg.Version # XXX take the real version or we'll lose binNMUs
  105.  
  106. frontend.update_progress()
  107. # Show changes later than fromversion
  108. fromversion = None
  109.  
  110. if not config.show_all:
  111. if srcpackage in seen_db:
  112. fromversion = seen_db[srcpackage]
  113. elif config.since:
  114. fromversion = config.since
  115. else:
  116. statusentry = status.find('Package', binpackage)
  117. if statusentry and statusentry.installed():
  118. fromversion = statusentry.version()
  119. else:
  120. # Package not installed or seen
  121. notes.append(_("%s: will be newly installed") % binpackage)
  122. continue
  123.  
  124. source_packages.setdefault(srcpackage, []).append(binpackage)
  125.  
  126. # For packages with non uniform binary versions wrt the source
  127. # version, the version reported for the binary package is the source
  128. # one, which lacks binNMU.
  129. #
  130. # This is why even if we've seen a package we may miss bits of
  131. # changelog in some odd cases
  132. if srcpackage in found and \
  133. apt_pkg.version_compare(srcversion, found[srcpackage]) <= 0:
  134. continue
  135.  
  136. if not config.show_all and apt_pkg.version_compare(fromversion, srcversion) >= 0:
  137. notes.append(_("%(pkg)s: Version %(version)s has already been seen")
  138. % {'pkg': binpackage, 'version': srcversion})
  139. continue
  140.  
  141. (news, changelog, binnmu) = pkg.extract_changes(config.which, fromversion, config.reverse)
  142.  
  143. if news or changelog or binnmu:
  144. found[srcpackage] = srcversion
  145. seen_db[srcpackage] = srcversion
  146. if news:
  147. all_news[srcpackage] = news
  148. if changelog:
  149. all_changelogs[srcpackage] = changelog
  150. if binnmu:
  151. all_binnmus[srcpackage] = binnmu
  152.  
  153. frontend.progress_done()
  154. seen_db.close_db()
  155.  
  156. # Merge binnmu entries with regular changelog entries.
  157. # Assumption: the binnmu version is greater than the last non-binnmu version.
  158. for srcpackage in all_binnmus:
  159. if srcpackage in all_changelogs:
  160. all_changelogs[srcpackage].merge_binnmu(all_binnmus[srcpackage], config.reverse)
  161. else:
  162. all_changelogs[srcpackage] = all_binnmus[srcpackage]
  163.  
  164. all_news = list(all_news.values())
  165. all_changelogs = list(all_changelogs.values())
  166.  
  167. for batch in (all_news, all_changelogs):
  168. batch.sort(key=lambda x: (x.urgency, x.package))
  169.  
  170. if config.headers:
  171. changes = ''
  172. news = ''
  173. for rec in all_news:
  174. if not rec.changes:
  175. continue
  176.  
  177. package = rec.package
  178. header = _('News for %s') % package
  179. if len([x for x in source_packages[package] if x != package]) > 0:
  180. # Differing source and binary packages
  181. header += ' (' + ' '.join(source_packages[package]) + ')'
  182. news += '--- ' + header + ' ---\n' + rec.changes
  183.  
  184. for rec in all_changelogs:
  185. if not rec.changes:
  186. continue
  187.  
  188. package = rec.package
  189. header = _('Changes for %s') % package
  190. if len([x for x in source_packages[package] if x != package]) > 0:
  191. # Differing source and binary packages
  192. header += ' (' + ' '.join(source_packages[package]) + ')'
  193. changes += '--- ' + header + ' ---\n' + rec.changes
  194. else:
  195. news = ''.join([x.changes for x in all_news if x.changes])
  196. changes = ''.join([x.changes for x in all_changelogs if x.changes])
  197.  
  198. if config.verbose and len(notes) > 0:
  199. changes += _("Informational notes") + ":\n\n" + '\n'.join(notes)
  200.  
  201. if news:
  202. frontend.set_title( _('apt-listchanges: News') )
  203. frontend.display_output(news)
  204.  
  205. if changes:
  206. frontend.set_title( _('apt-listchanges: Changelogs') )
  207. frontend.display_output(changes)
  208.  
  209. if news or changes:
  210. apt_listchanges.confirm_or_exit(config, frontend)
  211.  
  212. hostname = subprocess.getoutput('hostname')
  213.  
  214. if apt_listchanges.can_send_emails(config):
  215. if changes:
  216. subject = _("apt-listchanges: changelogs for %s") % hostname
  217. apt_listchanges.mail_changes(config, changes, subject)
  218.  
  219. if news:
  220. subject = _("apt-listchanges: news for %s") % hostname
  221. apt_listchanges.mail_changes(config, news, subject)
  222.  
  223. # Write out seen db
  224. seen_db.apply_changes()
  225.  
  226. elif not config.apt_mode and not source_packages.keys():
  227. ALCLog.error(_("Didn't find any valid .deb archives"))
  228. sys.exit(1)
  229.  
  230.  
  231. def _setup_signals():
  232. def signal_handler(signum, frame):
  233. ALCLog.error(_('Received signal %d, exiting') % signum)
  234. sys.exit(apt_listchanges.BREAK_APT_EXIT_CODE)
  235.  
  236. for s in [ signal.SIGHUP, signal.SIGQUIT, signal.SIGTERM ]:
  237. signal.signal(s, signal_handler)
  238.  
  239. if __name__ == '__main__':
  240. _setup_signals()
  241. config = ALCConfig.ALCConfig()
  242. try:
  243. main(config)
  244. except KeyboardInterrupt:
  245. sys.exit(apt_listchanges.BREAK_APT_EXIT_CODE)
  246. except ALCApt.AptPipelineError as ex:
  247. ALCLog.error(str(ex))
  248. sys.exit(apt_listchanges.BREAK_APT_EXIT_CODE)
  249. except ALCSeenDb.DbError as ex:
  250. ALCLog.error(str(ex))
  251. sys.exit(1)
  252. except Exception:
  253. traceback.print_exc()
  254. apt_listchanges.confirm_or_exit(config, apt_listchanges.ttyconfirm(config))
  255. sys.exit(1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement