1# Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights 2# reserved. Use of this source code is governed by a BSD-style license that 3# can be found in the LICENSE file. 4 5from __future__ import absolute_import 6from __future__ import print_function 7from file_util import * 8import git_util as git 9import os 10 11 12class VersionFormatter: 13 """ Formats CEF version information. """ 14 15 def __init__(self, chromium_src_path=None): 16 if chromium_src_path is None: 17 # Relative to the current directory. 18 script_path = os.path.abspath(os.path.dirname(__file__)) 19 chromium_src_path = os.path.abspath( 20 os.path.join(script_path, os.pardir, os.pardir)) 21 22 self.src_path = chromium_src_path 23 assert os.path.isdir(self.src_path), self.src_path 24 self.cef_path = os.path.join(self.src_path, 'cef') 25 assert os.path.isdir(self.cef_path), self.cef_path 26 27 # Whether to use the old version format by default. 28 self._old_format_default = \ 29 bool(int(os.environ.get('CEF_OLD_VERSION_FORMAT', '0'))) 30 31 self.reset() 32 33 def reset(self): 34 """ Reset internal state. """ 35 self._chrome_version = {} 36 self._cef_version = {} 37 self._cef_commit = {} 38 self._branch_version = {} 39 self._old_version_string = None 40 self._old_version_parts = {} 41 self._version_string = None 42 self._version_parts = {} 43 44 def get_chrome_version_components(self): 45 """ Returns Chrome version components. """ 46 if not bool(self._chrome_version): 47 file_path = os.path.join(self.src_path, 'chrome', 'VERSION') 48 assert os.path.isfile(file_path), file_path 49 read_version_file(file_path, self._chrome_version) 50 return self._chrome_version 51 52 def get_cef_version_components(self): 53 """ Returns CEF version components. """ 54 if not bool(self._cef_version): 55 file_path = os.path.join(self.cef_path, 'VERSION.in') 56 assert os.path.isfile(file_path), file_path 57 read_version_file(file_path, self._cef_version) 58 return self._cef_version 59 60 def get_cef_commit_components(self): 61 """ Returns CEF commit components. """ 62 if not bool(self._cef_commit): 63 hash = git.get_hash(self.cef_path) 64 number = git.get_commit_number(self.cef_path) 65 self._cef_commit = {'HASH': hash, 'NUMBER': number} 66 return self._cef_commit 67 68 def get_cef_branch_version_components(self): 69 """ Computes the CEF branch version. """ 70 if not bool(self._branch_version): 71 minor = 0 72 bugfix = 0 73 74 # Retrieve the list of commits that have been applied on the current 75 # branch since branching from origin/master. 76 hashes = git.get_branch_hashes(self.cef_path) 77 for hash in hashes: 78 # Determine if the API hash file was modified by the commit. 79 found = False 80 files = git.get_changed_files(self.cef_path, hash) 81 for file in files: 82 if file.find('cef_api_hash.h') >= 0: 83 found = True 84 break 85 86 if found: 87 minor += 1 88 bugfix = 0 89 else: 90 bugfix += 1 91 92 self._branch_version = {'MINOR': minor, 'PATCH': bugfix} 93 return self._branch_version 94 95 def get_chromium_version_string(self): 96 """ Returns the Chromium version number string. """ 97 chrome_version = self.get_chrome_version_components() 98 return '%s.%s.%s.%s' % (chrome_version['MAJOR'], chrome_version['MINOR'], 99 chrome_version['BUILD'], chrome_version['PATCH']) 100 101 @staticmethod 102 def _format_commit_hash(hash): 103 return 'g%s' % hash[:7] 104 105 # Computes old version numbers in the format "X.YYYY.A.gHHHHHHH". 106 # 107 # Where: 108 # - "X" is the CEF major version (currently 3). 109 # - "YYYY" is the Chromium branch. 110 # - "A" is an incremental number representing the number of commits in the 111 # current branch. This is roughly equivalent to the SVN revision number but 112 # on a per-branch basis and assists people in quickly determining the order 113 # of builds in the same branch (for bug reports, etc). 114 # - "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This 115 # facilitates lookup of the relevant commit history in Git. 116 # 117 # Example: "3.3729.1921.g62d140e" 118 def _compute_old_version(self): 119 if not self._old_version_string is None: 120 return 121 122 chrome_version = self.get_chrome_version_components() 123 cef_version = self.get_cef_version_components() 124 cef_commit = self.get_cef_commit_components() 125 cef_commit_hash = self._format_commit_hash(cef_commit['HASH']) 126 127 self._old_version_parts = { 128 'MAJOR': int(cef_version['CEF_MAJOR']), 129 'MINOR': int(chrome_version['BUILD']), 130 'PATCH': int(cef_commit['NUMBER']) 131 } 132 self._old_version_string = \ 133 '%s.%s.%s.%s' % (cef_version['CEF_MAJOR'], chrome_version['BUILD'], 134 cef_commit['NUMBER'], cef_commit_hash) 135 136 def _get_old_version_string(self): 137 self._compute_old_version() 138 return self._old_version_string 139 140 def _get_old_version_parts(self): 141 self._compute_old_version() 142 return self._old_version_parts 143 144 # Computes version numbers in the format: 145 # - "X.Y.Z+gHHHHHHH+chromium-A.B.C.D" for release branch builds. 146 # - "X.0.0-master.N+gHHHHHHH+chromium-A.B.C.D" for master branch builds. 147 # 148 # Where: 149 # - "X" is the Chromium major version (e.g. 74). 150 # - "Y" is an incremental number that starts at 0 when a release branch is 151 # created and changes only when the CEF C/C++ API changes (similar to how 152 # the CEF_API_HASH_UNIVERSAL value behaves in cef_version.h) (release branch 153 # only). 154 # - "Z" is an incremental number that starts at 0 when a release branch is 155 # created and changes on each commit, with reset to 0 when "Y" changes 156 # (release branch only). 157 # - "N" is an incremental number representing the number of commits (master 158 # branch only). 159 # - "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This 160 # facilitates lookup of the relevant commit history in Git. 161 # - "A.B.C.D" is the Chromium version (e.g. 74.0.3729.6). 162 # 163 # Examples: 164 # - "74.0.1+g62d140e+chromium-74.0.3729.6" for a release build. 165 # - "74.0.0-master.1920+g725ed88+chromium-74.0.3729.0" for a master build. 166 def _compute_version(self): 167 if not self._version_string is None: 168 return 169 170 chrome_version = self.get_chrome_version_components() 171 chrome_major = chrome_version['MAJOR'] 172 chrome_version_part = 'chromium-' + self.get_chromium_version_string() 173 174 cef_commit = self.get_cef_commit_components() 175 cef_commit_hash = self._format_commit_hash(cef_commit['HASH']) 176 177 # Determine whether the current commit is on a release branch. For example, 178 # if using Chrome build 3683, are we on CEF branch "3683" or "origin/3683"? 179 release_branch = chrome_version['BUILD'] 180 on_release_branch = ( 181 git.is_ancestor(self.cef_path, 'HEAD', release_branch) or 182 git.is_ancestor(self.cef_path, 'HEAD', 'origin/' + release_branch)) 183 184 if not on_release_branch: 185 # Not on a commit that is part of an official named release branch. See 186 # if we can get the name of the branch we are on (may be just "HEAD"). 187 cef_branch_name = git.get_branch_name(self.cef_path).split('/')[-1] 188 189 self._version_parts = {'MAJOR': int(chrome_major), 'MINOR': 0, 'PATCH': 0} 190 self._version_string = '%s.0.0-%s.%s+%s+%s' % \ 191 (chrome_major, cef_branch_name, cef_commit['NUMBER'], 192 cef_commit_hash, chrome_version_part) 193 else: 194 cef_branch = self.get_cef_branch_version_components() 195 196 self._version_parts = { 197 'MAJOR': int(chrome_major), 198 'MINOR': cef_branch['MINOR'], 199 'PATCH': cef_branch['PATCH'] 200 } 201 self._version_string = '%s.%d.%d+%s+%s' % \ 202 (chrome_major, cef_branch['MINOR'], cef_branch['PATCH'], 203 cef_commit_hash, chrome_version_part) 204 205 def _get_version_string(self): 206 self._compute_version() 207 return self._version_string 208 209 def _get_version_parts(self): 210 self._compute_version() 211 return self._version_parts 212 213 def get_version_string(self, oldFormat=None): 214 """ Returns the CEF version number string based on current checkout state. 215 """ 216 if oldFormat is None: 217 oldFormat = self._old_format_default 218 219 if oldFormat: 220 return self._get_old_version_string() 221 return self._get_version_string() 222 223 def get_version_parts(self, oldFormat=None): 224 """ Returns the CEF version number parts based on current checkout state. 225 """ 226 if oldFormat is None: 227 oldFormat = self._old_format_default 228 229 if oldFormat: 230 return self._get_old_version_parts() 231 return self._get_version_parts() 232 233 def get_plist_version_string(self, oldFormat=None): 234 """ Returns the CEF version number string for plist files based on current 235 checkout state. """ 236 parts = self.get_version_parts(oldFormat=oldFormat) 237 return "%d.%d.%d.0" % (parts['MAJOR'], parts['MINOR'], parts['PATCH']) 238 239 def get_dylib_version_string(self, oldFormat=None): 240 """ Returns the CEF version number string for dylib files based on current 241 checkout state. """ 242 parts = self.get_version_parts(oldFormat=oldFormat) 243 # Dylib format supports a max value of 255 for the 2nd and 3rd components. 244 return "%d%d.%d.%d" % (parts['MAJOR'], parts['MINOR'], parts['PATCH'] / 255, 245 parts['PATCH'] % 255) 246 247 248# Test the module. 249if __name__ == "__main__": 250 import sys 251 252 # Optionally specify a format. 253 formats = ['current', 'old', 'plist', 'dylib'] 254 if len(sys.argv) >= 2: 255 formats = [sys.argv[1]] 256 257 # Optionally specify the path to chromium/src. 258 chromium_src_path = None 259 if len(sys.argv) >= 3: 260 chromium_src_path = sys.argv[2] 261 262 formatter = VersionFormatter(chromium_src_path) 263 264 for format in formats: 265 if len(formats) > 1: 266 print(format) 267 268 if format == 'old': 269 print(formatter.get_version_string(True)) 270 elif format == 'dylib': 271 print(formatter.get_dylib_version_string()) 272 elif format == 'plist': 273 print(formatter.get_plist_version_string()) 274 else: 275 print(formatter.get_version_string(False)) 276