mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add initial support for API versioning (see #3836)
- Generated files are now created when running cef_create_projects or the new version_manager.py tool. These files are still created in the cef/ source tree (same location as before) but Git ignores them due to the generated .gitignore file. - API hashes are committed to Git as a new cef_api_versions.json file. This file is used for both code generation and CEF version calculation (replacing the previous usage of cef_api_hash.h for this purpose). It will be updated by the CEF admin before merging breaking API changes upstream. - As an added benefit to the above, contributor PRs will no longer contain generated code that is susceptible to frequent merge conflicts. - From a code generation perspective, the main difference is that we now use versioned structs (e.g. cef_browser_0_t instead of cef_browser_t) on the libcef (dll/framework) side. Most of the make_*.py tool changes are related to supporting this. - From the client perspective, you can now define CEF_API_VERSION in the project configuration (or get CEF_EXPERIMENTAL by default). This define will change the API exposed in CEF’s include/ and include/capi header files. All client-side targets including libcef_dll_wrapper will need be recompiled when changing this define. - Examples of the new API-related define usage are provided in cef_api_version_test.h, api_version_test_impl.cc and api_version_unittest.cc. To test: - Run `ceftests --gtest_filter=ApiVersionTest.*` - Add `cef_api_version=13300` to GN_DEFINES. Re-run configure, build and ceftests steps. - Repeat with 13301, 13302, 13303 (all supported test versions).
This commit is contained in:
@ -3,35 +3,45 @@
|
||||
# can be found in the LICENSE file.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import codecs
|
||||
import fnmatch
|
||||
from glob import iglob
|
||||
from io import open
|
||||
import json
|
||||
import os
|
||||
import fnmatch
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def read_file(name, normalize=True):
|
||||
def read_file(path, normalize=True):
|
||||
""" Read a file. """
|
||||
try:
|
||||
with open(name, 'r', encoding='utf-8') as f:
|
||||
# read the data
|
||||
data = f.read()
|
||||
if normalize:
|
||||
# normalize line endings
|
||||
data = data.replace("\r\n", "\n")
|
||||
return data
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to read file ' + name + ': ' + strerror)
|
||||
raise
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
# read the data
|
||||
data = f.read()
|
||||
if normalize:
|
||||
# normalize line endings
|
||||
data = data.replace("\r\n", "\n")
|
||||
return data
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def write_file(name, data):
|
||||
def write_file(path, data, overwrite=True, quiet=True):
|
||||
""" Write a file. """
|
||||
if not overwrite and os.path.exists(path):
|
||||
return False
|
||||
|
||||
if not quiet:
|
||||
print('Writing file %s' % path)
|
||||
|
||||
try:
|
||||
with open(name, 'w', encoding='utf-8', newline='\n') as f:
|
||||
with open(path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
# write the data
|
||||
if sys.version_info.major == 2:
|
||||
f.write(data.decode('utf-8'))
|
||||
@ -39,57 +49,67 @@ def write_file(name, data):
|
||||
f.write(data)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to write file ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def path_exists(name):
|
||||
def path_exists(path):
|
||||
""" Returns true if the path currently exists. """
|
||||
return os.path.exists(name)
|
||||
return os.path.exists(path)
|
||||
|
||||
|
||||
def write_file_if_changed(name, data):
|
||||
def write_file_if_changed(path, data, quiet=True):
|
||||
""" Write a file if the contents have changed. Returns True if the file was written. """
|
||||
if path_exists(name):
|
||||
old_contents = read_file(name)
|
||||
if path_exists(path):
|
||||
old_contents = read_file(path)
|
||||
assert not old_contents is None, path
|
||||
else:
|
||||
old_contents = ''
|
||||
|
||||
if (data != old_contents):
|
||||
write_file(name, data)
|
||||
write_file(path, data, quiet=quiet)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def backup_file(name):
|
||||
def backup_file(path):
|
||||
""" Rename the file to a name that includes the current time stamp. """
|
||||
move_file(name, name + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
|
||||
move_file(path, path + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
|
||||
|
||||
|
||||
def copy_file(src, dst, quiet=True):
|
||||
""" Copy a file. """
|
||||
if not os.path.isfile(src):
|
||||
return False
|
||||
|
||||
try:
|
||||
shutil.copy2(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Transferring ' + src + ' file.\n')
|
||||
shutil.copy2(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' +
|
||||
strerror)
|
||||
sys.stderr.write('ERROR: Failed to copy file from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def move_file(src, dst, quiet=True):
|
||||
""" Move a file. """
|
||||
if not os.path.isfile(src):
|
||||
return False
|
||||
|
||||
try:
|
||||
shutil.move(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Moving ' + src + ' file.\n')
|
||||
print('Moving ' + src + ' file.')
|
||||
shutil.move(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' +
|
||||
strerror)
|
||||
sys.stderr.write('ERROR: Failed to move file from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
||||
|
||||
def copy_files(src_glob, dst_folder, quiet=True):
|
||||
@ -102,56 +122,62 @@ def copy_files(src_glob, dst_folder, quiet=True):
|
||||
copy_file(fname, dst, quiet)
|
||||
|
||||
|
||||
def remove_file(name, quiet=True):
|
||||
def remove_file(path, quiet=True):
|
||||
""" Remove the specified file. """
|
||||
try:
|
||||
if path_exists(name):
|
||||
os.remove(name)
|
||||
if path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Removing ' + name + ' file.\n')
|
||||
print('Removing ' + path + ' file.')
|
||||
os.remove(path)
|
||||
return True
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to remove file ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to remove file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return False
|
||||
|
||||
|
||||
def copy_dir(src, dst, quiet=True):
|
||||
""" Copy a directory tree. """
|
||||
try:
|
||||
remove_dir(dst, quiet)
|
||||
shutil.copytree(src, dst)
|
||||
if not quiet:
|
||||
sys.stdout.write('Transferring ' + src + ' directory.\n')
|
||||
print('Transferring ' + src + ' directory.')
|
||||
shutil.copytree(src, dst)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst +
|
||||
': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to copy directory from ' + src + ' to ' +
|
||||
dst + ': ' + strerror)
|
||||
raise
|
||||
|
||||
|
||||
def remove_dir(name, quiet=True):
|
||||
def remove_dir(path, quiet=True):
|
||||
""" Remove the specified directory. """
|
||||
try:
|
||||
if path_exists(name):
|
||||
shutil.rmtree(name)
|
||||
if path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Removing ' + name + ' directory.\n')
|
||||
print('Removing ' + path + ' directory.')
|
||||
shutil.rmtree(path)
|
||||
return True
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to remove directory ' + path + ': ' +
|
||||
strerror)
|
||||
raise
|
||||
return False
|
||||
|
||||
|
||||
def make_dir(name, quiet=True):
|
||||
def make_dir(path, quiet=True):
|
||||
""" Create the specified directory. """
|
||||
try:
|
||||
if not path_exists(name):
|
||||
if not path_exists(path):
|
||||
if not quiet:
|
||||
sys.stdout.write('Creating ' + name + ' directory.\n')
|
||||
os.makedirs(name)
|
||||
print('Creating ' + path + ' directory.')
|
||||
os.makedirs(path)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('Failed to create directory ' + name + ': ' + strerror)
|
||||
sys.stderr.write('ERROR: Failed to create directory ' + path + ': ' +
|
||||
strerror)
|
||||
raise
|
||||
|
||||
|
||||
@ -180,13 +206,17 @@ def get_files_recursive(directory, pattern):
|
||||
yield filename
|
||||
|
||||
|
||||
def read_version_file(file, args):
|
||||
def read_version_file(path, args):
|
||||
""" Read and parse a version file (key=value pairs, one per line). """
|
||||
lines = read_file(file).split("\n")
|
||||
contents = read_file(path)
|
||||
if contents is None:
|
||||
return False
|
||||
lines = contents.split("\n")
|
||||
for line in lines:
|
||||
parts = line.split('=', 1)
|
||||
if len(parts) == 2:
|
||||
args[parts[0]] = parts[1]
|
||||
return True
|
||||
|
||||
|
||||
def eval_file(src):
|
||||
@ -199,3 +229,48 @@ def normalize_path(path):
|
||||
if sys.platform == 'win32':
|
||||
return path.replace('\\', '/')
|
||||
return path
|
||||
|
||||
|
||||
def read_json_file(path):
|
||||
""" Read and parse a JSON file. Returns a list/dictionary or None. """
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
with codecs.open(path, 'r', encoding='utf-8') as fp:
|
||||
return json.load(fp)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def _bytes_encoder(z):
|
||||
if isinstance(z, bytes):
|
||||
return str(z, 'utf-8')
|
||||
else:
|
||||
type_name = z.__class__.__name__
|
||||
raise TypeError(f"Object of type {type_name} is not serializable")
|
||||
|
||||
|
||||
def write_json_file(path, data, overwrite=True, quiet=True):
|
||||
""" Serialize and write a JSON file. Returns True on success. """
|
||||
if not overwrite and os.path.exists(path):
|
||||
return False
|
||||
|
||||
if not quiet:
|
||||
print('Writing file %s' % path)
|
||||
|
||||
try:
|
||||
with open(path, 'w', encoding='utf-8') as fp:
|
||||
json.dump(
|
||||
data,
|
||||
fp,
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
default=_bytes_encoder)
|
||||
except IOError as e:
|
||||
(errno, strerror) = e.args
|
||||
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
|
||||
raise
|
||||
return True
|
||||
|
Reference in New Issue
Block a user