ghwt.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #!/usr/bin/env python3
  2. # Copyright 2016 The Meson development team
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. # Unless required by applicable law or agreed to in writing, software
  8. # distributed under the License is distributed on an "AS IS" BASIS,
  9. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. # See the License for the specific language governing permissions and
  11. # limitations under the License.
  12. # ghwt - GitHub WrapTool
  13. #
  14. # An emergency wraptool(1) replacement downloader that downloads
  15. # directly from GitHub in case wrapdb.mesonbuild.com is down.
  16. import urllib.request, json, sys, os, shutil, subprocess
  17. import configparser, hashlib
  18. req_timeout = 600.0
  19. private_repos = {'meson', 'wrapweb', 'meson-ci'}
  20. spdir = 'subprojects'
  21. def gh_get(url):
  22. r = urllib.request.urlopen(url, timeout=req_timeout)
  23. jd = json.loads(r.read().decode('utf-8'))
  24. return jd
  25. def list_projects():
  26. jd = gh_get('https://api.github.com/orgs/mesonbuild/repos')
  27. entries = [entry['name'] for entry in jd]
  28. entries = [e for e in entries if e not in private_repos]
  29. entries.sort()
  30. for i in entries:
  31. print(i)
  32. return 0
  33. def unpack(sproj, branch):
  34. tmpdir = os.path.join(spdir, sproj + '_ghwt')
  35. shutil.rmtree(tmpdir, ignore_errors=True)
  36. subprocess.check_call(['git', 'clone', '-b', branch, 'https://github.com/mesonbuild/{}.git'.format(sproj), tmpdir])
  37. usfile = os.path.join(tmpdir, 'upstream.wrap')
  38. assert(os.path.isfile(usfile))
  39. config = configparser.ConfigParser(interpolation=None)
  40. config.read(usfile)
  41. outdir = os.path.join(spdir, sproj)
  42. if 'directory' in config['wrap-file']:
  43. outdir = os.path.join(spdir, config['wrap-file']['directory'])
  44. if os.path.isdir(outdir):
  45. print('Subproject is already there. To update, nuke the {} dir and reinstall.'.format(outdir))
  46. shutil.rmtree(tmpdir)
  47. return 1
  48. us_url = config['wrap-file']['source_url']
  49. us = urllib.request.urlopen(us_url, timeout=req_timeout).read()
  50. h = hashlib.sha256()
  51. h.update(us)
  52. dig = h.hexdigest()
  53. should = config['wrap-file']['source_hash']
  54. if dig != should:
  55. print('Incorrect hash on download.')
  56. print(' expected:', should)
  57. print(' obtained:', dig)
  58. return 1
  59. ofilename = os.path.join(spdir, config['wrap-file']['source_filename'])
  60. with open(ofilename, 'wb') as ofile:
  61. ofile.write(us)
  62. if 'lead_directory_missing' in config['wrap-file']:
  63. os.mkdir(outdir)
  64. shutil.unpack_archive(ofilename, outdir)
  65. else:
  66. shutil.unpack_archive(ofilename, spdir)
  67. assert(os.path.isdir(outdir))
  68. shutil.move(os.path.join(tmpdir, '.git'), outdir)
  69. subprocess.check_call(['git', 'reset', '--hard'], cwd=outdir)
  70. shutil.rmtree(tmpdir)
  71. shutil.rmtree(os.path.join(outdir, '.git'))
  72. os.unlink(ofilename)
  73. def install(sproj, requested_branch=None):
  74. if not os.path.isdir(spdir):
  75. print('Run this in your source root and make sure there is a subprojects directory in it.')
  76. return 1
  77. blist = gh_get('https://api.github.com/repos/mesonbuild/{}/branches'.format(sproj))
  78. blist = [b['name'] for b in blist]
  79. blist = [b for b in blist if b != 'master']
  80. blist.sort()
  81. branch = blist[-1]
  82. if requested_branch is not None:
  83. if requested_branch in blist:
  84. branch = requested_branch
  85. else:
  86. print('Could not find user-requested branch', requested_branch)
  87. print('Available branches for', sproj, ':')
  88. print(blist)
  89. return 1
  90. print('Using branch', branch)
  91. return unpack(sproj, branch)
  92. def print_help():
  93. print('Usage:')
  94. print(sys.argv[0], 'list')
  95. print(sys.argv[0], 'install', 'package_name', '[branch_name]')
  96. def run(args):
  97. if not args or args[0] == '-h' or args[0] == '--help':
  98. print_help()
  99. return 1
  100. command = args[0]
  101. args = args[1:]
  102. if command == 'list':
  103. list_projects()
  104. return 0
  105. elif command == 'install':
  106. if len(args) == 1:
  107. return install(args[0])
  108. elif len(args) == 2:
  109. return install(args[0], args[1])
  110. else:
  111. print_help()
  112. return 1
  113. else:
  114. print('Unknown command')
  115. return 1
  116. if __name__ == '__main__':
  117. print('This is an emergency wrap downloader. Use only when wrapdb is down.')
  118. sys.exit(run(sys.argv[1:]))