• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 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
22import updater_utils
23
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
36        self.new_version = None
37
38    def _setup_remote(self):
39        remotes = git_utils.list_remotes(self.proj_path)
40        for name, url in remotes.items():
41            if url == self.upstream_url.value:
42                self.upstream_remote_name = name
43
44            # Guess android remote name.
45            if '/platform/external/' in url:
46                self.android_remote_name = name
47
48        if self.upstream_remote_name is None:
49            self.upstream_remote_name = "update_origin"
50            git_utils.add_remote(self.proj_path, self.upstream_remote_name,
51                                 self.upstream_url.value)
52
53        git_utils.fetch(self.proj_path,
54                        [self.upstream_remote_name, self.android_remote_name])
55
56    def check(self):
57        """Checks upstream and returns whether a new version is available."""
58
59        self._setup_remote()
60        if git_utils.is_commit(self.metadata.third_party.version):
61            # Update to remote head.
62            self._check_head()
63        else:
64            # Update to latest version tag.
65            self._check_tag()
66
67    def get_current_version(self):
68        """Returns the latest version name recorded in METADATA."""
69        return self.metadata.third_party.version
70
71    def get_latest_version(self):
72        """Returns the latest version name in upstream."""
73        return self.new_version
74
75    def _check_tag(self):
76        tags = git_utils.list_remote_tags(self.proj_path,
77                                          self.upstream_remote_name)
78        current_ver = self.get_current_version()
79        self.new_version = updater_utils.get_latest_version(
80            current_ver, tags)
81        print('Current version: {}. Latest version: {}'.format(
82            current_ver, self.new_version), end='')
83
84    def _check_head(self):
85        commits = git_utils.get_commits_ahead(
86            self.proj_path, self.upstream_remote_name + '/master',
87            self.android_remote_name + '/master')
88
89        if not commits:
90            self.new_version = self.get_current_version()
91            return
92
93        self.new_version = commits[0]
94
95        commit_time = git_utils.get_commit_time(self.proj_path, commits[-1])
96        time_behind = datetime.datetime.now() - commit_time
97        print('{} commits ({} days) behind.'.format(
98            len(commits), time_behind.days), end='')
99
100    def _write_metadata(self, path):
101        updated_metadata = metadata_pb2.MetaData()
102        updated_metadata.CopyFrom(self.metadata)
103        updated_metadata.third_party.version = self.new_version
104        fileutils.write_metadata(path, updated_metadata)
105
106    def update(self):
107        """Updates the package.
108
109        Has to call check() before this function.
110        """
111        upstream_branch = self.upstream_remote_name + '/master'
112
113        print("Running `git merge {merge_branch}`..."
114              .format(merge_branch=self.new_version))
115        git_utils.merge(self.proj_path, self.new_version)
116        self._write_metadata(self.proj_path)
117        git_utils.add_file(self.proj_path, 'METADATA')
118