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(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) -> None:
56        """Updates the package.
57
58        Has to call check() before this function.
59        """
60        raise NotImplementedError()
61
62    def rollback(self) -> bool:
63        """Rolls the current update back.
64
65        This is an optional operation.  Returns whether the rollback succeeded.
66        """
67        return False
68
69    def update_metadata(self, metadata: metadata_pb2.MetaData) -> metadata_pb2:
70        """Rewrites the metadata file."""
71        updated_metadata = metadata_pb2.MetaData()
72        updated_metadata.CopyFrom(metadata)
73        updated_metadata.third_party.ClearField("version")
74        for identifier in updated_metadata.third_party.identifier:
75            if identifier == self.current_identifier:
76                identifier.CopyFrom(self.latest_identifier)
77        return updated_metadata
78
79    @property
80    def project_path(self) -> Path:
81        """Gets absolute path to the project."""
82        return self._proj_path
83
84    @property
85    def current_version(self) -> str:
86        """Gets the current version."""
87        return self._old_identifier.version
88
89    @property
90    def current_identifier(self) -> metadata_pb2.Identifier:
91        """Gets the current identifier."""
92        return self._old_identifier
93
94    @property
95    def latest_version(self) -> str:
96        """Gets latest version."""
97        return self._new_identifier.version
98
99    @property
100    def latest_identifier(self) -> metadata_pb2.Identifier:
101        """Gets identifier for latest version."""
102        return self._new_identifier
103
104    @property
105    def has_errors(self) -> bool:
106        """Gets whether this update had an error."""
107        return self._has_errors
108
109    @property
110    def alternative_latest_version(self) -> str | None:
111        """Gets alternative latest version."""
112        return self._alternative_new_ver
113
114    def refresh_without_upgrading(self) -> None:
115        """Uses current version and url as the latest to refresh project."""
116        self._new_identifier.version = self._old_identifier.version
117        self._new_identifier.value = self._old_identifier.value
118
119    def set_new_version(self, version: str) -> None:
120        """Uses the passed version as the latest to upgrade project."""
121        self._new_identifier.version = version
122