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.
 
 
 

110 lignes
4.1 KiB

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