package main import ( "bufio" "io" "os" "path" "path/filepath" "reflect" "strings" "text/template" ) func main() { var wd string var err error if len(os.Args) == 1 { wd, err = os.Getwd() if err != nil { panic(err) } } else { wd = os.Args[1] } cfg := buildCfgFromDir(wd) outfile := path.Join(wd, "zzgenerated_plugin.go") out, err := os.Create(outfile) if err != nil { panic(err) } defer out.Close() pluginTmpl.Execute(out, map[string]interface{}{ "Config": cfg, }) } type libraryConfig struct { Plugin *pluginConfig Element *elementConfig } type pluginConfig struct { Name, Description, Version, License, Source, Package, Origin, ReleaseDate string } type elementConfig struct { Name, Rank, Impl, Subclass, Interfaces string } func buildCfgFromDir(dir string) *libraryConfig { cfg := &libraryConfig{ Plugin: &pluginConfig{}, Element: &elementConfig{}, } err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if !strings.HasSuffix(path, ".go") { return nil } parseFileIntoCfg(path, cfg) return nil }) if err != nil { panic(err) } return cfg } func parseFileIntoCfg(path string, cfg *libraryConfig) { f, err := os.Open(path) if err != nil { panic(err) } scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() if !strings.HasPrefix(line, "// +") { continue } line = strings.TrimPrefix(line, "// +") if strings.HasPrefix(line, "plugin:") { parseLineToConfig("plugin", line, cfg.Plugin) continue } if strings.HasPrefix(line, "element:") { parseLineToConfig("element", line, cfg.Element) } } if err := scanner.Err(); err != nil && err != io.EOF { panic(err) } } func parseLineToConfig(prefix, line string, cfg interface{}) { trimmed := strings.TrimPrefix(line, prefix+":") arg, val := parseArgAndValue(trimmed) v := reflect.ValueOf(cfg).Elem() for i := 0; i < v.NumField(); i++ { if v.Type().Field(i).Name == arg { v.FieldByName(arg).SetString(val) } } } func parseArgAndValue(line string) (arg, val string) { spl := strings.Split(line, "=") return spl[0], spl[1] } var pluginTmpl = template.Must(template.New("").Funcs(template.FuncMap{ "adjustedName": func(name string) string { return strings.ToLower(strings.Replace(name, "-", "_", -1)) }, "splitInterfaces": func(ifacesString string) []string { return strings.Split(ifacesString, ",") }, "extendsFromBase": func(subclass string) bool { return strings.HasPrefix(subclass, "base.") }, }).Parse(`// !WARNING! THIS FILE WAS GENERATED BY GST-PLUGIN-GEN !WARNING! // package main import "C" import ( "unsafe" "github.com/go-gst/go-gst/gst" {{- if (.Config.Element.Subclass | extendsFromBase) }} "github.com/go-gst/go-gst/gst/base" {{- end }} ) // The metadata for this plugin var pluginMeta = &gst.PluginMetadata{ MajorVersion: gst.VersionMajor, MinorVersion: gst.VersionMinor, Name: "{{ .Config.Plugin.Name }}", Description: "{{ .Config.Plugin.Description }}", Version: "{{ .Config.Plugin.Version }}", License: {{ .Config.Plugin.License }}, Source: "{{ .Config.Plugin.Source }}", Package: "{{ .Config.Plugin.Package }}", Origin: "{{ .Config.Plugin.Origin }}", ReleaseDate: "{{ .Config.Plugin.ReleaseDate }}", // The init function is called to register elements provided by the plugin. Init: func(plugin *gst.Plugin) bool { return gst.RegisterElement( plugin, // The name of the element "{{ .Config.Element.Name }}", // The rank of the element {{ .Config.Element.Rank }}, // The GoElement implementation for the element &{{ .Config.Element.Impl }}{}, // The base subclass this element extends {{ .Config.Element.Subclass }}, {{- if .Config.Element.Interfaces }} // The interfaces this element implements {{- range $index, $interface := .Config.Element.Interfaces | splitInterfaces }} {{ $interface }}, {{- end }} {{- end }} ) }, } // A single method must be exported from the compiled library that provides for GStreamer // to fetch the description and init function for this plugin. The name of the method // must match the format gst_plugin_NAME_get_desc, where NAME is the name of the compiled // artifact with or without the "libgst" prefix and hyphens are replaced with underscores. //export gst_plugin_{{ .Config.Plugin.Name | adjustedName }}_get_desc func gst_plugin_{{ .Config.Plugin.Name | adjustedName }}_get_desc() unsafe.Pointer { return pluginMeta.Export() } `))