Пример #1
0
func (pf *protofile) printHeader(w io.Writer, e *yang.Entry) {
	syntax := "proto3"
	if proto2 {
		syntax = "proto2"
	}
	fmt.Fprintf(w, `syntax = %q;
// Automatically generated by goyang https://github.com/openconfig/goyang
// compiled %s`, syntax, time.Now().UTC().Format(time.RFC3339))
	fmt.Fprintf(w, `
// do not delete the next line
%s%s`, versionPrefix, protoVersion)
	fmt.Fprintf(w, `
// module %q
`, e.Name)

	if v := e.Extra["revision"]; len(v) > 0 {
		for _, rev := range v[0].([]*yang.Revision) {
			fmt.Fprintf(w, "// revision %q\n", rev.Name)
		}
	}
	if v := e.Extra["namespace"]; len(v) > 0 {
		fmt.Fprintf(w, "// namespace %q\n", v[0].(*yang.Value).Name)
	}

	fmt.Fprintln(w)
	if !protoNoComments && e.Description != "" {
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}
	fmt.Fprintf(w, "package %s;\n", pf.fieldName(e.Name))
}
Пример #2
0
// Print prints e to w in human readable form.
func (e *Entry) Print(w io.Writer) {
	if e.Description != "" {
		fmt.Fprintln(w)
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}
	if e.ReadOnly() {
		fmt.Fprintf(w, "RO: ")
	} else {
		fmt.Fprintf(w, "rw: ")
	}
	if e.Type != nil {
		fmt.Fprintf(w, "%s ", e.Type.Name)
	}
	switch {
	case e.Dir == nil && e.ListAttr != nil:
		fmt.Fprintf(w, "[]%s\n", e.Name)
		return
	case e.Dir == nil:
		fmt.Fprintf(w, "%s\n", e.Name)
		return
	case e.ListAttr != nil:
		fmt.Fprintf(w, "[%s]%s {\n", e.Key, e.Name) //}
	default:
		fmt.Fprintf(w, "%s {\n", e.Name) //}
	}
	var names []string
	for k := range e.Dir {
		names = append(names, k)
	}
	sort.Strings(names)
	for _, k := range names {
		e.Dir[k].Print(indent.NewWriter(w, "  "))
	}
	// { to match the brace below to keep brace matching working
	fmt.Fprintln(w, "}")
}
Пример #3
0
// FormatNode writes e, formatted almost like a protobuf message, to w.
func FormatNode(w io.Writer, e *yang.Entry) {
	fmt.Fprintln(w)
	if e.Description != "" {
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}
	fmt.Fprintf(w, "message %s {\n", fixName(e.Name))

	var names []string
	for k := range e.Dir {
		names = append(names, k)
	}
	sort.Strings(names)
	for x, k := range names {
		se := e.Dir[k]
		if se.Description != "" {
			fmt.Fprintln(indent.NewWriter(w, "  // "), se.Description)
		}
		if se.IsList {
			fmt.Fprint(w, "  repeated ")
		} else {
			fmt.Fprint(w, "  optional ")
		}
		if len(se.Dir) == 0 && se.Type != nil {
			// TODO(borman): this is probably an empty container.
			kind := "UNKNOWN TYPE"
			if se.Type != nil {
				kind = kind2proto[se.Type.Kind]
			}
			fmt.Fprintf(w, "%s %s = %d; // %s\n", kind, fixName(k), x+1, yang.Source(se.Node))
			continue
		}
		fmt.Fprintf(w, "%s %s = %d; // %s\n", fixName(se.Name), fixName(k), x+1, yang.Source(se.Node))
	}
	// { to match the brace below to keep brace matching working
	fmt.Fprintln(w, "}")
}
Пример #4
0
// printType prints type t in a moderately human readable format to w.
func printType(w io.Writer, t *yang.YangType, verbose bool) {
	if verbose && t.Base != nil {
		base := yang.Source(t.Base)
		if base == "unknown" {
			base = "unnamed type"
		}
		fmt.Fprintf(w, "%s: ", base)
	}
	fmt.Fprintf(w, "%s", t.Root.Name)
	if t.Kind.String() != t.Root.Name {
		fmt.Fprintf(w, "(%s)", t.Kind)
	}
	if t.Units != "" {
		fmt.Fprintf(w, " units=%s", t.Units)
	}
	if t.Default != "" {
		fmt.Fprintf(w, " default=%q", t.Default)
	}
	if t.FractionDigits != 0 {
		fmt.Fprintf(w, " fraction-digits=%d", t.FractionDigits)
	}
	if len(t.Length) > 0 {
		fmt.Fprintf(w, " length=%s", t.Length)
	}
	if t.Kind == yang.YinstanceIdentifier && !t.OptionalInstance {
		fmt.Fprintf(w, " required")
	}
	if t.Kind == yang.Yleafref && t.Path != "" {
		fmt.Fprintf(w, " path=%q", t.Path)
	}
	if len(t.Pattern) > 0 {
		fmt.Fprintf(w, " pattern=%s", strings.Join(t.Pattern, "|"))
	}
	b := yang.BaseTypedefs[t.Kind.String()].YangType
	if len(t.Range) > 0 && !t.Range.Equal(b.Range) {
		fmt.Fprintf(w, " range=%s", t.Range)
	}
	if len(t.Type) > 0 {
		fmt.Fprintf(w, "union{\n")
		for _, t := range t.Type {
			printType(indent.NewWriter(w, "  "), t, verbose)
		}
		fmt.Fprintf(w, "}")
	}
	fmt.Fprintf(w, ";\n")
}
Пример #5
0
// Write writes e, formatted, and all of its children, to w.
func Write(w io.Writer, e *yang.Entry) {
	if e.Description != "" {
		fmt.Fprintln(w)
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}
	if len(e.Exts) > 0 {
		fmt.Fprintf(w, "extensions: {\n")
		for _, ext := range e.Exts {
			if n := ext.NName(); n != "" {
				fmt.Fprintf(w, "  %s %s;\n", ext.Kind(), n)
			} else {
				fmt.Fprintf(w, "  %s;\n", ext.Kind())
			}
		}
		fmt.Fprintln(w, "}")
	}
	switch {
	case e.RPC != nil:
		fmt.Fprintf(w, "RPC: ")
	case e.ReadOnly():
		fmt.Fprintf(w, "RO: ")
	default:
		fmt.Fprintf(w, "rw: ")
	}
	if e.Type != nil {
		fmt.Fprintf(w, "%s ", getTypeName(e))
	}
	name := e.Name
	if e.Prefix != nil {
		name = e.Prefix.Name + ":" + name
	}
	switch {
	case e.Dir == nil && e.ListAttr != nil:
		fmt.Fprintf(w, "[]%s\n", name)
		return
	case e.Dir == nil:
		fmt.Fprintf(w, "%s\n", name)
		return
	case e.ListAttr != nil:
		fmt.Fprintf(w, "[%s]%s {\n", e.Key, name) //}
	default:
		fmt.Fprintf(w, "%s {\n", name) //}
	}
	if r := e.RPC; r != nil {
		if r.Input != nil {
			Write(indent.NewWriter(w, "  "), r.Input)
		}
		if r.Output != nil {
			Write(indent.NewWriter(w, "  "), r.Output)
		}
	}
	var names []string
	for k := range e.Dir {
		names = append(names, k)
	}
	sort.Strings(names)
	for _, k := range names {
		Write(indent.NewWriter(w, "  "), e.Dir[k])
	}
	// { to match the brace below to keep brace matching working
	fmt.Fprintln(w, "}")
}
Пример #6
0
// FormatNode writes e, formatted almost like a protobuf message, to w.
func FormatNode(w io.Writer, e *yang.Entry) {
	var names []string

	for k, se := range e.Dir {
		if se.RPC != nil {
			names = append(names, k)
		}
	}
	needEmpty := false
	if len(names) > 0 {
		sort.Strings(names)
		fmt.Fprintf(w, "service %s {\n", fixName(e.Name))
		for _, k := range names {
			rpc := e.Dir[k].RPC
			k = fixName(k)
			iName := "Empty"
			oName := "Empty"
			if rpc.Input != nil {
				iName = k + "Request"
				rpc.Input.Name = iName
				if isStream(rpc.Input) {
					iName = "stream " + iName
				}
			}
			if rpc.Output != nil {
				oName = k + "Response"
				rpc.Output.Name = oName
				if isStream(rpc.Output) {
					oName = "stream " + oName
				}
			}
			needEmpty = needEmpty || rpc.Input == nil || rpc.Output == nil
			fmt.Fprintf(w, "  rpc %s (%s) returns (%s);\n", k, iName, oName)
		}
		fmt.Fprintln(w, "}")
		for _, k := range names {
			rpc := e.Dir[k].RPC
			if rpc.Input != nil {
				FormatNode(w, rpc.Input)
			}
			if rpc.Output != nil {
				FormatNode(w, rpc.Output)
			}
		}
	}

	if needEmpty {
		fmt.Fprintln(w, "\nmessage Empty { }")
	}

	names = nil
	for k, se := range e.Dir {
		if se.RPC == nil {
			names = append(names, k)
		}
	}
	if len(names) == 0 {
		return
	}

	fmt.Fprintln(w)
	if e.Description != "" {
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}
	fmt.Fprintf(w, "message %s {\n", fixName(e.Name))

	sort.Strings(names)
	for x, k := range names {
		se := e.Dir[k]
		if se.Description != "" {
			fmt.Fprintln(indent.NewWriter(w, "  // "), se.Description)
		}
		if se.ListAttr != nil {
			fmt.Fprint(w, "  repeated ")
		} else {
			fmt.Fprint(w, "  optional ")
		}
		if len(se.Dir) == 0 && se.Type != nil {
			// TODO(borman): this is probably an empty container.
			kind := "UNKNOWN TYPE"
			if se.Type != nil {
				kind = kind2proto[se.Type.Kind]
			}
			fmt.Fprintf(w, "%s %s = %d; // %s\n", kind, fixName(k), x+1, yang.Source(se.Node))
			continue
		}
		fmt.Fprintf(w, "%s %s = %d; // %s\n", fixName(se.Name), fixName(k), x+1, yang.Source(se.Node))
	}
	// { to match the brace below to keep brace matching working
	fmt.Fprintln(w, "}")
}
Пример #7
0
// FindNode finds the node referenced by path relative to n.  If path does not
// reference a node then nil is returned (i.e. path not found).  The path looks
// similar to an XPath but curently has no wildcarding.  For example:
// "/if:interfaces/if:interface" and "../config".
func FindNode(n Node, path string) (Node, error) {
	if path == "" {
		return n, nil
	}
	// / is not a valid path, it needs a module name
	if path == "/" {
		return nil, fmt.Errorf("invalid path %q", path)
	}
	// Paths do not end in /'s
	if path[len(path)-1] == '/' {
		return nil, fmt.Errorf("invalid path %q", path)
	}

	parts := strings.Split(path, "/")

	// An absolute path has a leading component of "".
	// We need to discover which module they are part of
	// based on our imports.
	if parts[0] == "" {
		parts = parts[1:]

		// TODO(borman): merge this with FindModuleByPrefix?
		n = RootNode(n)
		// The base is always a module
		mod := n.(*Module)
		prefix, _ := getPrefix(parts[0])
		if mod.Kind() == "submodule" {
			m := mod.modules.Modules[mod.BelongsTo.Name]
			if m == nil {
				return nil, fmt.Errorf("%s: unknown module %s", m.Name, mod.BelongsTo.Name)
			}
			if prefix == "" || prefix == mod.BelongsTo.Prefix.Name {
				mod = m
				goto processing
			}
			mod = m
		}

		if prefix == "" || prefix == mod.Prefix.Name {
			goto processing
		}

		for _, i := range mod.Import {
			if prefix == i.Prefix.Name {
				n = i.Module
				goto processing
			}
		}
		// We didn't find a matching prefix.
		return nil, fmt.Errorf("unknown prefix: %q", prefix)
	processing:
		// At this point, n should be pointing to the Module node
		// of module we are rooted in
	}

	for _, part := range parts {
		// If we encounter an RPC node in our search then we
		// return the magic isRPCNode Node which just contains
		// an error that it is an RPC node.  isRPCNode is a singleton
		// and can be checked against.
		if n.Kind() == "rpc" {
			return isRPCNode, nil
		}
		if part == ".." {
		Loop:
			for {
				n = n.ParentNode()
				if n == nil {
					return nil, fmt.Errorf(".. with no parent")
				}
				// choice, leaf, and case nodes
				// are "invisible" when doing ".."
				// up the tree.
				switch n.Kind() {
				case "choice", "leaf", "case":
				default:
					break Loop
				}
			}
			continue
		}
		// For now just strip off any prefix
		// TODO(borman): fix this
		_, spart := getPrefix(part)
		n = ChildNode(n, spart)
		if n == nil {
			return nil, fmt.Errorf("%s: no such element", part)
		}
	}
	return n, nil
}

// ChildNode finds n's child node named name.  It returns nil if the node
// could not be found.  ChildNode looks at every direct Node pointer in
// n as well as every node in all slices of Node pointers.  Names must
// be non-ambiguous, otherwise ChildNode has a non-deterministic result.
func ChildNode(n Node, name string) Node {
	v := reflect.ValueOf(n).Elem()
	t := v.Type()
	nf := t.NumField()

Loop:
	for i := 0; i < nf; i++ {
		ft := t.Field(i)
		yang := ft.Tag.Get("yang")
		if yang == "" {
			continue
		}
		parts := strings.Split(yang, ",")
		for _, p := range parts[1:] {
			if p == "nomerge" {
				continue Loop
			}
		}

		f := v.Field(i)
		if !f.IsValid() || f.IsNil() {
			continue
		}

		check := func(n Node) Node {
			if n.NName() == name {
				return n
			}
			return nil
		}
		if parts[0] == "uses" {
			check = func(n Node) Node {
				uname := n.NName()
				// unrooted uses are rooted at root
				if !strings.HasPrefix(uname, "/") {
					uname = "/" + uname
				}
				if n, _ = FindNode(n, uname); n != nil {
					return ChildNode(n, name)
				}
				return nil
			}
		}

		switch ft.Type.Kind() {
		case reflect.Ptr:
			if n = check(f.Interface().(Node)); n != nil {
				return n
			}
		case reflect.Slice:
			sl := f.Len()
			for i := 0; i < sl; i++ {
				n = f.Index(i).Interface().(Node)
				if n = check(n); n != nil {
					return n
				}
			}
		}
	}
	return nil
}

// PrintNode prints node n to w, recursively.
// TODO(borman): display more information
func PrintNode(w io.Writer, n Node) {
	v := reflect.ValueOf(n).Elem()
	t := v.Type()
	nf := t.NumField()
	fmt.Fprintf(w, "%s%s [%s]\n", n.NName(), n.Kind())
Loop:
	for i := 0; i < nf; i++ {
		ft := t.Field(i)
		yang := ft.Tag.Get("yang")
		if yang == "" {
			continue
		}
		parts := strings.Split(yang, ",")
		for _, p := range parts[1:] {
			if p == "nomerge" {
				continue Loop
			}
		}

		// Skip uppercase elements.
		if parts[0][0] >= 'A' && parts[0][0] <= 'Z' {
			continue
		}

		f := v.Field(i)
		if !f.IsValid() || f.IsNil() {
			continue
		}

		switch ft.Type.Kind() {
		case reflect.Ptr:
			n = f.Interface().(Node)
			if v, ok := n.(*Value); ok {
				fmt.Fprintf(w, "%s%s = %s\n", ft.Name, v.Name)
			} else {
				PrintNode(indent.NewWriter(w, "    "), n)
			}
		case reflect.Slice:
			sl := f.Len()
			for i := 0; i < sl; i++ {
				n = f.Index(i).Interface().(Node)
				if v, ok := n.(*Value); ok {
					fmt.Fprintf(w, "%s%s[%d] = %s\n", ft.Name, i, v.Name)
				} else {
					PrintNode(indent.NewWriter(w, "    "), n)
				}
			}
		}
	}
}
Пример #8
0
// printNode writes e, formatted almost like a protobuf message, to w.
func (pf *protofile) printNode(w io.Writer, e *yang.Entry, nest bool) {
	nodes := children(e)

	if !protoNoComments && e.Description != "" {
		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
	}

	messageName := pf.fullName(e)
	mi := pf.messages[messageName]
	if mi == nil {
		mi = &messageInfo{
			fields: map[string]int{},
		}
		pf.messages[messageName] = mi
	}

	fmt.Fprintf(w, "message %s {", pf.messageName(e)) // matching brace }
	if protoWithSource {
		fmt.Fprintf(w, " // %s", yang.Source(e.Node))
	}
	fmt.Fprintln(w)

	for i, se := range nodes {
		k := se.Name
		if !protoNoComments && se.Description != "" {
			fmt.Fprintln(indent.NewWriter(w, "  // "), se.Description)
		}
		if nest && (len(se.Dir) > 0 || se.Type == nil) {
			pf.printNode(indent.NewWriter(w, "  "), se, true)
		}
		prefix := "  "
		if se.ListAttr != nil {
			prefix = "  repeated "
		} else if proto2 {
			prefix = "  optional "
		}
		name := pf.fieldName(k)
		printed := false
		var kind string
		if len(se.Dir) > 0 || se.Type == nil {
			kind = pf.messageName(se)
		} else if se.Type.Kind == yang.Ybits {
			values := dedup(se.Type.Bit.Values())
			asComment := false
			switch {
			case len(values) > 0 && values[len(values)-1] > 63:
				if i != 0 {
					fmt.Fprintln(w)
				}
				fmt.Fprintf(w, "  // *WARNING* bitfield %s has more than 64 positions\n", name)
				kind = "uint64"
				asComment = true
			case len(values) > 0 && values[len(values)-1] > 31:
				if i != 0 {
					fmt.Fprintln(w)
				}
				fmt.Fprintf(w, "  // bitfield %s to large for enum\n", name)
				kind = "uint64"
				asComment = true
			default:
				kind = pf.fixName(se.Name)
			}
			if !asComment {
				fmt.Fprintf(w, "  enum %s {\n", kind)
				fmt.Fprintf(w, "    %s_FIELD_NOT_SET = 0;\n", kind)
			} else {
				fmt.Fprintf(w, "  // Values:\n")
			}
			names := map[int64][]string{}
			for n, v := range se.Type.Bit.NameMap() {
				names[v] = append(names[v], n)
			}
			for _, v := range values {
				ns := names[v]
				sort.Strings(ns)
				if asComment {
					for _, n := range ns {
						fmt.Fprintf(w, "  //   %s = 1 << %d\n", n, v)
					}
				} else {
					n := strings.ToUpper(pf.fieldName(ns[0]))
					fmt.Fprintf(w, "    %s_%s = %d;\n", kind, n, 1<<uint(v))
					for _, n := range ns[1:] {
						n = strings.ToUpper(pf.fieldName(n))
						fmt.Fprintf(w, "    // %s = %d; (DUPLICATE VALUE)\n", n, 1<<uint(v))
					}
				}
			}
			if !asComment {
				fmt.Fprintf(w, "  };\n")
			}
		} else if se.Type.Kind == yang.Ydecimal64 {
			kind = "Decimal64"
			pf.hasDecimal64 = true
		} else if se.Type.Kind == yang.Yenum {
			kind = pf.fixName(se.Name)
			fmt.Fprintf(w, "  enum %s {", kind)
			if protoWithSource {
				fmt.Fprintf(w, " // %s", yang.Source(se.Node))
			}
			fmt.Fprintln(w)

			for i, n := range se.Type.Enum.Names() {
				fmt.Fprintf(w, "    %s_%s = %d;\n", kind, strings.ToUpper(pf.fieldName(n)), i)
			}
			fmt.Fprintf(w, "  };\n")
		} else if se.Type.Kind == yang.Yunion {
			types := pf.unionTypes(se.Type, map[string]bool{})
			switch len(types) {
			case 0:
				fmt.Fprintf(w, "    // *WARNING* union %s has no types\n", se.Name)
				printed = true
			case 1:
				kind = types[0]
			default:
				iw := w
				kind = pf.fixName(se.Name)
				if se.ListAttr != nil {
					fmt.Fprintf(w, "  message %s {\n", kind)
					iw = indent.NewWriter(w, "  ")
				}
				fmt.Fprintf(iw, "  oneof %s {", kind) // matching brace }
				if protoWithSource {
					fmt.Fprintf(w, " // %s", yang.Source(se.Node))
				}
				fmt.Fprintln(w)
				for _, tkind := range types {
					fmt.Fprintf(iw, "    %s %s_%s = %d;\n", tkind, kind, tkind, mi.tag(name, tkind, false))
				}
				// { to match the brace below to keep brace matching working
				fmt.Fprintf(iw, "  }\n")
				if se.ListAttr != nil {
					fmt.Fprintf(w, "  }\n")
				} else {
					printed = true
				}
			}
		} else {
			kind = kind2proto[se.Type.Kind]
		}
		if !printed {
			fmt.Fprintf(w, "%s%s %s = %d;", prefix, kind, name, mi.tag(name, kind, se.ListAttr != nil))
			if protoWithSource {
				fmt.Fprintf(w, " // %s", yang.Source(se.Node))
			}
			fmt.Fprintln(w)
		}
	}
	// { to match the brace below to keep brace matching working
	fmt.Fprintln(w, "}")
}