The little things give you away... A collection of various small helper stuff
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

94 lignes
3.4 KiB

  1. #!/usr/bin/env python3
  2. import html
  3. import logging
  4. import re
  5. import requests
  6. import shlex
  7. import sys
  8. import time
  9. GIT_URLS_OPTION = '--git-urls'
  10. GITGUD_COMPLETE_ITEMS_OPTION = '--gitgud-complete-items'
  11. MODES = (GIT_URLS_OPTION, GITGUD_COMPLETE_ITEMS_OPTION)
  12. mode = None
  13. name = False
  14. users = sys.argv[1:]
  15. if users and users[0] == '--name':
  16. name = True
  17. users = users[1:]
  18. if users and users[0] in MODES:
  19. mode = users[0]
  20. users = users[1:]
  21. assert users and (mode is None or mode in MODES) and not users[0].startswith('--'), f'Usage: github-list-repos [--name] [{" | ".join(MODES)}] USER [USER...]'
  22. def get(url):
  23. while True:
  24. logging.info(f'Fetching {url}')
  25. r = requests.get(url, headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0'})
  26. if r.status_code == 429:
  27. logging.warning(f'Got 429, sleeping and retrying')
  28. time.sleep(5)
  29. else:
  30. break
  31. return r
  32. def p(repoName):
  33. if mode is None:
  34. print(f'https://github.com/{repoName}')
  35. elif mode == GIT_URLS_OPTION:
  36. print(f'https://github.com/{repoName}.git')
  37. print(f'https://github.com/{repoName}.wiki.git')
  38. elif mode == GITGUD_COMPLETE_ITEMS_OPTION:
  39. print(f'web:complete:{repoName}')
  40. for user in users:
  41. r = get(f'https://github.com/{user}')
  42. if '<div id="org-repositories"' in r.text:
  43. # Organisation, complete list under /orgs/ with ?page=2 pagination
  44. if name:
  45. musername = re.search(r'<meta property="profile:username" content="([^"]*)" />', r.text)
  46. if not musername:
  47. print('Error: could not find profile:username meta tag', file = sys.stderr)
  48. sys.exit(1)
  49. mfullname = re.search(r'<h1\s(?:[^>]*\s)?class="(?:[^"]*\s)?h2(?:\s[^"]*)?"(?:\s[^>]*)?>(.*?)</h1>', r.text, flags = re.DOTALL)
  50. if not mfullname:
  51. print('Error: could not find name h1', file = sys.stderr)
  52. sys.exit(1)
  53. print(f'{shlex.quote(html.unescape(musername.group(1).strip()))} {shlex.quote(html.unescape(mfullname.group(1).strip()))}')
  54. r = get(f'https://github.com/orgs/{user}/repositories')
  55. page = 1
  56. while True:
  57. for m in re.finditer(r'<a itemprop="name codeRepository"\s(?:[^>]*\s)?data-hovercard-url="/([^/>"]+/[^/>"]+)/hovercard"', r.text):
  58. p(m.group(1))
  59. if '<a class="next_page"' not in r.text:
  60. # End of pagination
  61. break
  62. page += 1
  63. r = get(f'https://github.com/orgs/{user}/repositories?page={page}')
  64. else:
  65. # User, ?tab=repositories + cursor pagination
  66. if name:
  67. musername = re.search(r'<span\s(?:[^>]*\s)?class="(?:[^"]*\s)?vcard-username(?:\s[^"]*)?"(?:\s[^>]*)?>(.*?)</span>', r.text, flags = re.DOTALL)
  68. if not musername:
  69. print('Error: could not find vcard-username span', file = sys.stderr)
  70. sys.exit(1)
  71. if (m := re.search(r'<span\s(?:[^>]*\s)?class="(?:[^"]*\s)?vcard-fullname(?:\s[^"]*)?"(?:\s[^>]*)?>(.*?)</span>', r.text, flags = re.DOTALL)):
  72. fullname = html.unescape(m.group(1).strip())
  73. else:
  74. fullname = ''
  75. print(f'{shlex.quote(html.unescape(musername.group(1).strip()))} {shlex.quote(fullname)}')
  76. r = get(f'https://github.com/{user}?tab=repositories')
  77. while True:
  78. for m in re.finditer(r'<a href="/([^/>"]+/[^/>"]+)" itemprop="name codeRepository"(\s[^>]*)?>', r.text):
  79. p(m.group(1))
  80. if not (m := re.search(r'<a\s(?=(?:[^>]*\s)?class="next_page"(?:\s[^>]*)?>)(?:[^>]*\s)?href="/[^/?"]+\?page=([^&]+)&amp;tab=repositories"(?:\s[^>]*)?>', r.text)):
  81. # End of pagination
  82. break
  83. r = get(f'https://github.com/{user}?page={m.group(1)}&tab=repositories')