Update tooling to use clang-format (issue #2171)

This commit is contained in:
Marshall Greenblatt 2017-05-18 10:41:47 +02:00
parent 816f700d3e
commit a566549e04
20 changed files with 295 additions and 353 deletions

View File

@ -27,73 +27,6 @@ def wrap_text(text, indent = '', maxchars = 80):
result += indent+line+'\n'
return result
def wrap_code(code, indent = ' ', maxchars = 80, splitchars = '(=,'):
""" Wrap the code lines to the specified number of characters. If
necessary a line will be broken and wrapped after one of the split
characters.
"""
output = ''
# normalize line endings
code = code.replace("\r\n", "\n")
# break the code chunk into lines
lines = string.split(code, '\n')
for line in lines:
if len(line) <= maxchars:
# line is short enough that it doesn't need to be wrapped
output += line + '\n'
continue
# retrieve the whitespace at the beginning of the line for later use
# as padding
ws = ''
for char in line:
if char.isspace():
ws += char
else:
break
# iterate over all characters in the string keeping track of where the
# last valid break character was found and wrapping the line
# accordingly
lastsplit = 0
nextsplit = -1
splitct = 0
pos = 0
for char in line:
if splitchars.find(char) >= 0:
# a new split position has been found
nextsplit = pos
size = pos - lastsplit + 1
if splitct > 0:
size += len(ws) + len(indent)
if size >= maxchars:
# the line is too long
section = line[lastsplit:nextsplit+1]
if len(section) > 0:
# output the line portion between the last split and the
# next split
if splitct > 0:
# start a new line and trim the line section
output += '\n'+ws+indent
section = string.strip(section)
output += section
lastsplit = nextsplit + 1
splitct += 1
pos += 1
if len(line) - lastsplit > 0:
# output the remainder of the line
section = line[lastsplit:]
if splitct > 0:
# start a new line and trim the line section
output += '\n'+ws+indent
section = string.strip(section)
output += section
output += '\n'
return output
def is_base_class(clsname):
""" Returns true if |clsname| is a known base (root) class in the object
hierarchy.
@ -392,8 +325,8 @@ _cre_retval = '([A-Za-z0-9_<>:,\*\&]{1,})'
_cre_typedef = '([A-Za-z0-9_<>:,\*\&\s]{1,})'
# regex for matching function return value and name combination
_cre_func = '([A-Za-z][A-Za-z0-9_<>:,\*\&\s]{1,})'
# regex for matching virtual function modifiers
_cre_vfmod = '([A-Za-z0-9_]{0,})'
# regex for matching virtual function modifiers + arbitrary whitespace
_cre_vfmod = '([\sA-Za-z0-9_]{0,})'
# regex for matching arbitrary whitespace
_cre_space = '[\s]{1,}'
# regex for matching optional virtual keyword
@ -502,6 +435,8 @@ def get_copyright():
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=$$HASH$$$
//
"""
# add the copyright year
@ -598,12 +533,36 @@ class obj_header:
# build the class objects
for attrib, name, parent_name, body in list:
# Style may place the ':' on the next line.
comment = get_comment(data, name+' :')
if len(comment) == 0:
comment = get_comment(data, name+"\n")
validate_comment(filename, name, comment)
self.classes.append(
obj_class(self, filename, attrib, name, parent_name, body,
comment, includes, forward_declares))
# extract empty classes
p = re.compile('\n'+_cre_attrib+
'\nclass'+_cre_space+_cre_cfname+_cre_space+
':'+_cre_space+'public'+_cre_virtual+
_cre_space+_cre_cfname+_cre_space+
'{};', re.MULTILINE | re.DOTALL)
list = p.findall(data)
if len(list) > 0:
added = True
# build the class objects
for attrib, name, parent_name in list:
# Style may place the ':' on the next line.
comment = get_comment(data, name+' :')
if len(comment) == 0:
comment = get_comment(data, name+"\n")
validate_comment(filename, name, comment)
self.classes.append(
obj_class(self, filename, attrib, name, parent_name, "",
comment, includes, forward_declares))
if added:
# a global function or class was read from the header file
self.filenames.append(filename)
@ -800,7 +759,7 @@ class obj_class:
# extract virtual functions
p = re.compile('\n'+_cre_space+_cre_attrib+'\n'+_cre_space+'virtual'+
_cre_space+_cre_func+'\((.*?)\)'+_cre_space+_cre_vfmod,
_cre_space+_cre_func+'\((.*?)\)'+_cre_vfmod,
re.MULTILINE | re.DOTALL)
list = p.findall(body)
@ -811,7 +770,7 @@ class obj_class:
validate_comment(filename, retval, comment)
self.virtualfuncs.append(
obj_function_virtual(self, attrib, retval, argval, comment,
vfmod))
vfmod.strip()))
def __repr__(self):
result = '/* '+dict_to_str(self.attribs)+' */ class '+self.name+"\n{"
@ -2038,7 +1997,7 @@ if __name__ == "__main__":
sys.stdout.write('\n')
# output the parsed C++ data
sys.stdout.write(wrap_code(str(header), '\t'))
sys.stdout.write(str(header))
# output the C API formatted data
defined_names = header.get_defined_structs()
@ -2069,4 +2028,4 @@ if __name__ == "__main__":
for func in funcs:
result += func.get_capi_proto(defined_names)+';\n'
result += '\n'
sys.stdout.write(wrap_code(result, '\t'))
sys.stdout.write(result)

View File

@ -1,2 +0,0 @@
@echo off
python.bat check_style.py %*

View File

@ -1,121 +0,0 @@
# Copyright (c) 2012 The Chromium Embedded Framework Authors.
# Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os, re, string, sys
from file_util import *
import git_util as git
# script directory
script_dir = os.path.dirname(__file__)
# CEF root directory
cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir))
# Valid extensions for files we want to lint.
DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)"
DEFAULT_LINT_BLACKLIST_REGEX = r"$^"
try:
# depot_tools may already be in the import path.
import cpplint
import cpplint_chromium
except ImportError, e:
# Search the PATH environment variable to find the depot_tools folder.
depot_tools = None;
paths = os.environ.get('PATH').split(os.pathsep)
for path in paths:
if os.path.exists(os.path.join(path, 'cpplint_chromium.py')):
depot_tools = path
break
if depot_tools is None:
print >> sys.stderr, 'Error: could not find depot_tools in PATH.'
sys.exit(2)
# Add depot_tools to import path.
sys.path.append(depot_tools)
import cpplint
import cpplint_chromium
# The default implementation of FileInfo.RepositoryName looks for the top-most
# directory that contains a .git folder. This is a problem for CEF because the
# CEF root folder (which may have an arbitrary name) lives inside the Chromium
# src folder. Reimplement in a dumb but sane way.
def patch_RepositoryName(self):
fullname = self.FullName()
project_dir = os.path.dirname(fullname)
if os.path.exists(fullname):
root_dir = project_dir
while os.path.basename(project_dir) != "src":
project_dir = os.path.dirname(project_dir)
prefix = os.path.commonprefix([root_dir, project_dir])
components = fullname[len(prefix) + 1:].split('/')
return string.join(["cef"] + components[1:], '/')
return fullname
def check_style(args, white_list = None, black_list = None):
""" Execute cpplint with the specified arguments. """
# Apply patches.
cpplint.FileInfo.RepositoryName = patch_RepositoryName
# Process cpplint arguments.
filenames = cpplint.ParseArguments(args)
if not white_list:
white_list = DEFAULT_LINT_WHITELIST_REGEX
white_regex = re.compile(white_list)
if not black_list:
black_list = DEFAULT_LINT_BLACKLIST_REGEX
black_regex = re.compile(black_list)
extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace]
for filename in filenames:
if white_regex.match(filename):
if black_regex.match(filename):
print "Ignoring file %s" % filename
else:
cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level,
extra_check_functions)
else:
print "Skipping file %s" % filename
print "Total errors found: %d\n" % cpplint._cpplint_state.error_count
return 1
if __name__ == "__main__":
# Start with the default parameters.
args = [
# * Disable the 'build/class' test because it errors uselessly with C
# structure pointers and template declarations.
# * Disable the 'runtime/references' test because CEF allows non-const
# arguments passed by reference.
# * Disable the 'runtime/sizeof' test because it has a high number of
# false positives and adds marginal value.
'--filter=-build/class,-runtime/references,-runtime/sizeof',
]
# Add anything passed on the command-line.
args += sys.argv[1:]
# Pre-process the arguments before passing to the linter.
new_args = []
changed = []
for arg in args:
if arg == '--changed':
# Add any changed files.
changed = git.get_changed_files(cef_dir)
elif arg[:2] == '--' or not os.path.isdir(arg):
# Pass argument unchanged.
new_args.append(arg)
else:
# Add all files in the directory.
new_args += get_files(os.path.join(arg, '*'))
if len(changed) > 0:
new_args += changed
check_style(new_args)

View File

@ -1,2 +0,0 @@
#!/bin/sh
python check_style.py $@

22
tools/clang_util.py Normal file
View File

@ -0,0 +1,22 @@
# Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file
from exec_util import exec_cmd
import sys
if sys.platform == 'win32':
# Force use of the clang-format version bundled with depot_tools.
clang_format_exe = 'clang-format.bat'
else:
clang_format_exe = 'clang-format'
def clang_format(file_contents):
result = exec_cmd(clang_format_exe, ".", file_contents)
if result['out'] != '':
output = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
output = output.replace("\r", "")
return output
return None

2
tools/fix_style.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
python.bat tools\fix_style.py %*

101
tools/fix_style.py Normal file
View File

@ -0,0 +1,101 @@
# Copyright (c) 2017 The Chromium Embedded Framework Authors.
# Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os, re, sys
from clang_util import clang_format
from file_util import *
from git_util import get_changed_files
# Valid extensions for files we want to clang-format.
DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h|.*\.mm)$"
DEFAULT_LINT_BLACKLIST_REGEX = r"$^"
def msg(filename, status):
if sys.platform == 'win32':
# Use Unix path separator.
filename = filename.replace("\\", "/")
if len(filename) > 60:
# Truncate the file path in a nice way.
filename = filename[-57:]
pos = filename.find("/")
if pos > 0:
filename = filename[pos:]
filename = "..." + filename
print "%-60s %s" % (filename, status)
updatect = 0
def update_file(filename):
oldcontents = read_file(filename)
if len(oldcontents) == 0:
msg(filename, "empty")
return;
newcontents = clang_format(oldcontents)
if newcontents is None:
raise Exception("Failed to process %s" % filename)
if newcontents != oldcontents:
msg(filename, "fixed")
global updatect
updatect += 1
write_file(filename, newcontents)
else:
msg(filename, "ok")
return
def fix_style(filenames, white_list = None, black_list = None):
""" Execute clang-format with the specified arguments. """
if not white_list:
white_list = DEFAULT_LINT_WHITELIST_REGEX
white_regex = re.compile(white_list)
if not black_list:
black_list = DEFAULT_LINT_BLACKLIST_REGEX
black_regex = re.compile(black_list)
for filename in filenames:
if filename.find('*') > 0:
# Expand wildcards.
filenames.extend(get_files(filename))
continue
if os.path.isdir(filename):
# Add directory contents.
filenames.extend(get_files(os.path.join(filename, "*")))
continue
if not os.path.exists(filename):
files = get_changed_files(".", filename)
if len(files) > 0:
filenames.extend(files)
else:
msg(filename, "missing")
continue
if white_regex.match(filename):
if black_regex.match(filename):
msg(filename, "ignored")
else:
update_file(filename)
else:
msg(filename, "skipped")
if __name__ == "__main__":
if len(sys.argv) == 1:
print "Usage: %s [file-path|git-hash|unstaged|staged] ..." % sys.argv[0]
print "\n Format C, C++ and ObjC files using Chromium's clang-format style."
print "\nOptions:"
print " file-path\tProcess the specified file or directory."
print " \t\tDirectories will be processed recursively."
print " \t\tThe \"*\" wildcard character is supported."
print " git-hash\tProcess all files changed in the specified Git commit."
print " unstaged\tProcess all unstaged files in the Git repo."
print " staged\t\tProcess all staged files in the Git repo."
sys.exit(1)
# Process anything passed on the command-line.
fix_style(sys.argv[1:])
print 'Done - Wrote %d files.' % updatect

2
tools/fix_style.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
python tools/fix_style.py $@

View File

@ -40,9 +40,21 @@ def get_commit_number(path = '.', branch = 'HEAD'):
return result['out'].strip()
return '0'
def get_changed_files(path = '.'):
def get_changed_files(path, hash):
""" Retrieves the list of changed files. """
# not implemented
if hash == 'unstaged':
cmd = "%s diff --name-only" % git_exe
elif hash == 'staged':
cmd = "%s diff --name-only --cached" % git_exe
else:
cmd = "%s diff-tree --no-commit-id --name-only -r %s" % (git_exe, hash)
result = exec_cmd(cmd, path)
if result['out'] != '':
files = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
files = files.replace('\r\n', '\n')
return files.strip().split("\n")
return []
def write_indented_output(output):

View File

@ -14,8 +14,7 @@ def make_capi_global_funcs(funcs, defined_names, translate_map, indent):
result += '\n'+format_comment(comment, indent, translate_map);
if func.get_retval().get_type().is_result_string():
result += indent+'// The resulting string must be freed by calling cef_string_userfree_free().\n'
result += wrap_code(indent+'CEF_EXPORT '+
func.get_capi_proto(defined_names)+';')
result += indent+'CEF_EXPORT '+func.get_capi_proto(defined_names)+';\n'
if first:
first = False
return result
@ -30,9 +29,8 @@ def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
if func.get_retval().get_type().is_result_string():
result += indent+'// The resulting string must be freed by calling cef_string_userfree_free().\n'
parts = func.get_capi_parts()
result += wrap_code(indent+parts['retval']+' (CEF_CALLBACK *'+
parts['name']+')('+
string.join(parts['args'], ', ')+');')
result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \
')('+string.join(parts['args'], ', ')+');\n'
if first:
first = False
return result
@ -81,6 +79,8 @@ def make_capi_header(header, filename):
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=$$HASH$$$
//
#ifndef $GUARD$
#define $GUARD$
@ -118,7 +118,10 @@ def make_capi_header(header, filename):
translated_includes.add(include)
declares = cls.get_forward_declares()
for declare in declares:
all_declares.add(header.get_class(declare).get_capi_name())
declare_cls = header.get_class(declare)
if declare_cls is None:
raise Exception('Unknown class: %s' % declare)
all_declares.add(declare_cls.get_capi_name())
# output translated includes
if len(translated_includes) > 0:
@ -195,24 +198,10 @@ extern "C" {
return result
def write_capi_header(header, header_dir, filename, backup):
capi_path = get_capi_file_name(os.path.join(header_dir, filename))
if path_exists(capi_path):
oldcontents = read_file(capi_path)
else:
oldcontents = ''
def write_capi_header(header, header_dir, filename):
file = get_capi_file_name(os.path.join(header_dir, filename))
newcontents = make_capi_header(header, filename)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(capi_path)
capi_dir = os.path.split(capi_path)[0]
if not os.path.isdir(capi_dir):
make_dir(capi_dir)
write_file(capi_path, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -76,31 +76,17 @@ def make_cpptoc_header(header, clsname):
result += '#endif // CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_'
return wrap_code(result)
return result
def write_cpptoc_header(header, clsname, dir, backup):
def write_cpptoc_header(header, clsname, dir):
# give the output file the same directory offset as the input file
cls = header.get_class(clsname)
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
file = os.path.join(dir, get_capi_name(clsname[3:], False)+'_cpptoc.h')
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
newcontents = make_cpptoc_header(header, clsname)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
file_dir = os.path.split(file)[0]
if not os.path.isdir(file_dir):
make_dir(file_dir)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -23,9 +23,7 @@ def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names):
if len(changes) > 0:
notify(name+' prototype changed')
return wrap_code(make_cpptoc_impl_proto(name, func, parts))+'{'+ \
changes+impl['body']+'\n}\n'
return result
return make_cpptoc_impl_proto(name, func, parts)+'{'+changes+impl['body']+'\n}\n\n'
def make_cpptoc_function_impl_new(cls, name, func, defined_names):
# retrieve the C API prototype parts
@ -62,7 +60,7 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names):
result += '\n #pragma message("Warning: "__FILE__": '+name+' is not implemented")'
result += '\n // END DELETE BEFORE MODIFYING'
result += '\n}\n\n'
return wrap_code(result)
return result
result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
@ -454,8 +452,8 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names):
if len(result) != result_len:
result += '\n'
result += '}\n'
return wrap_code(result)
result += '}\n\n'
return result
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, defined_names):
impl = ''
@ -633,7 +631,7 @@ def make_cpptoc_class_impl(header, clsname, impl):
'#endif\n\n'+ \
'template<> CefWrapperType '+parent_sig+'::kWrapperType = '+get_wrapper_type_enum(clsname)+';'
result += '\n\n'+wrap_code(const)
result += '\n\n'+const
return result
@ -671,7 +669,7 @@ def make_cpptoc_global_impl(header, impl):
return result
def write_cpptoc_impl(header, clsname, dir, backup):
def write_cpptoc_impl(header, clsname, dir):
if clsname is None:
# global file
file = dir
@ -691,16 +689,7 @@ def write_cpptoc_impl(header, clsname, dir, backup):
newcontents = make_cpptoc_global_impl(header, oldcontents)
else:
newcontents = make_cpptoc_class_impl(header, clsname, oldcontents)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
file_dir = os.path.split(file)[0]
if not os.path.isdir(file_dir):
make_dir(file_dir)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -119,31 +119,17 @@ def make_ctocpp_header(header, clsname):
result += '#endif // CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_'
return wrap_code(result)
return result
def write_ctocpp_header(header, clsname, dir, backup):
def write_ctocpp_header(header, clsname, dir):
# give the output file the same directory offset as the input file
cls = header.get_class(clsname)
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
file = os.path.join(dir, get_capi_name(clsname[3:], False)+'_ctocpp.h')
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
newcontents = make_ctocpp_header(header, clsname)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
file_dir = os.path.split(file)[0]
if not os.path.isdir(file_dir):
make_dir(file_dir)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -31,8 +31,8 @@ def make_ctocpp_function_impl_existing(clsname, name, func, impl):
if len(changes) > 0:
notify(name+' prototype changed')
return wrap_code(make_ctocpp_impl_proto(clsname, name, func, parts))+'{'+ \
changes+impl['body']+'\n}\n'
return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \
changes+impl['body']+'\n}\n\n'
def make_ctocpp_function_impl_new(clsname, name, func):
# build the C++ prototype
@ -91,7 +91,7 @@ def make_ctocpp_function_impl_new(clsname, name, func):
result += '\n #pragma message("Warning: "__FILE__": '+name+' is not implemented")'
result += '\n // END DELETE BEFORE MODIFYING'
result += '\n}\n\n'
return wrap_code(result)
return result
result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
@ -493,8 +493,8 @@ def make_ctocpp_function_impl_new(clsname, name, func):
if len(result) != result_len:
result += '\n'
result += '}\n'
return wrap_code(result)
result += '}\n\n'
return result
def make_ctocpp_function_impl(clsname, funcs, existing):
impl = ''
@ -634,7 +634,7 @@ def make_ctocpp_class_impl(header, clsname, impl):
'#endif\n\n'+ \
'template<> CefWrapperType '+parent_sig+'::kWrapperType = '+get_wrapper_type_enum(clsname)+';'
result += wrap_code(const)
result += const
return result
@ -669,7 +669,7 @@ def make_ctocpp_global_impl(header, impl):
return result
def write_ctocpp_impl(header, clsname, dir, backup):
def write_ctocpp_impl(header, clsname, dir):
if clsname is None:
# global file
file = dir
@ -689,16 +689,7 @@ def write_ctocpp_impl(header, clsname, dir, backup):
newcontents = make_ctocpp_global_impl(header, oldcontents)
else:
newcontents = make_ctocpp_class_impl(header, clsname, oldcontents)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
file_dir = os.path.split(file)[0]
if not os.path.isdir(file_dir):
make_dir(file_dir)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -17,6 +17,8 @@ def make_gypi_file(header):
# by hand. See the translator.README.txt file in the tools directory for
# more information.
#
# $hash=$$HASH$$$
#
{
'variables': {
@ -81,20 +83,9 @@ def make_gypi_file(header):
return result
def write_gypi_file(header, file, backup):
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
def write_gypi_file(header, file):
newcontents = make_gypi_file(header)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -28,9 +28,9 @@ def make_views_function_stub_impl(clsname, func):
if retval_default != '':
result += '\n return ' + retval_default + ';'
result += '\n}\n'
result += '\n}\n\n'
return wrap_code(result)
return result
def make_views_class_stub_impl(header, cls):
impl = ''
@ -64,23 +64,9 @@ def make_views_stub_impl(header):
result += impl
return result
def write_views_stub_impl(header, file, backup):
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
def write_views_stub_impl(header, file):
newcontents = make_views_stub_impl(header)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
file_dir = os.path.split(file)[0]
if not os.path.isdir(file_dir):
make_dir(file_dir)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# Test the module.
if __name__ == "__main__":

View File

@ -21,23 +21,12 @@ def make_wrapper_types_header(header):
result += '};\n\n' + \
'#endif // CEF_LIBCEF_DLL_WRAPPER_TYPES_H_'
return wrap_code(result)
return result
def write_wrapper_types_header(header, file, backup):
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
def write_wrapper_types_header(header, file):
newcontents = make_wrapper_types_header(header)
if newcontents != oldcontents:
if backup and oldcontents != '':
backup_file(file)
write_file(file, newcontents)
return True
return False
return (file, newcontents)
# test the module

View File

@ -1,3 +1,3 @@
@echo off
call python.bat translator.py --root-dir ..
call python.bat translator.py --root-dir .. %*
pause

View File

@ -4,6 +4,9 @@
import sys
from cef_parser import *
from clang_util import clang_format
from file_util import *
import hashlib
from make_capi_header import *
from make_cpptoc_header import *
from make_cpptoc_impl import *
@ -32,6 +35,9 @@ parser.add_option('--root-dir', dest='rootdir', metavar='DIR',
parser.add_option('--backup',
action='store_true', dest='backup', default=False,
help='create a backup of modified files')
parser.add_option('--force',
action='store_true', dest='force', default=False,
help='force rewrite of the file')
parser.add_option('-c', '--classes', dest='classes', action='append',
help='only translate the specified classes')
parser.add_option('-q', '--quiet',
@ -76,24 +82,80 @@ header.add_directory(cpp_header_dir, excluded_files)
header.add_directory(cpp_header_test_dir)
header.add_directory(cpp_header_views_dir)
# Track the number of files that were written.
writect = 0
#output the C API header
def update_file(file, newcontents):
""" Replaces the contents of |file| with |newcontents| if necessary. """
oldcontents = ''
oldhash = ''
if newcontents[-1:] != "\n":
# Add newline at end of file.
newcontents += "\n"
# clang-format is slow so we don't want to apply it if the pre-formatted
# content hasn't changed. To check for changes we embed a hash of the pre-
# formatted content in the resulting file.
hash_start = "$hash="
hash_end = "$"
hash_token = "$$HASH$$"
if not options.force and path_exists(file):
oldcontents = read_file(file)
# Extract the existing hash.
start = oldcontents.find(hash_start)
if start > 0:
end = oldcontents.find(hash_end, start + len(hash_start))
if end > 0:
oldhash = oldcontents[start + len(hash_start):end]
# Compute the new hash.
rev = hashlib.sha1(newcontents).digest();
newhash = ''.join(format(ord(i),'0>2x') for i in rev)
if oldhash == newhash:
# Pre-formatted contents have not changed.
return
newcontents = newcontents.replace(hash_token, newhash, 1)
# Apply clang-format for C/C++ files.
if os.path.splitext(file)[1][1:] in ('cc', 'cpp', 'h'):
result = clang_format(newcontents)
if result != None:
newcontents = result
else:
raise Exception("Call to clang-format failed")
if options.backup and oldcontents != '':
backup_file(file)
filedir = os.path.split(file)[0]
if not os.path.isdir(filedir):
make_dir(filedir)
write_file(file, newcontents)
global writect
writect += 1
# output the C API header
if not options.quiet:
sys.stdout.write('In C API header directory '+capi_header_dir+'...\n')
filenames = sorted(header.get_file_names())
for filename in filenames:
if not options.quiet:
sys.stdout.write('Generating '+filename+' C API header...\n')
writect += write_capi_header(header, capi_header_dir, filename,
options.backup)
update_file(*write_capi_header(header, capi_header_dir, filename))
# output the wrapper types header
if not options.quiet:
sys.stdout.write('Generating wrapper types header...\n')
writect += write_wrapper_types_header(header,
wrapper_types_header,
options.backup)
update_file(*write_wrapper_types_header(header, wrapper_types_header))
# build the list of classes to parse
allclasses = header.get_class_names()
@ -111,12 +173,12 @@ classes = sorted(classes)
# output CppToC global file
if not options.quiet:
sys.stdout.write('Generating CppToC global implementation...\n')
writect += write_cpptoc_impl(header, None, cpptoc_global_impl, options.backup)
update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl))
# output CToCpp global file
if not options.quiet:
sys.stdout.write('Generating CToCpp global implementation...\n')
writect += write_ctocpp_impl(header, None, ctocpp_global_impl, options.backup)
update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl))
# output CppToC class files
if not options.quiet:
@ -124,10 +186,10 @@ if not options.quiet:
for cls in classes:
if not options.quiet:
sys.stdout.write('Generating '+cls+'CppToC class header...\n')
writect += write_cpptoc_header(header, cls, cpptoc_dir, options.backup)
update_file(*write_cpptoc_header(header, cls, cpptoc_dir))
if not options.quiet:
sys.stdout.write('Generating '+cls+'CppToC class implementation...\n')
writect += write_cpptoc_impl(header, cls, cpptoc_dir, options.backup)
update_file(*write_cpptoc_impl(header, cls, cpptoc_dir))
# output CppToC class files
if not options.quiet:
@ -135,20 +197,20 @@ if not options.quiet:
for cls in classes:
if not options.quiet:
sys.stdout.write('Generating '+cls+'CToCpp class header...\n')
writect += write_ctocpp_header(header, cls, ctocpp_dir, options.backup)
update_file(*write_ctocpp_header(header, cls, ctocpp_dir))
if not options.quiet:
sys.stdout.write('Generating '+cls+'CToCpp class implementation...\n')
writect += write_ctocpp_impl(header, cls, ctocpp_dir, options.backup)
update_file(*write_ctocpp_impl(header, cls, ctocpp_dir))
# output the gypi file
if not options.quiet:
sys.stdout.write('Generating '+gypi_file+' file...\n')
writect += write_gypi_file(header, gypi_file, options.backup)
update_file(*write_gypi_file(header, gypi_file))
# output the views stub file
if not options.quiet:
sys.stdout.write('Generating '+views_stub_impl+' file...\n')
writect += write_views_stub_impl(header, views_stub_impl, options.backup)
update_file(*write_views_stub_impl(header, views_stub_impl))
if not options.quiet:
sys.stdout.write('Done - Wrote '+str(writect)+' files.\n')

View File

@ -1,2 +1,2 @@
#!/bin/sh
python translator.py --root-dir ..
python translator.py --root-dir .. $@