def get_nanopb_suboptions(subdesc, options, name): '''Get copy of options, and merge information from subdesc.''' new_options = nanopb_pb2.NanoPBOptions() new_options.CopyFrom(options) # Handle options defined in a separate file dotname = '.'.join(name.parts) for namemask, options in Globals.separate_options: if fnmatch(dotname, namemask): new_options.MergeFrom(options) # Handle options defined in .proto if isinstance(subdesc.options, descriptor.FieldOptions): ext_type = nanopb_pb2.nanopb elif isinstance(subdesc.options, descriptor.FileOptions): ext_type = nanopb_pb2.nanopb_fileopt elif isinstance(subdesc.options, descriptor.MessageOptions): ext_type = nanopb_pb2.nanopb_msgopt elif isinstance(subdesc.options, descriptor.EnumOptions): ext_type = nanopb_pb2.nanopb_enumopt else: raise Exception("Unknown options type") if subdesc.options.HasExtension(ext_type): ext = subdesc.options.Extensions[ext_type] new_options.MergeFrom(ext) if Globals.verbose_options: print "Options for " + dotname + ":" print text_format.MessageToString(new_options) return new_options
def process(filenames, options): '''Process the files given on the command line.''' if not filenames: optparser.print_help() return False if options.quiet: options.verbose = False toplevel_options = nanopb_pb2.NanoPBOptions() for s in options.settings: text_format.Merge(s, toplevel_options) for filename in filenames: data = open(filename, 'rb').read() fdesc = descriptor.FileDescriptorSet.FromString(data) file_options = get_nanopb_suboptions(fdesc.file[0], toplevel_options) if options.verbose: print "Options for " + filename + ":" print text_format.MessageToString(file_options) enums, messages = parse_file(fdesc.file[0], file_options) noext = os.path.splitext(filename)[0] headername = noext + '.' + options.extension + '.h' sourcename = noext + '.' + options.extension + '.c' headerbasename = os.path.basename(headername) if not options.quiet: print "Writing to " + headername + " and " + sourcename # List of .proto files that should not be included in the C header file # even if they are mentioned in the source .proto. excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto' ] + options.exclude dependencies = [ d for d in fdesc.file[0].dependency if d not in excludes ] header = open(headername, 'w') for part in generate_header(dependencies, headerbasename, enums, messages, options): header.write(part) source = open(sourcename, 'w') for part in generate_source(headerbasename, enums, messages): source.write(part) return True
def read_options_file(infile): '''Parse a separate options file to list: [(namemask, options), ...] ''' results = [] for line in infile: line = line.strip() if not line or line.startswith('//') or line.startswith('#'): continue parts = line.split(None, 1) opts = nanopb_pb2.NanoPBOptions() text_format.Merge(parts[1], opts) results.append((parts[0], opts)) return results
def get_nanopb_suboptions(subdesc, options): '''Get copy of options, and merge information from subdesc.''' new_options = nanopb_pb2.NanoPBOptions() new_options.CopyFrom(options) if isinstance(subdesc.options, descriptor.FieldOptions): ext_type = nanopb_pb2.nanopb elif isinstance(subdesc.options, descriptor.FileOptions): ext_type = nanopb_pb2.nanopb_fileopt elif isinstance(subdesc.options, descriptor.MessageOptions): ext_type = nanopb_pb2.nanopb_msgopt elif isinstance(subdesc.options, descriptor.EnumOptions): ext_type = nanopb_pb2.nanopb_enumopt else: raise Exception("Unknown options type") if subdesc.options.HasExtension(ext_type): ext = subdesc.options.Extensions[ext_type] new_options.MergeFrom(ext) return new_options
def process_file(filename, fdesc, options): '''Process a single file. filename: The full path to the .proto or .pb source file, as string. fdesc: The loaded FileDescriptorSet, or None to read from the input file. options: Command line options as they come from OptionsParser. Returns a dict: {'headername': Name of header file, 'headerdata': Data for the .h header file, 'sourcename': Name of the source code file, 'sourcedata': Data for the .c source code file } ''' toplevel_options = nanopb_pb2.NanoPBOptions() for s in options.settings: text_format.Merge(s, toplevel_options) if not fdesc: data = open(filename, 'rb').read() fdesc = descriptor.FileDescriptorSet.FromString(data).file[0] # Check if there is a separate .options file try: optfilename = options.options_file % os.path.splitext(filename)[0] except TypeError: # No %s specified, use the filename as-is optfilename = options.options_file if options.verbose: print 'Reading options from ' + optfilename if os.path.isfile(optfilename): Globals.separate_options = read_options_file(open(optfilename, "rU")) else: Globals.separate_options = [] # Parse the file file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) enums, messages, extensions = parse_file(fdesc, file_options) # Decide the file names noext = os.path.splitext(filename)[0] headername = noext + '.' + options.extension + '.h' sourcename = noext + '.' + options.extension + '.c' headerbasename = os.path.basename(headername) # List of .proto files that should not be included in the C header file # even if they are mentioned in the source .proto. excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto' ] + options.exclude dependencies = [d for d in fdesc.dependency if d not in excludes] headerdata = ''.join( generate_header(dependencies, headerbasename, enums, messages, extensions, options)) sourcedata = ''.join( generate_source(headerbasename, enums, messages, extensions, options)) return { 'headername': headername, 'headerdata': headerdata, 'sourcename': sourcename, 'sourcedata': sourcedata }
def process_file(filename, fdesc, options): '''Process a single file. filename: The full path to the .proto or .pb source file, as string. fdesc: The loaded FileDescriptorSet, or None to read from the input file. options: Command line options as they come from OptionsParser. Returns a dict: {'headername': Name of header file, 'headerdata': Data for the .h header file, 'sourcename': Name of the source code file, 'sourcedata': Data for the .c source code file } ''' toplevel_options = nanopb_pb2.NanoPBOptions() for s in options.settings: text_format.Merge(s, toplevel_options) if not fdesc: data = open(filename, 'rb').read() fdesc = descriptor.FileDescriptorSet.FromString(data).file[0] # Check if there is a separate .options file had_abspath = False try: optfilename = options.options_file % os.path.splitext(filename)[0] except TypeError: # No %s specified, use the filename as-is optfilename = options.options_file had_abspath = True if os.path.isfile(optfilename): if options.verbose: sys.stderr.write('Reading options from ' + optfilename + '\n') Globals.separate_options = read_options_file(open(optfilename, "rU")) else: # If we are given a full filename and it does not exist, give an error. # However, don't give error when we automatically look for .options file # with the same name as .proto. if options.verbose or had_abspath: sys.stderr.write('Options file not found: ' + optfilename) Globals.separate_options = [] Globals.matched_namemasks = set() # Parse the file file_options = get_nanopb_suboptions(fdesc, toplevel_options, Names([filename])) enums, messages, extensions = parse_file(fdesc, file_options) # Decide the file names noext = os.path.splitext(filename)[0] headername = noext + options.extension + '.h' sourcename = noext + options.extension + '.c' headerbasename = os.path.basename(headername) # List of .proto files that should not be included in the C header file # even if they are mentioned in the source .proto. excludes = ['nanopb.proto', 'google/protobuf/descriptor.proto' ] + options.exclude dependencies = [d for d in fdesc.dependency if d not in excludes] headerdata = ''.join( generate_header(dependencies, headerbasename, enums, messages, extensions, options)) sourcedata = ''.join( generate_source(headerbasename, enums, messages, extensions, options)) # Check if there were any lines in .options that did not match a member unmatched = [ n for n, o in Globals.separate_options if n not in Globals.matched_namemasks ] if unmatched and not options.quiet: sys.stderr.write("Following patterns in " + optfilename + " did not match any fields: " + ', '.join(unmatched) + "\n") if not Globals.verbose_options: sys.stderr.write( "Use protoc --nanopb-out=-v:. to see a list of the field names.\n" ) return { 'headername': headername, 'headerdata': headerdata, 'sourcename': sourcename, 'sourcedata': sourcedata }