Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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
    }
Пример #6
0
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
    }