blob: bde48a70d498c0b18cfb4ff80f7548891e0e3a82 [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
22
23
24class GitUpdater():
25 """Updater for Git upstream."""
26
27 def __init__(self, url, proj_path, metadata):
28 if url.type != metadata_pb2.URL.GIT:
29 raise ValueError('Only support GIT upstream.')
30 self.proj_path = proj_path
31 self.metadata = metadata
32 self.upstream_url = url
33 self.upstream_remote_name = None
34 self.android_remote_name = None
35 self.latest_commit = None
36
37 def _setup_remote(self):
38 remotes = git_utils.list_remotes(self.proj_path)
39 for name, url in remotes.items():
40 if url == self.upstream_url.value:
41 self.upstream_remote_name = name
42
43 # Guess android remote name.
44 if '/platform/external/' in url:
45 self.android_remote_name = name
46
47 if self.upstream_remote_name is None:
48 self.upstream_remote_name = "update_origin"
49 git_utils.add_remote(self.proj_path, self.upstream_remote_name,
50 self.upstream_url.value)
51
52 git_utils.fetch(self.proj_path,
53 [self.upstream_remote_name, self.android_remote_name])
54
55 def check(self):
56 """Checks upstream and returns whether a new version is available."""
57
58 self._setup_remote()
59 commits = git_utils.get_commits_ahead(
60 self.proj_path, self.upstream_remote_name + '/master',
61 self.android_remote_name + '/master')
62
63 if not commits:
64 return False
65
66 self.latest_commit = commits[0]
67 commit_time = git_utils.get_commit_time(self.proj_path, commits[-1])
68 time_behind = datetime.datetime.now() - commit_time
69 print('{} commits ({} days) behind.'.format(
70 len(commits), time_behind.days), end='')
71 return True
72
73 def _write_metadata(self, path):
74 updated_metadata = metadata_pb2.MetaData()
75 updated_metadata.CopyFrom(self.metadata)
76 updated_metadata.third_party.version = self.latest_commit
77 fileutils.write_metadata(path, updated_metadata)
78
79 def update(self):
80 """Updates the package.
81
82 Has to call check() before this function.
83 """
84 # See whether we have a local upstream.
85 branches = git_utils.list_remote_branches(
86 self.proj_path, self.android_remote_name)
87 upstreams = [
88 branch for branch in branches if branch.startswith('upstream-')]
89 if len(upstreams) == 1:
90 merge_branch = '{}/{}'.format(
91 self.android_remote_name, upstreams[0])
92 elif not upstreams:
93 merge_branch = 'update_origin/master'
94 else:
95 raise ValueError('Ambiguous upstream branch. ' + upstreams)
96
97 upstream_branch = self.upstream_remote_name + '/master'
98
99 commits = git_utils.get_commits_ahead(
100 self.proj_path, merge_branch, upstream_branch)
101 if commits:
102 print('Warning! {} is {} commits ahead of {}. {}'.format(
103 merge_branch, len(commits), upstream_branch, commits))
104
105 commits = git_utils.get_commits_ahead(
106 self.proj_path, upstream_branch, merge_branch)
107 if commits:
108 print('Warning! {} is {} commits behind of {}.'.format(
109 merge_branch, len(commits), upstream_branch))
110
111 self._write_metadata(self.proj_path)
112 print("""
113This tool only updates METADATA. Run the following command to update:
114 git merge {merge_branch}
115
116To check all local changes:
117 git diff {merge_branch} HEAD
118""".format(merge_branch=merge_branch))