Generate the remaining consts. (#55)
* Generate the remaining consts. There were a number of hand-written consts in go-libvirt, including flag values for various libvirt functions. Remove these and generate them instead, so that we now have a complete set, and the naming is consistent. I used c-for-go to do this generation, but turned off any cgo usage by the generated code - we don't want or need to introduce a dependency on cgo just to get constants from C headers. All code is still generated using 'go generate ./...', which now calls a wrapper script for added robustness. This change also returns to using Go types for flags for most libvirt functions, instead of plain integers.
This commit is contained in:
@@ -16,6 +16,7 @@ package lvgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -23,6 +24,8 @@ import (
|
||||
"text/template"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
// If you're making changes to the generator, or troubleshooting the generated
|
||||
@@ -375,6 +378,8 @@ func fixAbbrevs(s string) string {
|
||||
// defined in the protocol file. If one or both of these structs is not defined
|
||||
// then either the args or return values are empty.
|
||||
func procLink() {
|
||||
flagTypes := mapFlagTypes()
|
||||
|
||||
for ix, proc := range Gen.Procs {
|
||||
argsName := proc.Name + "Args"
|
||||
retName := proc.Name + "Ret"
|
||||
@@ -383,6 +388,7 @@ func procLink() {
|
||||
if hasArgs {
|
||||
argsStruct := Gen.Structs[argsIx]
|
||||
Gen.Procs[ix].ArgsStruct = argsStruct.Name
|
||||
changeFlagType(proc.Name, &argsStruct, flagTypes)
|
||||
Gen.Procs[ix].Args = argsStruct.Members
|
||||
}
|
||||
if hasRet {
|
||||
@@ -393,6 +399,138 @@ func procLink() {
|
||||
}
|
||||
}
|
||||
|
||||
// mapFlagTypes builds a map of the C types which appear to correspond to the
|
||||
// various flags fields in libvirt calls. Determining whether a type actually
|
||||
// corresponds to a set of flags is done by pattern matching the type name;
|
||||
// libvirt isn't completely consistent about the names of flag types, but they
|
||||
// all seem to have one of three suffixes, so that's what we look for here.
|
||||
//
|
||||
// This code uses the loader package to load the constants file generated by
|
||||
// c-for-go, which runs against libvirt's C sources. This file is generated by
|
||||
// 'go generate ./...' prior to the lvgen/ generator being run.
|
||||
func mapFlagTypes() map[string]ast.Expr {
|
||||
pconf := loader.Config{}
|
||||
f, err := pconf.ParseFile("../../const.gen.go", nil)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintln("failed to read constants file: ", err))
|
||||
}
|
||||
pconf.CreateFromFiles("const", f)
|
||||
prog, err := pconf.Load()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintln("failed to load package: ", err))
|
||||
}
|
||||
cpkg := prog.Package("const")
|
||||
|
||||
tmap := make(map[string]ast.Expr)
|
||||
ast.Inspect(cpkg.Files[0], func(n ast.Node) bool {
|
||||
switch t := n.(type) {
|
||||
case *ast.TypeSpec:
|
||||
// There isn't a single name pattern that covers all of the flag
|
||||
// types, so we'll collect all the types that map to int32 here.
|
||||
if fmt.Sprintf("%s", t.Type) == "int32" {
|
||||
tmap[t.Name.String()] = t.Type
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return tmap
|
||||
}
|
||||
|
||||
// Many libvirt calls use flags whose values come from a set of definitions
|
||||
// whose name we can't predict. So this map exists to do the translation for us.
|
||||
// The only way to remove this fragile map would be to use the comments from the
|
||||
// .c files in libvirt, which contain doxygen-style parameter comments that
|
||||
// specify the valid value types for flags.
|
||||
var flagMap = map[string]string{
|
||||
"ConnectOpen": "ConnectFlags",
|
||||
"DomainAddIothread": "DomainModificationImpact",
|
||||
"DomainCoreDumpWithFormat": "DomainCoreDumpFlags",
|
||||
"DomainCreateXML": "DomainCreateFlags",
|
||||
"DomainCreateWithFiles": "DomainCreateFlags",
|
||||
"DomainCreateXMLWithFiles": "DomainCreateFlags",
|
||||
"DomainDefineXMLFlags": "DomainDefineFlags",
|
||||
"DomainDelIothread": "DomainModificationImpact",
|
||||
"DomainDestroyFlags": "DomainDestroyFlagsValues",
|
||||
"DomainGetCPUStats": "TypedParameterFlags",
|
||||
"DomainGetEmulatorPinInfo": "DomainModificationImpact",
|
||||
"DomainGetInterfaceParameters": "DomainModificationImpact",
|
||||
"DomainGetIothreadInfo": "DomainModificationImpact",
|
||||
"DomainGetMetadata": "DomainModificationImpact",
|
||||
"DomainGetPerfEvents": "DomainModificationImpact",
|
||||
"DomainGetXMLDesc": "DomainXMLFlags",
|
||||
"DomainManagedSaveDefineXML": "DomainSaveRestoreFlags",
|
||||
"DomainManagedSaveGetXMLDesc": "DomainXMLFlags",
|
||||
"DomainMemoryPeek": "DomainMemoryFlags",
|
||||
"DomainMigratePerform3Params": "DomainMigrateFlags",
|
||||
"DomainOpenChannel": "DomainChannelFlags",
|
||||
"DomainOpenGraphicsFd": "DomainOpenGraphicsFlags",
|
||||
"DomainPinEmulator": "DomainModificationImpact",
|
||||
"DomainPinIothread": "DomainModificationImpact",
|
||||
"DomainSetLifecycleAction": "DomainModificationImpact",
|
||||
"DomainSetMemoryStatsPeriod": "DomainMemoryModFlags",
|
||||
"DomainSetMetadata": "DomainModificationImpact",
|
||||
"DomainSetPerfEvents": "DomainModificationImpact",
|
||||
"DomainSetVcpu": "DomainModificationImpact",
|
||||
"DomainShutdownFlags": "DomainShutdownFlagValues",
|
||||
"DomainUndefineFlags": "DomainUndefineFlagsValues",
|
||||
"StoragePoolCreateXML": "StoragePoolCreateFlags",
|
||||
"StoragePoolGetXMLDesc": "StorageXMLFlags",
|
||||
"StorageVolCreateXML": "StorageVolCreateFlags",
|
||||
"StorageVolCreateXMLFrom": "StorageVolCreateFlags",
|
||||
}
|
||||
|
||||
// findFlagType attempts to find a real type for the flags passed to a given
|
||||
// libvirt routine.
|
||||
func findFlagType(procName string, flagTypes map[string]ast.Expr) (string, bool) {
|
||||
flagName, ok := flagMap[procName]
|
||||
if ok {
|
||||
// Verify the mapped name exists
|
||||
if _, ok = flagTypes[flagName]; ok == false {
|
||||
// If one of the manual flag mappings is wrong, complain but
|
||||
// continue. This happens with older versions of libvirt.
|
||||
fmt.Printf("manual flag type %v for %v not found, continuing", flagName, procName)
|
||||
return "", false
|
||||
}
|
||||
return flagName, true
|
||||
}
|
||||
|
||||
// Not in the manual map, so do a search using the 3 patterns libvirt uses.
|
||||
tnames := [...]string{procName + "Flags", procName + "FlagValues", procName + "FlagsValues"}
|
||||
for _, n := range tnames {
|
||||
if _, ok := flagTypes[n]; ok == true {
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// changeFlagType looks up the go type for a libvirt call's flags field. In C
|
||||
// these flags are all uint32, and you have to consult the documentation to
|
||||
// determine what the valid set of flags is for a given libvirt call. For Go
|
||||
// we're attempting to do better by specifying an actual type so that the
|
||||
// possible values are easier to determine. This is a heuristic, however, based
|
||||
// on naming patterns in the libvirt code. To do better we would need to look at
|
||||
// the doxygen-style comments in the libvirt sources.
|
||||
//
|
||||
// Failing to find a flags type isn't a fatal error, it just means that we'll
|
||||
// leave the flags with a type of uint32.
|
||||
func changeFlagType(procName string, s *Structure, flagTypes map[string]ast.Expr) {
|
||||
for ix, d := range s.Members {
|
||||
if d.Name == "Flags" {
|
||||
tname, found := findFlagType(procName, flagTypes)
|
||||
|
||||
if found {
|
||||
s.Members[ix].Type = tname
|
||||
} else {
|
||||
// If you're adding procedures to to the manual map, you may
|
||||
// want to uncomment this to see what flag types are not found.
|
||||
// fmt.Println("flags type for", procName, "not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Routines called by the parser's actions.
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -592,7 +730,6 @@ func AddOptValue(identifier, itype string) {
|
||||
atype := "[]" + itype
|
||||
decl := NewDecl(identifier, atype)
|
||||
newType := "Opt" + decl.Name
|
||||
fmt.Printf("Adding mapping %v = %v\n", decl.Name, newType)
|
||||
goEquivTypes[decl.Name] = newType
|
||||
decl.Name = newType
|
||||
addDecl(decl)
|
||||
|
||||
Reference in New Issue
Block a user