1# Copyright (C) 2018 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"""Base class for all updaters.""" 15 16from pathlib import Path 17 18import git_utils 19import fileutils 20# pylint: disable=import-error 21import metadata_pb2 # type: ignore 22 23 24class Updater: 25 """Base Updater that defines methods common for all updaters.""" 26 def __init__(self, proj_path: Path, old_identifier: metadata_pb2.Identifier, 27 old_ver: str) -> None: 28 self._proj_path = fileutils.get_absolute_project_path(proj_path) 29 self._old_identifier = old_identifier 30 self._old_identifier.version = old_identifier.version if old_identifier.version else old_ver 31 32 self._new_identifier = metadata_pb2.Identifier() 33 self._new_identifier.CopyFrom(old_identifier) 34 35 self._alternative_new_ver: str | None = None 36 37 self._has_errors = False 38 39 def is_supported_url(self) -> bool: 40 """Returns whether the url is supported.""" 41 raise NotImplementedError() 42 43 def setup_remote(self) -> None: 44 raise NotImplementedError() 45 46 def validate(self) -> str: 47 """Checks whether aosp version is what it claims to be.""" 48 self.setup_remote() 49 return git_utils.diff_stat(self._proj_path, 'a', self._old_identifier.version) 50 51 def check(self) -> None: 52 """Checks whether a new version is available.""" 53 raise NotImplementedError() 54 55 def update(self) -> Path | None: 56 """Updates the package. 57 58 Has to call check() before this function. Returns either the temporary 59 dir it stored the old version in after upgrading or None. 60 """ 61 raise NotImplementedError() 62 63 def rollback(self) -> bool: 64 """Rolls the current update back. 65 66 This is an optional operation. Returns whether the rollback succeeded. 67 """ 68 return False 69 70 def update_metadata(self, metadata: metadata_pb2.MetaData) -> metadata_pb2: 71 """Rewrites the metadata file.""" 72 updated_metadata = metadata_pb2.MetaData() 73 updated_metadata.CopyFrom(metadata) 74 updated_metadata.third_party.ClearField("version") 75 for identifier in updated_metadata.third_party.identifier: 76 if identifier == self.current_identifier: 77 identifier.CopyFrom(self.latest_identifier) 78 return updated_metadata 79 80 @property 81 def project_path(self) -> Path: 82 """Gets absolute path to the project.""" 83 return self._proj_path 84 85 @property 86 def current_version(self) -> str: 87 """Gets the current version.""" 88 return self._old_identifier.version 89 90 @property 91 def current_identifier(self) -> metadata_pb2.Identifier: 92 """Gets the current identifier.""" 93 return self._old_identifier 94 95 @property 96 def latest_version(self) -> str: 97 """Gets latest version.""" 98 return self._new_identifier.version 99 100 @property 101 def latest_identifier(self) -> metadata_pb2.Identifier: 102 """Gets identifier for latest version.""" 103 return self._new_identifier 104 105 @property 106 def has_errors(self) -> bool: 107 """Gets whether this update had an error.""" 108 return self._has_errors 109 110 @property 111 def alternative_latest_version(self) -> str | None: 112 """Gets alternative latest version.""" 113 return self._alternative_new_ver 114 115 def refresh_without_upgrading(self) -> None: 116 """Uses current version and url as the latest to refresh project.""" 117 self._new_identifier.version = self._old_identifier.version 118 self._new_identifier.value = self._old_identifier.value 119 120 def set_new_version(self, version: str) -> None: 121 """Uses the passed version as the latest to upgrade project.""" 122 self._new_identifier.version = version 123 124 def set_custom_version(self, custom_version: str) -> None: 125 """Uses the passed version as the latest to upgrade project if the 126 passed version is not older than the current version.""" 127 if git_utils.is_ancestor(self._proj_path, self._old_identifier.version, custom_version): 128 self._new_identifier.version = custom_version 129 else: 130 raise RuntimeError( 131 f"Cannot upgrade to {custom_version}. " 132 f"Either the current version is newer than {custom_version} " 133 f"or the current version in the METADATA file is not correct.") 134