blob: 81ee93d5d6575140bc3790dd4b4eaf9421b1d5f7 [file] [log] [blame]
Haibo Huang24950e72018-06-29 14:53:39 -07001# 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"""Module to check updates from Git upstream."""
15
16
17import datetime
18
19import fileutils
20import git_utils
21import metadata_pb2 # pylint: disable=import-error
Haibo Huang0d3810f2018-08-31 20:44:25 -070022import updater_utils
Haibo Huang24950e72018-06-29 14:53:39 -070023
24
25class GitUpdater():
26 """Updater for Git upstream."""
27
28 def __init__(self, url, proj_path, metadata):
29 if url.type != metadata_pb2.URL.GIT:
30 raise ValueError('Only support GIT upstream.')
31 self.proj_path = proj_path
32 self.metadata = metadata
33 self.upstream_url = url
34 self.upstream_remote_name = None
35 self.android_remote_name = None
Haibo Huang0d3810f2018-08-31 20:44:25 -070036 self.new_version = None
37 self.merge_from = None
Haibo Huang24950e72018-06-29 14:53:39 -070038
39 def _setup_remote(self):
40 remotes = git_utils.list_remotes(self.proj_path)
41 for name, url in remotes.items():
42 if url == self.upstream_url.value:
43 self.upstream_remote_name = name
44
45 # Guess android remote name.
46 if '/platform/external/' in url:
47 self.android_remote_name = name
48
49 if self.upstream_remote_name is None:
50 self.upstream_remote_name = "update_origin"
51 git_utils.add_remote(self.proj_path, self.upstream_remote_name,
52 self.upstream_url.value)
53
54 git_utils.fetch(self.proj_path,
55 [self.upstream_remote_name, self.android_remote_name])
56
57 def check(self):
58 """Checks upstream and returns whether a new version is available."""
59
60 self._setup_remote()
Haibo Huang0d3810f2018-08-31 20:44:25 -070061 if git_utils.is_commit(self.metadata.third_party.version):
62 # Update to remote head.
Haibo Huang39aaab62019-01-25 12:23:03 -080063 self._check_head()
64 else:
65 # Update to latest version tag.
66 self._check_tag()
Haibo Huang0d3810f2018-08-31 20:44:25 -070067
Haibo Huang39aaab62019-01-25 12:23:03 -080068 def get_current_version(self):
69 """Returns the latest version name recorded in METADATA."""
70 return self.metadata.third_party.version
71
72 def get_latest_version(self):
73 """Returns the latest version name in upstream."""
74 return self.new_version
Haibo Huang0d3810f2018-08-31 20:44:25 -070075
76 def _check_tag(self):
77 tags = git_utils.list_remote_tags(self.proj_path,
78 self.upstream_remote_name)
Haibo Huang39aaab62019-01-25 12:23:03 -080079 current_ver = self.get_current_version()
Haibo Huang0d3810f2018-08-31 20:44:25 -070080 self.new_version = updater_utils.get_latest_version(
81 current_ver, tags)
82 self.merge_from = self.new_version
83 print('Current version: {}. Latest version: {}'.format(
84 current_ver, self.new_version), end='')
Haibo Huang0d3810f2018-08-31 20:44:25 -070085
86 def _check_head(self):
Haibo Huang24950e72018-06-29 14:53:39 -070087 commits = git_utils.get_commits_ahead(
88 self.proj_path, self.upstream_remote_name + '/master',
89 self.android_remote_name + '/master')
90
91 if not commits:
Haibo Huang39aaab62019-01-25 12:23:03 -080092 self.new_version = self.get_current_version()
93 return
Haibo Huang24950e72018-06-29 14:53:39 -070094
Haibo Huang0d3810f2018-08-31 20:44:25 -070095 self.new_version = commits[0]
96
97 # See whether we have a local upstream.
98 branches = git_utils.list_remote_branches(
99 self.proj_path, self.android_remote_name)
100 upstreams = [
101 branch for branch in branches if branch.startswith('upstream-')]
102 if upstreams:
103 self.merge_from = '{}/{}'.format(
104 self.android_remote_name, upstreams[0])
105 else:
106 self.merge_from = 'update_origin/master'
107
Haibo Huang24950e72018-06-29 14:53:39 -0700108 commit_time = git_utils.get_commit_time(self.proj_path, commits[-1])
109 time_behind = datetime.datetime.now() - commit_time
110 print('{} commits ({} days) behind.'.format(
111 len(commits), time_behind.days), end='')
Haibo Huang24950e72018-06-29 14:53:39 -0700112
113 def _write_metadata(self, path):
114 updated_metadata = metadata_pb2.MetaData()
115 updated_metadata.CopyFrom(self.metadata)
Haibo Huang0d3810f2018-08-31 20:44:25 -0700116 updated_metadata.third_party.version = self.new_version
Haibo Huang24950e72018-06-29 14:53:39 -0700117 fileutils.write_metadata(path, updated_metadata)
118
119 def update(self):
120 """Updates the package.
121
122 Has to call check() before this function.
123 """
Haibo Huang24950e72018-06-29 14:53:39 -0700124 upstream_branch = self.upstream_remote_name + '/master'
125
126 commits = git_utils.get_commits_ahead(
Haibo Huang0d3810f2018-08-31 20:44:25 -0700127 self.proj_path, self.merge_from, upstream_branch)
Haibo Huang24950e72018-06-29 14:53:39 -0700128 if commits:
Haibo Huang0d3810f2018-08-31 20:44:25 -0700129 print('{} is {} commits ahead of {}. {}'.format(
130 self.merge_from, len(commits), upstream_branch, commits))
Haibo Huang24950e72018-06-29 14:53:39 -0700131
132 commits = git_utils.get_commits_ahead(
Haibo Huang0d3810f2018-08-31 20:44:25 -0700133 self.proj_path, upstream_branch, self.merge_from)
Haibo Huang24950e72018-06-29 14:53:39 -0700134 if commits:
Haibo Huang0d3810f2018-08-31 20:44:25 -0700135 print('{} is {} commits behind of {}.'.format(
136 self.merge_from, len(commits), upstream_branch))
Haibo Huang24950e72018-06-29 14:53:39 -0700137
Haibo Huang39aaab62019-01-25 12:23:03 -0800138 print("Running `git merge {merge_branch}`..."
139 .format(merge_branch=self.merge_from))
Haibo Huang0cabc2e2019-01-18 13:29:48 -0800140 git_utils.merge(self.proj_path, self.merge_from)
Haibo Huangc3c0cd42019-01-29 15:24:45 -0800141 self._write_metadata(self.proj_path)
142 git_utils.add_file(self.proj_path, 'METADATA')