idl2proto 5.12 KB
Newer Older
gejun's avatar
gejun committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#!/bin/bash -f

# mcpack2pb - Make protobuf be front-end of mcpack/compack
# Copyright (c) 2015 Baidu.com, Inc. All Rights Reserved
# Date: Mon Oct 19 17:17:36 CST 2015

# source shflags from current directory
mydir="${BASH_SOURCE%/*}"
if [[ ! -d "$mydir" ]]; then mydir="$PWD"; fi
. $mydir/shflags

# command-line flags
DEFINE_string ns '' 'Namespace of the idl file'
DEFINE_boolean pb3 false 'Use new data structures introduced in protobuf 3'

# parse the command-line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

# Printing to stderr
function error() {
    >&2 echo "idl2proto: $@"
}

if [[ "$1" == "" ]]; then
    flags_help
    exit 1
fi
if [[ $(basename "$1" | awk -F. '{print $2}') != "idl" ]]; then
    error "$1 is not an idl file";
    exit 1
fi

package_statement=""
if [[ "$FLAGS_ns" != "" ]]; then
    package_statement="package $FLAGS_ns;\n"
fi

sed -e ':a;N;$!ba;s/=\s*\n\+/=/g' $1 | \
 sed -e 's/;\//; \//g' \
    -e 's/^\(\s*#\(define\>\|if\|endif\|undef\)\)/\/\/ \1/g' \
    -e 's/^\s*struct\>/message/g' \
    -e 's/\<\(range\|regex\|rest\)\s*\(([^)]*)\)\s*,*\(.*\)/\3 \/\/\1\2/g' \
    -e 's/\<default(\([^)]*\))\s*,*/[default=\1]/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\)\s*\[[0-9]*\]\(.*\)/rrepeated \1\2/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\s*=.*\)\<\(vector\|array\)(\w*)\s*,*\(.*\)/rrepeated \1\3/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\s*=.*\)\<map(\w*)\s*,*\(.*\)/map \1\2/g' \
    -e 's/^\s*map\s\+\(\w\+\s\+\w\+\s*=.*\)\<optional()\s*,*\(.*\)/map \1\2/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\s*=.*\)\<optional()\s*,*\(.*\)/optional \1\2/g' \
    -e 's/^\s*rrepeated\s\+\(\w\+\s\+\w\+\s*=.*\)\<optional()\s*,*\(.*\)/repeated \1\2/g' \
    -e 's/^\s*\(\(optional\|repeated\|rrepeated\|map\)\s\+\w\+\s\+\w\+\)\s*=/\1 /g' \
    -e 's/^\s*\(\(optional\|repeated\|rrepeated\|map\)\s\+\w\+\s\+\w\+\)\s*;/\1 ;/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\)\s*;/required \1 ;/g' \
    -e 's/^\s*\(\w\+\s\+\w\+\)\s*=\(.*\)/required \1 \2/g' \
    -e 's/\[default=\(0\|""\)\]//g' \
    -e 's/^\(\s*\)\w\+\s\+\(\w\+\)\s*(\s*\(\w\+\)\s\+\w\+\s*,\s*out\s\+\(\w\+\)\s\+\w\+\s*)\s*;/\1rpc \2(\3) returns (\4);/g' \
    -e 's/^\s*#include  *\"\([^.]*\.\)idl *\"/import \"\1proto\";/g' | \
 awk 'BEGIN{\
        typemap["uint64_t"] = "uint64";\
        typemap["int64_t"] = "int64";\
        typemap["int32_t"] = "int32";\
        typemap["uint32_t"] = "uint32";\
        typemap["int16_t"] = "int32";\
        typemap["uint16_t"] = "uint32";\
        typemap["int8_t"] = "int32";\
        typemap["uint8_t"] = "uint32";\
        typemap["binary"] = "bytes";\
        idlopt["int8_t"] = "[(idl_type)=IDL_INT8]";\
        idlopt["uint8_t"] = "[(idl_type)=IDL_UINT8]";\
        idlopt["int16_t"] = "[(idl_type)=IDL_INT16]";\
        idlopt["uint16_t"] = "[(idl_type)=IDL_UINT16]";\
        primitives["int8_t"] = 1; \
        primitives["int16_t"] = 1; \
        primitives["int32_t"] = 1; \
        primitives["int64_t"] = 1; \
        primitives["uint8_t"] = 1; \
        primitives["uint16_t"] = 1; \
        primitives["uint32_t"] = 1; \
        primitives["uint64_t"] = 1; \
        primitives["bool"] = 1; \
        primitives["float"] = 1; \
        primitives["double"] = 1; \
        
gejun's avatar
gejun committed
84
        print "// Converted from '$1' by brpc/tools/idl2proto\n" \
gejun's avatar
gejun committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
              "syntax=\"proto2\";\n" \
              "import \"idl_options.proto\";\n" \
              "option (idl_support) = true;\n\n" \
              "option cc_generic_services = true;\n" \
              "'"$package_statement"'" \
    }{\
        if ($1 == "message") {\
            count = 0;\
            message_name = $2; \
            print $0;\
        } else if ($1 == "required" || $1 == "optional" || \
                   $1 == "repeated" || $1 == "rrepeated" || \
                   $1 == "map") { \
            if ($1 == "rrepeated") { $1 = "repeated"; $4 = "[(idl_on)=1]"$4 } \
            if ($1 == "repeated" && ($2 in primitives)) { $4 = "[packed=true]"$4 } \
            if ($2 in idlopt) { $4 = idlopt[$2]$4 } \
            if ($2 in typemap) { $2 = typemap[$2] } \
            if ($1 == "map") { \
                if ("'"$FLAGS_pb3"'" == "0") { \
                    $1 = "map<string,";\
                    $2 = $2">";\
                } else {\
                    $1 = "repeated";          \
                    if (!($2 in need_map)) {\
                        need_map[$2] = message_name; \
                    } \
                    $2 = need_map[$2] "MapEntry_string_" $2; \
                }\
            } \
            $3 = $3" = "++count;\
            if ($5 ~ /^\/\// || $5 ~ /^\/\*/) {\
                len_before = length($1) + length($2) + length($3) + length($4) + 3;\
                spaces = "";\
                for (; len_before < 50; ++len_before) {\
                    spaces = spaces" ";\
                }\
                $5 = spaces $5;\
            }\
            print "    "$0;\
        } else { print $0 }\
    } END{\
        for (value in need_map) { \
            print "\nmessage " need_map[value] "MapEntry_string_" value " {\n" \
                  "    required string key = 1;\n" \
                  "    optional " value " value = 2;\n" \
                  "}"; \
        }\
    }' | \
 sed -e 's/ ;/; /g' -e 's/};/}/g' -e 's/\]\[/, /g'