Skip yanked packages and use newest version number.

* crates.io keeps yanked packages with the "yanked" attribute.
  For example, log-0.4.9 and log-0.4.10 were yanked so
  "get_rust_pkg log" should skip them.
* Compare version numbers before the publish id number.
  For example, lazy_static-1.1.1 was published after lazy_static-1.4.0,
  but "get_rust_pkg lazy_static" should fetch 1.4.0.

Test: get_rust_pkg.py -v log  # get log.0.4.8
Test: get_rust_pkg.py -v log-0.4.10  # get log.0.4.10
Test: get_rust_pkg.py -v lazy_static  # get lazy_static-1.4.0
Change-Id: Id005a91b75c0885285a76136bd6de19d0dafa5c1
This commit is contained in:
Chih-Hung Hsieh
2020-04-01 12:51:39 -07:00
parent ebfb3a9927
commit 7c6362a96b

View File

@@ -39,6 +39,10 @@ PKG_VERSION_PATTERN = r"(.*)-([0-9]+\.[0-9]+\.[0-9]+.*)"
PKG_VERSION_MATCHER = re.compile(PKG_VERSION_PATTERN) PKG_VERSION_MATCHER = re.compile(PKG_VERSION_PATTERN)
VERSION_PATTERN = r"([0-9]+)\.([0-9]+)\.([0-9]+)"
VERSION_MATCHER = re.compile(VERSION_PATTERN)
def parse_args(): def parse_args():
"""Parse main arguments.""" """Parse main arguments."""
@@ -72,6 +76,20 @@ def pkg_base_name(args, name):
return base, version return base, version
def get_version_numbers(version):
match = VERSION_MATCHER.match(version)
if match is not None:
return tuple(int(match.group(i)) for i in range(1, 4))
return (0, 0, 0)
def is_newer_version(args, prev_version, prev_id, check_version, check_id):
"""Return true if check_version+id is newer than prev_version+id."""
echo(args, "checking version={} id={}".format(check_version, check_id))
return ((get_version_numbers(check_version), check_id) >
(get_version_numbers(prev_version), prev_id))
def find_dl_path(args, name): def find_dl_path(args, name):
"""Ask crates.io for the latest version download path.""" """Ask crates.io for the latest version download path."""
base_name, version = pkg_base_name(args, name) base_name, version = pkg_base_name(args, name)
@@ -79,23 +97,32 @@ def find_dl_path(args, name):
echo(args, "get versions at {}".format(url)) echo(args, "get versions at {}".format(url))
with urllib.request.urlopen(url) as request: with urllib.request.urlopen(url) as request:
data = json.loads(request.read().decode()) data = json.loads(request.read().decode())
versions = data["versions"]
# version with the largest id number is assumed to be the latest # version with the largest id number is assumed to be the latest
last_id = 0 last_id = 0
dl_path = "" dl_path = ""
for v in versions: found_version = ""
for v in data["versions"]:
# Return the given version if it is found.
if version == v["num"]: if version == v["num"]:
dl_path = v["dl_path"] dl_path = v["dl_path"]
found_version = version
break break
if not version and int(v["id"]) > last_id: if version: # must find user specified version
continue
# Skip yanked version.
if v["yanked"]:
echo(args, "skip yanked version {}".format(v["num"]))
continue
# Remember the newest version.
if is_newer_version(args, found_version, last_id, v["num"], int(v["id"])):
last_id = int(v["id"]) last_id = int(v["id"])
version = v["num"] found_version = v["num"]
dl_path = v["dl_path"] dl_path = v["dl_path"]
if not dl_path: if not dl_path:
print("ERROR: cannot find version {} of package {}" print("ERROR: cannot find version {} of package {}"
.format(version, base_name)) .format(version, base_name))
sys.exit(1) sys.exit(1)
echo(args, "found download path for version {}".format(version)) echo(args, "found download path for version {}".format(found_version))
return dl_path return dl_path