# Copyright (C) 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Module to check updates from Git upstream.""" import datetime import fileutils import git_utils import metadata_pb2 # pylint: disable=import-error import updater_utils class GitUpdater(): """Updater for Git upstream.""" def __init__(self, url, proj_path, metadata): if url.type != metadata_pb2.URL.GIT: raise ValueError('Only support GIT upstream.') self.proj_path = proj_path self.metadata = metadata self.upstream_url = url self.upstream_remote_name = None self.android_remote_name = None self.new_version = None def _setup_remote(self): remotes = git_utils.list_remotes(self.proj_path) for name, url in remotes.items(): if url == self.upstream_url.value: self.upstream_remote_name = name # Guess android remote name. if '/platform/external/' in url: self.android_remote_name = name if self.upstream_remote_name is None: self.upstream_remote_name = "update_origin" git_utils.add_remote(self.proj_path, self.upstream_remote_name, self.upstream_url.value) git_utils.fetch(self.proj_path, [self.upstream_remote_name, self.android_remote_name]) def check(self): """Checks upstream and returns whether a new version is available.""" self._setup_remote() if git_utils.is_commit(self.metadata.third_party.version): # Update to remote head. self._check_head() else: # Update to latest version tag. self._check_tag() def get_current_version(self): """Returns the latest version name recorded in METADATA.""" return self.metadata.third_party.version def get_latest_version(self): """Returns the latest version name in upstream.""" return self.new_version def _check_tag(self): tags = git_utils.list_remote_tags(self.proj_path, self.upstream_remote_name) current_ver = self.get_current_version() self.new_version = updater_utils.get_latest_version( current_ver, tags) print('Current version: {}. Latest version: {}'.format( current_ver, self.new_version), end='') def _check_head(self): commits = git_utils.get_commits_ahead( self.proj_path, self.upstream_remote_name + '/master', self.android_remote_name + '/master') if not commits: self.new_version = self.get_current_version() return self.new_version = commits[0] commit_time = git_utils.get_commit_time(self.proj_path, commits[-1]) time_behind = datetime.datetime.now() - commit_time print('{} commits ({} days) behind.'.format( len(commits), time_behind.days), end='') def _write_metadata(self, path): updated_metadata = metadata_pb2.MetaData() updated_metadata.CopyFrom(self.metadata) updated_metadata.third_party.version = self.new_version fileutils.write_metadata(path, updated_metadata) def update(self): """Updates the package. Has to call check() before this function. """ upstream_branch = self.upstream_remote_name + '/master' print("Running `git merge {merge_branch}`..." .format(merge_branch=self.new_version)) git_utils.merge(self.proj_path, self.new_version) self._write_metadata(self.proj_path) git_utils.add_file(self.proj_path, 'METADATA')