repopick: Use the builtin urllib to handle HTTP basic authentication
Also do proper URL encode while at it.
Change-Id: I64c0913eed535b109af2adc830288b3dd17c0cbb
diff --git a/build/tools/repopick.py b/build/tools/repopick.py
index 341a95e..fc3383f 100755
--- a/build/tools/repopick.py
+++ b/build/tools/repopick.py
@@ -27,14 +27,11 @@
import subprocess
import sys
import textwrap
+import urllib.parse
+import urllib.request
from functools import cmp_to_key
from xml.etree import ElementTree
-try:
- import requests
-except ImportError:
- import urllib.request
-
# cmp() is not available in Python 3, define it manually
# See https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
@@ -121,39 +118,49 @@
return reviews
-def fetch_query_via_http(remote_url, query):
- if "requests" in sys.modules:
- auth = None
- if os.path.isfile(os.getenv("HOME") + "/.gerritrc"):
- f = open(os.getenv("HOME") + "/.gerritrc", "r")
- for line in f:
- parts = line.rstrip().split("|")
- if parts[0] in remote_url:
- auth = requests.auth.HTTPBasicAuth(
- username=parts[1], password=parts[2]
- )
- status_code = "-1"
- if auth:
- url = "{0}/a/changes/?q={1}&o=CURRENT_REVISION&o=ALL_REVISIONS&o=ALL_COMMITS".format(
- remote_url, query
- )
- data = requests.get(url, auth=auth)
- status_code = str(data.status_code)
- if status_code != "200":
- # They didn't get good authorization or data, Let's try the old way
- url = "{0}/changes/?q={1}&o=CURRENT_REVISION&o=ALL_REVISIONS&o=ALL_COMMITS".format(
- remote_url, query
- )
- data = requests.get(url)
- reviews = json.loads(data.text[5:])
- else:
- """Given a query, fetch the change numbers via http"""
- url = "{0}/changes/?q={1}&o=CURRENT_REVISION&o=ALL_REVISIONS&o=ALL_COMMITS".format(
- remote_url, query
- )
- data = urllib.request.urlopen(url).read().decode("utf-8")
- reviews = json.loads(data[5:])
+def build_query_url(remote_url, query, auth):
+ p = urllib.parse.urlparse(remote_url)._asdict()
+ p["path"] = ("/a" if auth else "") + "/changes"
+ p["query"] = urllib.parse.urlencode(
+ {
+ "q": query,
+ "o": ["CURRENT_REVISION", "ALL_REVISIONS", "ALL_COMMITS"],
+ },
+ doseq=True,
+ )
+ return urllib.parse.urlunparse(urllib.parse.ParseResult(**p))
+
+def fetch_query_via_http(remote_url, query, auth=True):
+ """Given a query, fetch the change numbers via http"""
+ if auth:
+ gerritrc = os.path.expanduser("~/.gerritrc")
+ username = password = ""
+ if os.path.isfile(gerritrc):
+ with open(gerritrc, "r") as f:
+ for line in f:
+ parts = line.rstrip().split("|")
+ if parts[0] in remote_url:
+ username, password = parts[1], parts[2]
+
+ if username and password:
+ url = build_query_url(remote_url, query, auth)
+ password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
+ password_mgr.add_password(None, url, username, password)
+ auth_handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
+ opener = urllib.request.build_opener(auth_handler)
+ response = opener.open(url)
+ if response.getcode() != 200:
+ # They didn't get good authorization or data, Let's try the old way
+ return fetch_query_via_http(remote_url, query, False)
+ else:
+ return fetch_query_via_http(remote_url, query, False)
+ else:
+ url = build_query_url(remote_url, query, auth)
+ response = urllib.request.urlopen(url)
+
+ data = response.read().decode("utf-8")
+ reviews = json.loads(data[5:])
for review in reviews:
review["number"] = review.pop("_number")
@@ -165,7 +172,7 @@
if remote_url[0:3] == "ssh":
return fetch_query_via_ssh(remote_url, query)
elif remote_url[0:4] == "http":
- return fetch_query_via_http(remote_url, query.replace(" ", "+"))
+ return fetch_query_via_http(remote_url, query)
else:
raise Exception(
"Gerrit URL should be in the form http[s]://hostname/ or ssh://[user@]host[:port]"