• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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