ghwt.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. def gh_get(url):
  21. r = urllib.request.urlopen(url, timeout=req_timeout)
  22. jd = json.loads(r.read().decode('utf-8'))
  23. return jd
  24. def list_projects():
  25. jd = gh_get('https://api.github.com/orgs/mesonbuild/repos')
  26. entries = [entry['name'] for entry in jd]
  27. entries = [e for e in entries if e not in private_repos]
  28. entries.sort()
  29. for i in entries:
  30. print(i)
  31. return 0
  32. def unpack(sproj, branch, outdir):
  33. subprocess.check_call(['git', 'clone', '-b', branch, 'https://github.com/mesonbuild/%s.git' % sproj, outdir])
  34. usfile = os.path.join(outdir, 'upstream.wrap')
  35. assert(os.path.isfile(usfile))
  36. config = configparser.ConfigParser()
  37. config.read(usfile)
  38. us_url = config['wrap-file']['source_url']
  39. us = urllib.request.urlopen(us_url, timeout=req_timeout).read()
  40. h = hashlib.sha256()
  41. h.update(us)
  42. dig = h.hexdigest()
  43. should = config['wrap-file']['source_hash']
  44. if dig != should:
  45. print('Incorrect hash on download.')
  46. print(' expected:', dig)
  47. print(' obtained:', should)
  48. return 1
  49. spdir = os.path.dirname(outdir)
  50. ofilename = os.path.join(spdir, config['wrap-file']['source_filename'])
  51. with open(ofilename, 'wb') as ofile:
  52. ofile.write(us)
  53. if 'lead_directory_missing' in config['wrap-file']:
  54. os.mkdir(outdir)
  55. shutil.unpack_archive(ofilename, outdir)
  56. else:
  57. shutil.unpack_archive(ofilename, spdir)
  58. extdir = os.path.join(spdir, config['wrap-file']['directory'])
  59. assert(os.path.isdir(extdir))
  60. shutil.move(os.path.join(outdir, '.git'), extdir)
  61. subprocess.check_call(['git', 'reset', '--hard'], cwd=extdir)
  62. shutil.rmtree(outdir)
  63. shutil.move(extdir, outdir)
  64. shutil.rmtree(os.path.join(outdir, '.git'))
  65. os.unlink(ofilename)
  66. def install(sproj):
  67. sproj_dir = os.path.join('subprojects', sproj)
  68. if not os.path.isdir('subprojects'):
  69. print('Run this in your source root and make sure there is a subprojects directory in it.')
  70. return 1
  71. if os.path.isdir(sproj_dir):
  72. print('Subproject is already there. To update, nuke the dir and reinstall.')
  73. return 1
  74. blist = gh_get('https://api.github.com/repos/mesonbuild/%s/branches' % sproj)
  75. blist = [b['name'] for b in blist]
  76. blist = [b for b in blist if b != 'master']
  77. blist.sort()
  78. branch = blist[-1]
  79. print('Using branch', branch)
  80. return unpack(sproj, branch, sproj_dir)
  81. def run(args):
  82. if not args or args[0] == '-h' or args[0] == '--help':
  83. print(sys.argv[0], 'list/install', 'package_name')
  84. return 1
  85. command = args[0]
  86. args = args[1:]
  87. if command == 'list':
  88. list_projects()
  89. return 0
  90. elif command == 'install':
  91. if len(args) != 1:
  92. print('Install requires exactly one argument.')
  93. return 1
  94. return install(args[0])
  95. else:
  96. print('Unknown command')
  97. return 1
  98. if __name__ == '__main__':
  99. print('This is an emergency wrap downloader. Use only when wrapdb is down.')
  100. sys.exit(run(sys.argv[1:]))