A semantic search engine for source code https://bitshift.benkurtovic.com/
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

147 строки
5.4 KiB

  1. """
  2. :synopsis: Main crawler module, to oversee all site-specific crawlers.
  3. Contains all website/framework-specific Class crawlers.
  4. """
  5. import logging, requests, time, threading
  6. from bitshift.crawler import indexer
  7. from ..codelet import Codelet
  8. from ..database import Database
  9. class GitHubCrawler(threading.Thread):
  10. """
  11. Crawler that retrieves links to all of GitHub's public repositories.
  12. GitHubCrawler is a threaded singleton that queries GitHub's API for urls
  13. to its public repositories, which it inserts into a :class:`Queue.Queue`
  14. shared with :class:`indexer.GitIndexer`.
  15. :ivar clone_queue: (:class:`Queue.Queue`) Contains :class:`GitRepository`
  16. with repository metadata retrieved by :class:`GitHubCrawler`, and other Git
  17. crawlers, to be processed by :class:`indexer.GitIndexer`.
  18. """
  19. def __init__(self, clone_queue):
  20. """
  21. Create an instance of the singleton `GitHubCrawler`.
  22. :param clone_queue: see :attr:`self.clone_queue`
  23. :type clone_queue: see :attr:`self.clone_queue`
  24. """
  25. self.clone_queue = clone_queue
  26. logging.info("Starting %s." % self.__class__.__name__)
  27. super(GitHubCrawler, self).__init__(name=self.__class__.__name__)
  28. def run(self):
  29. """
  30. Query the GitHub API for data about every public repository.
  31. Pull all of GitHub's repositories by making calls to its API in a loop,
  32. accessing a subsequent page of results via the "next" URL returned in an
  33. API response header. Uses Severyn Kozak's (sevko) authentication
  34. credentials. For every new repository, a :class:`GitRepository` is
  35. inserted into :attr:`self.clone_queue`.
  36. """
  37. next_api_url = "https://api.github.com/repositories"
  38. authentication_params = {
  39. "client_id" : "436cb884ae09be7f2a4e",
  40. "client_secret" : "8deeefbc2439409c5b7a092fd086772fe8b1f24e"
  41. }
  42. api_request_interval = 5e3 / 60 ** 2
  43. while len(next_api_url) > 0:
  44. start_time = time.time()
  45. response = requests.get(next_api_url, params=authentication_params)
  46. queue_percent_full = (float(self.clone_queue.qsize()) /
  47. self.clone_queue.maxsize) * 100
  48. logging.info("API call made. Limit remaining: %s. Queue-size: (%d"
  49. "%%) %d/%d" % (response.headers["x-ratelimit-remaining"],
  50. queue_percent_full, self.clone_queue.qsize(),
  51. self.clone_queue.maxsize))
  52. for repo in response.json():
  53. while self.clone_queue.full():
  54. time.sleep(1)
  55. self.clone_queue.put(indexer.GitRepository(
  56. repo["html_url"], repo["full_name"].replace("/", ""),
  57. "GitHub"))
  58. if int(response.headers["x-ratelimit-remaining"]) == 0:
  59. time.sleep(int(response.headers["x-ratelimit-reset"]) -
  60. time.time())
  61. next_api_url = response.headers["link"].split(">")[0][1:]
  62. sleep_time = api_request_interval - (time.time() - start_time)
  63. if sleep_time > 0:
  64. time.sleep(sleep_time)
  65. class BitbucketCrawler(threading.Thread):
  66. """
  67. Crawler that retrieves links to all of Bitbucket's public repositories.
  68. BitbucketCrawler is a threaded singleton that queries Bitbucket's API for
  69. urls to its public repositories, and inserts them as
  70. :class:`indexer.GitRepository` into a :class:`Queue.Queue` shared with
  71. :class:`indexer.GitIndexer`.
  72. :ivar clone_queue: (:class:`Queue.Queue`) The shared queue to insert
  73. :class:`indexer.GitRepository` repository urls into.
  74. """
  75. def __init__(self, clone_queue):
  76. """
  77. Create an instance of the singleton `BitbucketCrawler`.
  78. :param clone_queue: see :attr:`self.clone_queue`
  79. :type clone_queue: see :attr:`self.clone_queue`
  80. """
  81. self.clone_queue = clone_queue
  82. logging.info("Starting %s." % self.__class__.__name__)
  83. super(BitbucketCrawler, self).__init__(name=self.__class__.__name__)
  84. def run(self):
  85. """
  86. Query the Bitbucket API for data about every public repository.
  87. Query the Bitbucket API's "/repositories" endpoint and read its
  88. paginated responses in a loop; any "git" repositories have their
  89. clone-urls and names inserted into a :class:`indexer.GitRepository` in
  90. :attr:`self.clone_queue`.
  91. """
  92. next_api_url = "https://api.bitbucket.org/2.0/repositories"
  93. while True:
  94. response = requests.get(next_api_url).json()
  95. queue_percent_full = (float(self.clone_queue.qsize()) /
  96. self.clone_queue.maxsize) * 100
  97. logging.info("API call made. Queue-size: (%d%%) %d/%d" % (
  98. queue_percent_full, self.clone_queue.qsize(),
  99. self.clone_queue.maxsize))
  100. for repo in response["values"]:
  101. if repo["scm"] == "git":
  102. while self.clone_queue.full():
  103. time.sleep(1)
  104. clone_links = repo["links"]["clone"]
  105. clone_url = (clone[0]["href"] if clone[0]["name"] == "https"
  106. else clone[1]["href"])
  107. links.append("clone_url")
  108. self.clone_queue.put(indexer.GitRepository(
  109. clone_url, repo["full_name"], "Bitbucket"))
  110. next_api_url = response["next"]