1# Copyright (C) 2020 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Module to check updates from crates.io.""" 15 16import json 17import re 18import urllib.request 19 20import archive_utils 21from base_updater import Updater 22import metadata_pb2 # type: ignore 23import updater_utils 24 25CRATES_IO_URL_PATTERN: str = (r'^https:\/\/crates.io\/crates\/([-\w]+)') 26 27CRATES_IO_URL_RE: re.Pattern = re.compile(CRATES_IO_URL_PATTERN) 28 29 30class CratesUpdater(Updater): 31 """Updater for crates.io packages.""" 32 33 dl_path: str 34 package: str 35 36 def is_supported_url(self) -> bool: 37 if self._old_url.type != metadata_pb2.URL.HOMEPAGE: 38 return False 39 match = CRATES_IO_URL_RE.match(self._old_url.value) 40 if match is None: 41 return False 42 self.package = match.group(1) 43 return True 44 45 def check(self) -> None: 46 """Checks crates.io and returns whether a new version is available.""" 47 url = "https://crates.io/api/v1/crates/" + self.package 48 with urllib.request.urlopen(url) as request: 49 data = json.loads(request.read().decode()) 50 self._new_ver = data["crate"]["max_version"] 51 url = url + "/" + self._new_ver 52 with urllib.request.urlopen(url) as request: 53 data = json.loads(request.read().decode()) 54 self.dl_path = data["version"]["dl_path"] 55 56 def update(self) -> None: 57 """Updates the package. 58 59 Has to call check() before this function. 60 """ 61 try: 62 url = 'https://crates.io' + self.dl_path 63 temporary_dir = archive_utils.download_and_extract(url) 64 package_dir = archive_utils.find_archive_root(temporary_dir) 65 updater_utils.replace_package(package_dir, self._proj_path) 66 finally: 67 urllib.request.urlcleanup() 68