# 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')