sanity-check.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. # -*- coding: utf-8 -*-
  2. # GNU Guix --- Functional package management for GNU
  3. # Copyright © 2021, 2022 Lars-Dominik Braun <lars@6xq.net>
  4. #
  5. # This file is part of GNU Guix.
  6. #
  7. # GNU Guix is free software; you can redistribute it and/or modify it
  8. # under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 3 of the License, or (at
  10. # your option) any later version.
  11. #
  12. # GNU Guix is distributed in the hope that it will be useful, but
  13. # WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. from __future__ import print_function # Python 2 support.
  20. import importlib
  21. import sys
  22. import traceback
  23. try:
  24. import pkg_resources
  25. except ImportError:
  26. print('Warning: Skipping, because python-setuptools are not available.')
  27. sys.exit(0)
  28. try:
  29. from importlib.machinery import PathFinder
  30. except ImportError:
  31. PathFinder = None
  32. ret = 0
  33. # Only check site-packages installed by this package, but not dependencies
  34. # (which pkg_resources.working_set would include). Path supplied via argv.
  35. ws = pkg_resources.find_distributions(sys.argv[1])
  36. for dist in ws:
  37. print('validating', repr(dist.project_name), dist.location)
  38. try:
  39. print('...checking requirements: ', end='')
  40. req = str(dist.as_requirement())
  41. # dist.activate() is not enough to actually check requirements, we
  42. # have to .require() it.
  43. pkg_resources.require(req)
  44. print('OK')
  45. except Exception as e:
  46. print('ERROR:', req, repr(e))
  47. ret = 1
  48. continue
  49. # Try to load top level modules. This should not have any side-effects.
  50. try:
  51. metalines = dist.get_metadata_lines('top_level.txt')
  52. except (KeyError, EnvironmentError):
  53. # distutils (i.e. #:use-setuptools? #f) will not install any metadata.
  54. # This file is also missing for packages built using a PEP 517 builder
  55. # such as poetry.
  56. print('WARNING: cannot determine top-level modules')
  57. continue
  58. for name in metalines:
  59. # Only available on Python 3.
  60. if PathFinder and PathFinder.find_spec(name) is None:
  61. # Ignore unavailable modules, often C modules, which were not
  62. # installed at the top-level. Cannot use ModuleNotFoundError,
  63. # because it is raised by failed imports too.
  64. continue
  65. try:
  66. print('...trying to load module', name, end=': ')
  67. importlib.import_module(name)
  68. print('OK')
  69. except Exception:
  70. print('ERROR:')
  71. traceback.print_exc(file=sys.stdout)
  72. ret = 1
  73. # Try to load entry points of console scripts too, making sure they
  74. # work. They should be removed if they don't. Other groups may not be
  75. # safe, as they can depend on optional packages.
  76. for group, v in dist.get_entry_map().items():
  77. if group not in {'console_scripts', 'gui_scripts'}:
  78. continue
  79. for name, ep in v.items():
  80. try:
  81. print('...trying to load endpoint', group, name, end=': ')
  82. ep.load()
  83. print('OK')
  84. except Exception:
  85. print('ERROR:')
  86. traceback.print_exc(file=sys.stdout)
  87. ret = 1
  88. sys.exit(ret)