diff --git a/tools/cef_parser.py b/tools/cef_parser.py index bb1a44957..cae49abb5 100644 --- a/tools/cef_parser.py +++ b/tools/cef_parser.py @@ -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) diff --git a/tools/check_style.bat b/tools/check_style.bat deleted file mode 100644 index 8bd86b20c..000000000 --- a/tools/check_style.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -python.bat check_style.py %* diff --git a/tools/check_style.py b/tools/check_style.py deleted file mode 100644 index 0ac54ca1f..000000000 --- a/tools/check_style.py +++ /dev/null @@ -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) diff --git a/tools/check_style.sh b/tools/check_style.sh deleted file mode 100755 index 3a38a6ab7..000000000 --- a/tools/check_style.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -python check_style.py $@ diff --git a/tools/clang_util.py b/tools/clang_util.py new file mode 100644 index 000000000..3b8e8b422 --- /dev/null +++ b/tools/clang_util.py @@ -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 diff --git a/tools/fix_style.bat b/tools/fix_style.bat new file mode 100644 index 000000000..4270518a0 --- /dev/null +++ b/tools/fix_style.bat @@ -0,0 +1,2 @@ +@echo off +python.bat tools\fix_style.py %* diff --git a/tools/fix_style.py b/tools/fix_style.py new file mode 100644 index 000000000..e65dbeb6d --- /dev/null +++ b/tools/fix_style.py @@ -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 diff --git a/tools/fix_style.sh b/tools/fix_style.sh new file mode 100755 index 000000000..c466ab06c --- /dev/null +++ b/tools/fix_style.sh @@ -0,0 +1,2 @@ +#!/bin/sh +python tools/fix_style.py $@ diff --git a/tools/git_util.py b/tools/git_util.py index 027243ec7..a7552de14 100644 --- a/tools/git_util.py +++ b/tools/git_util.py @@ -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): diff --git a/tools/make_capi_header.py b/tools/make_capi_header.py index 8434df2e2..09bc091e3 100644 --- a/tools/make_capi_header.py +++ b/tools/make_capi_header.py @@ -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 diff --git a/tools/make_cpptoc_header.py b/tools/make_cpptoc_header.py index a8c58e119..da76fe50f 100644 --- a/tools/make_cpptoc_header.py +++ b/tools/make_cpptoc_header.py @@ -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 diff --git a/tools/make_cpptoc_impl.py b/tools/make_cpptoc_impl.py index a0497d0ba..950717613 100644 --- a/tools/make_cpptoc_impl.py +++ b/tools/make_cpptoc_impl.py @@ -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 diff --git a/tools/make_ctocpp_header.py b/tools/make_ctocpp_header.py index 64b4e8e7d..227b5fa32 100644 --- a/tools/make_ctocpp_header.py +++ b/tools/make_ctocpp_header.py @@ -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 diff --git a/tools/make_ctocpp_impl.py b/tools/make_ctocpp_impl.py index 36e7eed8c..be4393587 100644 --- a/tools/make_ctocpp_impl.py +++ b/tools/make_ctocpp_impl.py @@ -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 diff --git a/tools/make_gypi_file.py b/tools/make_gypi_file.py index 465130ebd..b447f6dcd 100644 --- a/tools/make_gypi_file.py +++ b/tools/make_gypi_file.py @@ -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 diff --git a/tools/make_views_stub_impl.py b/tools/make_views_stub_impl.py index 93b3dfca4..42200dd26 100644 --- a/tools/make_views_stub_impl.py +++ b/tools/make_views_stub_impl.py @@ -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__": diff --git a/tools/make_wrapper_types_header.py b/tools/make_wrapper_types_header.py index 48535ce5f..05c29318d 100644 --- a/tools/make_wrapper_types_header.py +++ b/tools/make_wrapper_types_header.py @@ -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 diff --git a/tools/translator.bat b/tools/translator.bat index 2905032c4..a63c8d17c 100644 --- a/tools/translator.bat +++ b/tools/translator.bat @@ -1,3 +1,3 @@ @echo off -call python.bat translator.py --root-dir .. +call python.bat translator.py --root-dir .. %* pause \ No newline at end of file diff --git a/tools/translator.py b/tools/translator.py index 73c9f8ea8..0b07f160f 100644 --- a/tools/translator.py +++ b/tools/translator.py @@ -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') diff --git a/tools/translator.sh b/tools/translator.sh index 03f5a2d8a..9304a9f1f 100755 --- a/tools/translator.sh +++ b/tools/translator.sh @@ -1,2 +1,2 @@ #!/bin/sh -python translator.py --root-dir .. +python translator.py --root-dir .. $@