Skip to content
Snippets Groups Projects
write.go 4.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • Manuel Kieweg's avatar
    Manuel Kieweg committed
    package csbi
    
    import (
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"bytes"
    	"encoding/json"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"fmt"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"html/template"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"io/fs"
    	"os"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"os/exec"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"path/filepath"
    	"strings"
    
    	spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound"
    	"github.com/openconfig/ygot/genutil"
    	"github.com/openconfig/ygot/ygen"
    	log "github.com/sirupsen/logrus"
    	"github.com/spf13/viper"
    )
    
    // write takes a ygen.Generatedcode struct and writes the Go code
    // snippets contained within it to the io.Writer, w, provided as an argument.
    // The output includes a package header which is generated.
    func write(code *ygen.GeneratedGoCode, path string, sbiType spb.Type) error {
    	if err := os.Mkdir(path, 0755); err != nil {
    		if err.(*fs.PathError).Err.Error() != "file exists" {
    			return err
    		}
    	}
    	switch sbiType {
    	case spb.Type_PLUGIN:
    		return writePlugin(code, path)
    	case spb.Type_CONTAINERISED:
    		return writeCsbi(code, path)
    	default:
    		return fmt.Errorf("invalid sbi type provided")
    	}
    }
    
    func writeCsbi(code *ygen.GeneratedGoCode, path string) error {
    	controller := viper.GetString("controller-address")
    	target := viper.GetString("target-address")
    
    	writerViper := viper.New()
    	writerViper.Set("uuid", path)
    	writerViper.Set("controller", controller+":55055")
    	writerViper.Set("target", target)
    
    	if err := writerViper.WriteConfigAs(filepath.Join(path, ".csbi.toml")); err != nil {
    		return err
    	}
    
    	if err := copyFile(path, "csbi.go"); err != nil {
    		return err
    	}
    
    	if err := copyFile(path, "go.mod"); err != nil {
    		return err
    	}
    
    	if err := copyFile(path, "go.sum"); err != nil {
    		return err
    	}
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err := copyFile(path, "Dockerfile"); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		return err
    	}
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return writeCode(path, code)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    func writePlugin(code *ygen.GeneratedGoCode, path string) error {
    	err := writeCode(path, code)
    	if err != nil {
    		return err
    	}
    	return writeGoMod(path)
    }
    
    func copyFile(path, filename string) error {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	var stderr bytes.Buffer
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	srcFile := filepath.Join("resources", filename)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	dstFile := filepath.Join(path, filename)
    	cmd := exec.Command("cp", srcFile, dstFile)
    	cmd.Stderr = &stderr
    	err := cmd.Run()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		log.Error(stderr.String())
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		return err
    	}
    
    	log.WithFields(log.Fields{
    		"source file": srcFile,
    		"dst file":    dstFile,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}).Infof("file copied")
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return nil
    }
    
    func writeCode(path string, code *ygen.GeneratedGoCode) error {
    	code.CommonHeader = strings.TrimSuffix(code.CommonHeader, ")\n")
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	code.CommonHeader = code.CommonHeader + pluginImportAmendmend
    	code.Structs = append(code.Structs, pluginStruct)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	file := filepath.Join(path, "gostructs.go")
    	generatedCode := genutil.OpenFile(file)
    	defer genutil.SyncFile(generatedCode)
    	// Write the package header to the supplier writer.
    	fmt.Fprint(generatedCode, code.CommonHeader)
    	fmt.Fprint(generatedCode, code.OneOffHeader)
    
    	// Write the returned Go code out. First the Structs - which is the struct
    	// definitions for the generated YANG entity, followed by the enumerations.
    	for _, snippet := range code.Structs {
    		fmt.Fprintln(generatedCode, snippet)
    	}
    
    	for _, snippet := range code.Enums {
    		fmt.Fprintln(generatedCode, snippet)
    	}
    
    	// Write the generated enumeration map out.
    	fmt.Fprintln(generatedCode, code.EnumMap)
    
    	// Write the schema out if it was received.
    	if len(code.JSONSchemaCode) > 0 {
    		fmt.Fprintln(generatedCode, code.JSONSchemaCode)
    	}
    
    	if len(code.EnumTypeMap) > 0 {
    		fmt.Fprintln(generatedCode, code.EnumTypeMap)
    	}
    	return nil
    }
    
    func writeDockerfile(path string, buffer []string) error {
    	file := filepath.Join(path, "Dockerfile")
    	dockerfile, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0755)
    	defer dockerfile.Sync()
    	if err != nil {
    		return err
    	}
    	for _, line := range buffer {
    		fmt.Fprintln(dockerfile, line)
    	}
    	return nil
    }
    
    func writeGoMod(path string) error {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	// Read dependencies from JSON file
    	deps, err := os.ReadFile(filepath.Join("resources", "plugin_deps.json"))
    	if err != nil {
    		return err
    	}
    	module := GoMod{}
    	if err := json.Unmarshal(deps, &module); err != nil {
    		return err
    	}
    
    	// Create go.mod in destination directory and write template
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	file := filepath.Join(path, "go.mod")
    	goMod, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0755)
    	if err != nil {
    		return err
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	defer goMod.Sync()
    
    	templater := template.New("goMod").Delims("<<", ">>")
    	_, err = templater.Parse(pluginGoModTemplate)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    		return err
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return templater.Execute(goMod, module)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }