blob: 4c878c847cfa9431326b4a8a96f6b8ca6882dce4 [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.
63 return self._check_head()
64
65 # Update to latest version tag.
66 return self._check_tag()
67
68 def _check_tag(self):
69 tags = git_utils.list_remote_tags(self.proj_path,
70 self.upstream_remote_name)
71 current_ver = self.metadata.third_party.version
72 self.new_version = updater_utils.get_latest_version(
73 current_ver, tags)
74 self.merge_from = self.new_version
75 print('Current version: {}. Latest version: {}'.format(
76 current_ver, self.new_version), end='')
77 return self.new_version != current_ver
78
79 def _check_head(self):
Haibo Huang24950e72018-06-29 14:53:39 -070080 commits = git_utils.get_commits_ahead(
81 self.proj_path, self.upstream_remote_name + '/master',
82 self.android_remote_name + '/master')
83
84 if not commits:
85 return False
86
Haibo Huang0d3810f2018-08-31 20:44:25 -070087 self.new_version = commits[0]
88
89 # See whether we have a local upstream.
90 branches = git_utils.list_remote_branches(
91 self.proj_path, self.android_remote_name)
92 upstreams = [
93 branch for branch in branches if branch.startswith('upstream-')]
94 if upstreams:
95 self.merge_from = '{}/{}'.format(
96 self.android_remote_name, upstreams[0])
97 else:
98 self.merge_from = 'update_origin/master'
99
Haibo Huang24950e72018-06-29 14:53:39 -0700100 commit_time = git_utils.get_commit_time(self.proj_path, commits[-1])
101 time_behind = datetime.datetime.now() - commit_time
102 print('{} commits ({} days) behind.'.format(
103 len(commits), time_behind.days), end='')
104 return True
105
106 def _write_metadata(self, path):
107 updated_metadata = metadata_pb2.MetaData()
108 updated_metadata.CopyFrom(self.metadata)
Haibo Huang0d3810f2018-08-31 20:44:25 -0700109 updated_metadata.third_party.version = self.new_version
Haibo Huang24950e72018-06-29 14:53:39 -0700110 fileutils.write_metadata(path, updated_metadata)
111
112 def update(self):
113 """Updates the package.
114
115 Has to call check() before this function.
116 """
Haibo Huang24950e72018-06-29 14:53:39 -0700117 upstream_branch = self.upstream_remote_name + '/master'
118
119 commits = git_utils.get_commits_ahead(
Haibo Huang0d3810f2018-08-31 20:44:25 -0700120 self.proj_path, self.merge_from, upstream_branch)
Haibo Huang24950e72018-06-29 14:53:39 -0700121 if commits:
Haibo Huang0d3810f2018-08-31 20:44:25 -0700122 print('{} is {} commits ahead of {}. {}'.format(
123 self.merge_from, len(commits), upstream_branch, commits))
Haibo Huang24950e72018-06-29 14:53:39 -0700124
125 commits = git_utils.get_commits_ahead(
Haibo Huang0d3810f2018-08-31 20:44:25 -0700126 self.proj_path, upstream_branch, self.merge_from)
Haibo Huang24950e72018-06-29 14:53:39 -0700127 if commits:
Haibo Huang0d3810f2018-08-31 20:44:25 -0700128 print('{} is {} commits behind of {}.'.format(
129 self.merge_from, len(commits), upstream_branch))
Haibo Huang24950e72018-06-29 14:53:39 -0700130
131 self._write_metadata(self.proj_path)
132 print("""
133This tool only updates METADATA. Run the following command to update:
134 git merge {merge_branch}
135
136To check all local changes:
137 git diff {merge_branch} HEAD
Haibo Huang0d3810f2018-08-31 20:44:25 -0700138""".format(merge_branch=self.merge_from))