__main__.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import argparse
  2. from importlib import import_module
  3. import os
  4. __all__ = ['main']
  5. def exists(path):
  6. if not os.path.exists(path):
  7. raise argparse.ArgumentTypeError("could not find: {}".format(path))
  8. return os.path.abspath(path)
  9. def main():
  10. '''Entry point for the CLI
  11. '''
  12. # Binary dependencies
  13. binaries = ('appimagetool', 'patchelf')
  14. # Parse arguments
  15. parser = argparse.ArgumentParser(
  16. prog='python-appimage',
  17. description='Bundle a Python installation into an AppImage')
  18. subparsers = parser.add_subparsers(title='command',
  19. help='Command to execute',
  20. dest='command')
  21. parser.add_argument('-a', '--appimagetool-version',
  22. help='set appimagetool version')
  23. parser.add_argument('-q', '--quiet', help='disable logging',
  24. dest='verbosity', action='store_const', const='ERROR')
  25. parser.add_argument('-v', '--verbose', help='print extra information',
  26. dest='verbosity', action='store_const', const='DEBUG')
  27. build_parser = subparsers.add_parser('build',
  28. description='Build a Python appimage')
  29. build_subparsers = build_parser.add_subparsers(title='type',
  30. help='Type of AppImage build', dest='sub_command')
  31. cache_parser = subparsers.add_parser('cache',
  32. description='Manage Python appimage cache')
  33. cache_subparsers = cache_parser.add_subparsers(title='operation',
  34. help='Type of cache operation', dest='sub_command')
  35. cache_clean_parser = cache_subparsers.add_parser('clean',
  36. description='Clean cached image(s)')
  37. cache_clean_parser.add_argument('tags', nargs='*',
  38. help='manylinux image tag(s) (e.g. 2014_x86_64)')
  39. cache_clean_parser.add_argument('-a', '--all', action='store_true',
  40. help='remove all image(s) data')
  41. cache_get_parser = cache_subparsers.add_parser('get',
  42. description='Download image(s) to the cache')
  43. cache_get_parser.add_argument('tags', nargs='+',
  44. help='manylinux image tag(s) (e.g. 2014_x86_64)')
  45. cache_get_parser.add_argument('-e', '--extract', action='store_true',
  46. help='extract compressed image data')
  47. cache_list_parser = cache_subparsers.add_parser('list',
  48. description='List cached image(s)')
  49. install_parser = subparsers.add_parser('install',
  50. description='Install binary dependencies')
  51. install_parser.add_argument('binary', nargs='+',
  52. choices=binaries, help='one or more binary name')
  53. build_local_parser = build_subparsers.add_parser('local',
  54. description='Bundle a local Python installation')
  55. build_local_parser.add_argument('-d', '--destination',
  56. help='AppImage destination')
  57. build_local_parser.add_argument('-p', '--python', help='python executable')
  58. build_manylinux_parser = build_subparsers.add_parser('manylinux',
  59. description='Bundle a manylinux Python installation')
  60. build_manylinux_parser.add_argument('tag',
  61. help='manylinux image tag (e.g. 2010_x86_64)')
  62. build_manylinux_parser.add_argument('abi',
  63. help='python ABI (e.g. cp37-cp37m)')
  64. build_manylinux_parser.add_argument('-b', '--bare',
  65. help='produce a bare image without the AppImage layer',
  66. action='store_true')
  67. build_manylinux_parser.add_argument('-c', '--clean',
  68. help='clean the cache after extraction', action='store_true')
  69. build_manylinux_parser.add_argument('-n', '--no-packaging',
  70. help='do not package (compress) the image', action='store_true')
  71. build_app_parser = build_subparsers.add_parser('app',
  72. description='Build a Python application using a base AppImage')
  73. build_app_parser.add_argument('appdir',
  74. help='path to the application metadata')
  75. build_app_parser.add_argument('-b', '--base-image',
  76. help='path to a base image on disk')
  77. build_app_parser.add_argument('-l', '--linux-tag',
  78. help='linux compatibility tag (e.g. manylinux1_x86_64)')
  79. build_app_parser.add_argument('-n', '--name',
  80. help='application name')
  81. build_app_parser.add_argument('--no-packaging',
  82. help='do not package the app', action='store_true')
  83. build_app_parser.add_argument('--python-tag',
  84. help='python compatibility tag (e.g. cp37-cp37m)')
  85. build_app_parser.add_argument('-p', '--python-version',
  86. help='python version (e.g. 3.8)')
  87. build_app_parser.add_argument('--in-tree-build',
  88. help='force pip in-tree-build',
  89. action='store_true',
  90. default=False)
  91. build_app_parser.add_argument('-x', '--extra-data', type=exists,
  92. help='extra application data (bundled under $APPDIR/)', nargs='+')
  93. list_parser = subparsers.add_parser('list',
  94. description='List Python versions installed in a manylinux image')
  95. list_parser.add_argument('tag',
  96. help='manylinux image tag (e.g. 2010_x86_64)')
  97. which_parser = subparsers.add_parser('which',
  98. description='Locate a binary dependency')
  99. which_parser.add_argument('binary', choices=binaries,
  100. help='name of the binary to locate')
  101. args = parser.parse_args()
  102. # Configure the verbosity
  103. if args.verbosity:
  104. from .utils import log
  105. log.set_level(args.verbosity)
  106. if args.appimagetool_version:
  107. from .utils import deps
  108. deps.APPIMAGETOOL_VERSION = args.appimagetool_version
  109. # check if no arguments are passed
  110. if args.command is None:
  111. parser.print_help()
  112. return
  113. # Call the requested command
  114. module = '.commands.' + args.command
  115. try:
  116. module += '.' + args.sub_command
  117. except AttributeError:
  118. pass
  119. command = import_module(module, package=__package__)
  120. # check if the module has a 'execute' subcommand
  121. # if not, display the help message
  122. if not hasattr(command, 'execute'):
  123. locals().get('{}_parser'.format(args.command)).print_help()
  124. return
  125. # execute the command
  126. command.execute(*command._unpack_args(args))
  127. if __name__ == '__main__':
  128. main()