Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: tools/protoc_wrapper/protoc_wrapper.py

Issue 2239383002: GN proto_libary refactoring. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix LITE_RUNTIME Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2016 The Chromium Authors. All rights reserved.
petrcermak 2016/08/15 13:00:06 The date should NOT be changed. See https://chromi
kraynov 2016/08/15 13:37:49 Acknowledged.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 A simple wrapper for protoc. 7 A simple wrapper for protoc.
8 8 Script for //third_party/protobuf/proto_library.gni .
9 - Adds includes in generated headers. 9 Features:
10 - Handles building with system protobuf as an option. 10 - Automatic include insertion.
petrcermak 2016/08/15 13:00:06 Maybe add a hash ("#include") so that it's easier
kraynov 2016/08/15 13:37:50 Acknowledged.
11 - Preventing bad proto names.
petrcermak 2016/08/15 13:00:06 s/Preventing/Prevents/
kraynov 2016/08/15 13:37:49 Acknowledged.
11 """ 12 """
12 13
13 import fnmatch 14 from __future__ import print_function
14 import optparse 15 import optparse
15 import os.path 16 import os.path
16 import shutil
17 import subprocess 17 import subprocess
18 import sys 18 import sys
19 import tempfile 19 import tempfile
20 20
21 PROTOC_INCLUDE_POINT = '// @@protoc_insertion_point(includes)\n' 21 PROTOC_INCLUDE_POINT = "// @@protoc_insertion_point(includes)"
22
23 def ModifyHeader(header_file, extra_header):
24 """Adds |extra_header| to |header_file|. Returns 0 on success.
25
26 |extra_header| is the name of the header file to include.
27 |header_file| is a generated protobuf cpp header.
28 """
29 include_point_found = False
30 header_contents = []
31 with open(header_file) as f:
32 for line in f:
33 header_contents.append(line)
34 if line == PROTOC_INCLUDE_POINT:
35 extra_header_msg = '#include "%s"\n' % extra_header
36 header_contents.append(extra_header_msg)
37 include_point_found = True;
38 if not include_point_found:
39 return 1
40
41 with open(header_file, 'wb') as f:
42 f.write(''.join(header_contents))
43 return 0
44
45 def ScanForBadFiles(scan_root):
46 """Scan for bad file names, see http://crbug.com/386125 for details.
47 Returns True if any filenames are bad. Outputs errors to stderr.
48
49 |scan_root| is the path to the directory to be recursively scanned.
50 """
51 badname = False
52 real_scan_root = os.path.realpath(scan_root)
53 for dirpath, dirnames, filenames in os.walk(real_scan_root):
54 matches = fnmatch.filter(filenames, '*-*.proto')
55 if len(matches) > 0:
56 if not badname:
57 badname = True
58 sys.stderr.write('proto files must not have hyphens in their names ('
59 'see http://crbug.com/386125 for more information):\n')
60 for filename in matches:
61 sys.stderr.write(' ' + os.path.join(real_scan_root,
62 dirpath, filename) + '\n')
63 return badname
64 22
65 23
66 def RewriteProtoFilesForSystemProtobuf(path): 24 def ProtocGenOptions(options):
petrcermak 2016/08/15 13:00:06 The name is a noun, so it suggests that it's a cla
petrcermak 2016/08/15 13:00:06 If I understand correctly, all methods in this fil
kraynov 2016/08/15 13:37:49 Acknowledged.
kraynov 2016/08/15 13:37:50 It's standalone utility. I've followed the previou
67 wrapper_dir = tempfile.mkdtemp() 25 if options is not None:
petrcermak 2016/08/15 13:00:06 Unless '' (empty string) are valid |options|, you
petrcermak 2016/08/15 13:00:06 Don't use nested if statements unless necessary:
kraynov 2016/08/15 13:37:49 Acknowledged.
68 try: 26 if options.endswith(":"):
69 for filename in os.listdir(path): 27 return options
70 if not filename.endswith('.proto'): 28 else:
71 continue 29 return options + ":"
72 with open(os.path.join(path, filename), 'r') as src_file: 30 else:
73 with open(os.path.join(wrapper_dir, filename), 'w') as dst_file: 31 return ""
74 for line in src_file:
75 # Remove lines that break build with system protobuf.
76 # We cannot optimize for lite runtime, because system lite runtime
77 # does not have a Chromium-specific hack to retain unknown fields.
78 # Similarly, it does not understand corresponding option to control
79 # the usage of that hack.
80 if 'LITE_RUNTIME' in line or 'retain_unknown_fields' in line:
81 continue
82 dst_file.write(line)
83 32
84 return wrapper_dir 33
85 except: 34 def StripProtos(protos):
petrcermak 2016/08/15 13:00:06 (Feel free to ignore) I would personally use a com
kraynov 2016/08/15 13:37:49 Acknowledged.
86 shutil.rmtree(wrapper_dir) 35 stripped = []
87 raise 36 for filename in protos:
37 if not filename.endswith(".proto"):
38 raise RuntimeError("Invalid proto filename extension: " + filename)
39 if "-" in filename:
40 raise RuntimeError("Proto files must not have hyphens in their names "
petrcermak 2016/08/15 13:00:06 suggestion "Proto file names must not contain hyph
kraynov 2016/08/15 13:37:50 Acknowledged.
41 "(see http://crbug.com/386125 for more information).")
petrcermak 2016/08/15 13:00:06 supernit: Your error ends with a period here, but
kraynov 2016/08/15 13:37:49 Acknowledged.
42 # Remove .proto extension.
43 stripped.append(filename.rsplit(".", 1)[0])
44 return stripped
45
46
47 def WriteIncludes(headers, include):
48 for filename in headers:
49 include_point_found = False
50 contents = []
51 with open(filename) as f:
52 for line in f:
53 stripped_line = line.strip()
54 contents.append(stripped_line)
55 if stripped_line == PROTOC_INCLUDE_POINT:
petrcermak 2016/08/15 13:00:06 you should add an if statement asserting that incl
kraynov 2016/08/15 13:37:49 Acknowledged.
56 extra_statement = '#include "{0}"'.format(include)
57 contents.append(extra_statement)
58 include_point_found = True
59
60 if not include_point_found:
61 raise RuntimeError("Include point not found in header: " + filename)
62
63 with open(filename, "w") as f:
64 for line in contents:
petrcermak 2016/08/15 13:00:06 f.writelines(contents)
kraynov 2016/08/15 13:37:49 Acknowledged.
65 print(line, file=f)
88 66
89 67
90 def main(argv): 68 def main(argv):
91 parser = optparse.OptionParser() 69 parser = optparse.OptionParser()
petrcermak 2016/08/15 13:00:06 Could you use the argparse module instead? Optpars
kraynov 2016/08/15 13:37:50 Okay.
92 parser.add_option('--include', dest='extra_header', 70 parser.add_option("--protoc",
93 help='The extra header to include. This must be specified ' 71 help="Relative path to compiler.")
94 'along with --protobuf.')
95 parser.add_option('--protobuf', dest='generated_header',
96 help='The c++ protobuf header to add the extra header to. '
97 'This must be specified along with --include.')
98 parser.add_option('--proto-in-dir',
99 help='The directory containing .proto files.')
100 parser.add_option('--proto-in-file', help='Input file to compile.')
101 parser.add_option('--use-system-protobuf', type=int, default=0,
102 help='Option to use system-installed protobuf '
103 'instead of bundled one.')
104 (options, args) = parser.parse_args(sys.argv)
105 if len(args) < 2:
106 return 1
107 72
108 if ScanForBadFiles(options.proto_in_dir): 73 parser.add_option("--proto-in-dir",
109 return 1 74 help="Base directory with source protos.")
75 parser.add_option("--cc-out-dir",
76 help="Output directory for standard C++ generator.")
77 parser.add_option("--py-out-dir",
78 help="Output directory for standard Python generator.")
79 parser.add_option("--plugin-out-dir",
80 help="Output directory for custom generator.")
petrcermak 2016/08/15 13:00:06 I think that the help string should contain the wo
kraynov 2016/08/15 13:37:49 Acknowledged.
110 81
111 proto_path = options.proto_in_dir 82 parser.add_option("--plugin",
112 if options.use_system_protobuf == 1: 83 help="Relative path to custom generator plugin.")
113 proto_path = RewriteProtoFilesForSystemProtobuf(proto_path) 84 parser.add_option("--plugin-options",
114 try: 85 help="Custom generator options.")
petrcermak 2016/08/15 13:00:07 I think that the help string should contain the wo
kraynov 2016/08/15 13:37:50 Acknowledged.
115 # Run what is hopefully protoc. 86 parser.add_option("--cc-options",
116 protoc_args = args[1:] 87 help="Standard C++ generator options.")
117 protoc_args += ['--proto_path=%s' % proto_path, 88 parser.add_option("--include",
118 os.path.join(proto_path, options.proto_in_file)] 89 help="Name of include to put into generated headers.")
petrcermak 2016/08/15 13:00:06 supernit: s/put/insert/
kraynov 2016/08/15 13:37:50 Acknowledged.
119 ret = subprocess.call(protoc_args) 90 (options, args) = parser.parse_args(argv)
petrcermak 2016/08/15 13:00:06 no need for parentheses (feel free to ignore)
kraynov 2016/08/15 13:37:49 Acknowledged.
120 if ret != 0:
121 return ret
122 finally:
123 if options.use_system_protobuf == 1:
124 # Remove temporary directory holding re-written files.
125 shutil.rmtree(proto_path)
126 91
127 # protoc succeeded, check to see if the generated cpp header needs editing. 92 protoc = os.path.realpath(options.protoc)
petrcermak 2016/08/15 13:00:06 In my opinion, there's no need to define this here
kraynov 2016/08/15 13:37:49 Acknowledged.
128 if not options.extra_header or not options.generated_header: 93 proto_dir = os.path.relpath(options.proto_in_dir)
129 return 0 94 protoc_args = ["--proto_path", proto_dir]
petrcermak 2016/08/15 13:00:06 To avoid pre-pending the protoc binary at the end
kraynov 2016/08/15 13:37:50 Acknowledged.
130 return ModifyHeader(options.generated_header, options.extra_header) 95
96 protos = args[1:]
97 stripped_protos = StripProtos(protos)
98 headers = []
99
100 if options.cc_out_dir is not None:
petrcermak 2016/08/15 13:00:06 you could do the following: if options.cc_out_dir
kraynov 2016/08/15 13:37:49 Acknowledged.
101 cc_options = ProtocGenOptions(options.cc_options)
102 protoc_args += ["--cpp_out", cc_options + options.cc_out_dir]
103 for name in stripped_protos:
104 headers.append(os.path.join(options.cc_out_dir, name + ".pb.h"))
105
106 if options.py_out_dir is not None:
107 protoc_args += ["--python_out", options.py_out_dir]
108
109 if options.plugin_out_dir is not None:
110 plugin_options = ProtocGenOptions(options.plugin_options)
111 protoc_args += [
112 "--plugin", "protoc-gen-plugin=" + os.path.relpath(options.plugin),
113 "--plugin_out", plugin_options + options.plugin_out_dir,
114 ]
115
116 for name in protos:
117 protoc_args.append(os.path.join(proto_dir, name))
petrcermak 2016/08/15 13:00:06 I personally prefer comprehensions over explicit l
kraynov 2016/08/15 13:37:49 Acknowledged.
118
119 ret = subprocess.call([protoc] + protoc_args)
120 if ret != 0:
121 raise RuntimeError("Protoc has returned non-zero status: " + str(ret))
122
123 if options.include is not None:
petrcermak 2016/08/15 13:00:06 I think you can drop "is not None" here
kraynov 2016/08/15 13:37:49 Acknowledged.
124 WriteIncludes(headers, options.include)
131 125
132 126
133 if __name__ == '__main__': 127 if __name__ == '__main__':
petrcermak 2016/08/15 13:00:06 Before this patch, this file used single quotes ev
kraynov 2016/08/15 13:37:50 Acknowledged.
134 sys.exit(main(sys.argv)) 128 try:
129 main(sys.argv)
130 except RuntimeError as e:
131 print(e, file=sys.stderr)
132 sys.exit(1)
OLDNEW
« third_party/protobuf/proto_library.gni ('K') | « third_party/protobuf/proto_library.gni ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698