mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-17 13:58:00 +08:00
This splits the backend into two parts: the local backend for desktop cellxgene and the AWS backend for hosted cellxgene. The local backend is in local_server while the hosted remains in server. The general idea is to copy everything from server to local_server, pull unneeded stuff out of local_server, and keep server as-is for this PR. Not touching server means all the infra and deployment code will continue working just as it did before so we can make those changes incrementally.
86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
import re
|
|
|
|
import click
|
|
import requests
|
|
from requests.exceptions import ConnectionError
|
|
|
|
from .. import __version__
|
|
|
|
# Official SemVer regex: https://semver.org/
|
|
SEMVER_FORMAT = re.compile(
|
|
r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*["
|
|
r"a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+("
|
|
r"?:\.[0-9a-zA-Z-]+)*))?$"
|
|
)
|
|
|
|
|
|
def log_upgrade_check():
|
|
# Sanity-check that the CLI version is a properly-formatted SemVer string
|
|
assert validate_version_str(__version__, release_only=False)
|
|
|
|
# Get the current latest release
|
|
try:
|
|
release_tag_generator = (r["tag_name"] for r in _request_cellxgene_releases())
|
|
latest_release = next(release_tag_generator, lambda tag_name: validate_version_str(tag_name))
|
|
if version_gt(latest_release, __version__):
|
|
click.echo(f"There's a new version of cellxgene available ({latest_release})!", err=True)
|
|
click.echo("To upgrade, run the following: pip install --upgrade cellxgene\n", err=True)
|
|
except (ConnectionError, RateLimitException):
|
|
click.echo("Upgrade check failed.\n")
|
|
|
|
|
|
class RateLimitException(Exception):
|
|
"""
|
|
Github API Rate Limit Exception
|
|
"""
|
|
|
|
|
|
def _request_cellxgene_releases():
|
|
def raise_on_rate_limit(response):
|
|
if response.status_code == 403 and res.headers.get("X-RateLimit-Remaining") == "0":
|
|
raise RateLimitException
|
|
|
|
url = "https://api.github.com/repos/chanzuckerberg/cellxgene/releases"
|
|
res = requests.get(url)
|
|
raise_on_rate_limit(res)
|
|
for release in res.json():
|
|
yield release
|
|
while "next" in res.links.keys():
|
|
res = requests.get(res.links["next"]["url"])
|
|
raise_on_rate_limit(res)
|
|
for release in res.json():
|
|
yield release
|
|
|
|
|
|
def validate_version_str(version_str, release_only=True):
|
|
"""
|
|
Test if a string conforms to SemVer format (https://semver.org/)
|
|
:param version_str: a string to be validated
|
|
:param release_only: only declare releases (not prereleases) valid
|
|
:return: True if the version string is of a valid SemVer format else False
|
|
"""
|
|
match = SEMVER_FORMAT.match(version_str)
|
|
has_match = match is not None
|
|
if has_match and release_only:
|
|
return not match.group("prerelease")
|
|
return has_match
|
|
|
|
|
|
def split_version(version_string):
|
|
"""
|
|
Split a SemVer-formatted string into its component integers
|
|
:param version_string: a SemVer string to be split
|
|
:return: an array of three integers
|
|
"""
|
|
match = SEMVER_FORMAT.match(version_string)
|
|
return [int(match.group(group)) for group in ["major", "minor", "patch"]]
|
|
|
|
|
|
def version_gt(left_version, right_version):
|
|
for left, right in zip(split_version(left_version), split_version(right_version)):
|
|
if left > right:
|
|
return True
|
|
elif right > left:
|
|
return False
|
|
return False
|