github.com/bluenviron/gomavlib/v2@v2.2.1-0.20240308101627-2c07e3da629c/cmd/dialects-gen/main.go (about)

     1  // dialects-gen command.
     2  package main
     3  
     4  import (
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strings"
    12  	"text/template"
    13  )
    14  
    15  var tplTest = template.Must(template.New("").Parse(
    16  	`//autogenerated:yes
    17  //nolint:revive
    18  package dialects
    19  
    20  import (
    21      "testing"
    22      "encoding"
    23      "reflect"
    24  
    25      "github.com/stretchr/testify/require"
    26  
    27      "github.com/bluenviron/gomavlib/v2/pkg/dialect"
    28  {{- range .Dialects }}
    29  	"github.com/bluenviron/gomavlib/v2/pkg/dialects/{{ . }}"
    30  {{- end }}
    31  )
    32  
    33  func TestDialects(t *testing.T) {
    34  {{- range .Dialects }}
    35  	func() {
    36  		_, err := dialect.NewReadWriter({{ . }}.Dialect)
    37  		require.NoError(t, err)
    38  	}()
    39  {{- end }}
    40  }
    41  
    42  var casesEnum = []struct {
    43  	name string
    44  	dec  encoding.TextMarshaler
    45  	enc  string
    46  }{
    47  	{
    48  		"bitmask",
    49  		common.POSITION_TARGET_TYPEMASK_VX_IGNORE | common.POSITION_TARGET_TYPEMASK_VY_IGNORE,
    50  		"POSITION_TARGET_TYPEMASK_VX_IGNORE | POSITION_TARGET_TYPEMASK_VY_IGNORE",
    51  	},
    52  	{
    53  		"value",
    54  		common.GPS_FIX_TYPE_NO_FIX,
    55  		"GPS_FIX_TYPE_NO_FIX",
    56  	},
    57  }
    58  
    59  func TestEnumUnmarshalText(t *testing.T) {
    60  	for _, ca := range casesEnum {
    61  		t.Run(ca.name, func(t *testing.T) {
    62  			dec := reflect.New(reflect.TypeOf(ca.dec)).Interface().(encoding.TextUnmarshaler)
    63  			err := dec.UnmarshalText([]byte(ca.enc))
    64  			require.NoError(t, err)
    65  			require.Equal(t, ca.dec, reflect.ValueOf(dec).Elem().Interface())
    66  		})
    67  	}
    68  }
    69  
    70  func TestEnumMarshalText(t *testing.T) {
    71  	for _, ca := range casesEnum {
    72  		t.Run(ca.name, func(t *testing.T) {
    73  			byts, err := ca.dec.MarshalText()
    74  			require.NoError(t, err)
    75  			require.Equal(t, ca.enc, string(byts))
    76  		})
    77  	}
    78  }
    79  `))
    80  
    81  func writeTemplate(fpath string, tpl *template.Template, args map[string]interface{}) error {
    82  	f, err := os.Create(fpath)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	defer f.Close()
    87  
    88  	return tpl.Execute(f, args)
    89  }
    90  
    91  func shellCommand(cmdstr string) error {
    92  	fmt.Fprintf(os.Stderr, "%s\n", cmdstr)
    93  	cmd := exec.Command("sh", "-c", cmdstr)
    94  	cmd.Stderr = os.Stderr
    95  	cmd.Stdout = os.Stdout
    96  	return cmd.Run()
    97  }
    98  
    99  func downloadJSON(addr string, data interface{}) error {
   100  	req, err := http.NewRequest("GET", addr, nil)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	res, err := http.DefaultClient.Do(req)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	defer res.Body.Close()
   110  
   111  	return json.NewDecoder(res.Body).Decode(data)
   112  }
   113  
   114  func processDialect(commit string, name string) error {
   115  	fmt.Fprintf(os.Stderr, "[%s]\n", name)
   116  
   117  	err := shellCommand(fmt.Sprintf("go run ../../cmd/dialect-import --link %s",
   118  		"https://raw.githubusercontent.com/mavlink/mavlink/"+commit+"/message_definitions/v1.0/"+name+".xml",
   119  	))
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	fmt.Fprintf(os.Stderr, "\n")
   125  	return nil
   126  }
   127  
   128  func run() error {
   129  	err := shellCommand("rm -rf pkg/dialects/*/")
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	os.Mkdir(filepath.Join("pkg", "dialects"), 0o755)
   135  	os.Chdir(filepath.Join("pkg", "dialects"))
   136  
   137  	var res struct {
   138  		Sha string `json:"sha"`
   139  	}
   140  	err = downloadJSON("https://api.github.com/repos/mavlink/mavlink/commits/master", &res)
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	var files []struct {
   146  		Name string `json:"name"`
   147  	}
   148  	err = downloadJSON("https://api.github.com/repos/mavlink/mavlink/contents/message_definitions/v1.0?ref="+res.Sha,
   149  		&files)
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	var dialects []string //nolint:prealloc
   155  
   156  	for _, f := range files {
   157  		if !strings.HasSuffix(f.Name, ".xml") {
   158  			continue
   159  		}
   160  		name := f.Name[:len(f.Name)-len(".xml")]
   161  
   162  		err = processDialect(res.Sha, name)
   163  		if err != nil {
   164  			return err
   165  		}
   166  
   167  		dialects = append(dialects, strings.ReplaceAll(strings.ToLower(name), "_", ""))
   168  	}
   169  
   170  	err = writeTemplate(
   171  		"package_test.go",
   172  		tplTest,
   173  		map[string]interface{}{
   174  			"Dialects": dialects,
   175  		})
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func main() {
   184  	err := run()
   185  	if err != nil {
   186  		fmt.Fprintf(os.Stderr, "ERR: %s\n", err)
   187  		os.Exit(1)
   188  	}
   189  }