scripts/resolve_i64/main.go (123 lines of code) (raw):
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"github.com/pkg/errors"
"github.com/uber/zanzibar/codegen"
"github.com/uber/zanzibar/runtime"
"go.uber.org/thriftrw/compile"
)
const (
templateFileName = "i64.tmpl"
outFileName = "/types_i64.go"
)
type naivePackageNameResolver struct {
}
func (r *naivePackageNameResolver) TypePackageName(
thriftFile string,
) (string, error) {
if thriftFile[0] == '.' {
return "", errors.Errorf("Naive does not support relative imports")
}
return "", nil
}
// Meta is the struct container for i64 related meta data and package name
type Meta struct {
PackageName string
Types []I64Struct
}
// I64Structs is the struct container for array if I64Struct
type I64Structs []I64Struct
// I64Struct is the struct container for i64 related meta data
type I64Struct struct {
IsLong bool
IsTimestamp bool
TypedefType string
}
func (l I64Structs) Len() int { return len(l) }
func (l I64Structs) Less(i, j int) bool {
return l[i].TypedefType < l[j].TypedefType
}
func (l I64Structs) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func getDirName() string {
_, file, _, _ := runtime.Caller(0)
return zanzibar.GetDirnameFromRuntimeCaller(file)
}
func main() {
thriftFile := os.Args[1]
idlPathPrefix := os.Args[2]
annotationJSType := os.Args[3]
module, err := compile.Compile(thriftFile)
if err != nil {
panic(fmt.Sprintf("Failed to parse thrift file: %s", thriftFile))
}
meta := &Meta{}
s := strings.TrimSuffix(thriftFile, ".thrift")
s = strings.Replace(s, idlPathPrefix, "/build/gen-code/", 1)
meta.PackageName = filepath.Base(s)
for _, typeDef := range module.Types {
t, ok := typeDef.(*compile.TypedefSpec)
if !ok {
continue
}
i64Struct := I64Struct{}
if t.Target != nil {
typThriftAnnotation := t.Target.ThriftAnnotations()
if typThriftAnnotation != nil {
p := naivePackageNameResolver{}
refType, err := codegen.GoReferenceType(&p, t)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing reference type: %s", err.Error()))
os.Exit(1)
return
}
i64Struct.TypedefType = refType[1:]
if typThriftAnnotation[annotationJSType] == "Long" {
i64Struct.IsLong = true
}
if typThriftAnnotation[annotationJSType] == "Date" {
i64Struct.IsTimestamp = true
}
}
}
if i64Struct.IsTimestamp || i64Struct.IsLong {
meta.Types = append(meta.Types, i64Struct)
}
}
if len(meta.Types) == 0 {
return
}
// Note type defs are not read by unique order so they need to be sorted before writing
sort.Sort(I64Structs(meta.Types))
tmpl, err := template.ParseFiles(filepath.Join(getDirName(), templateFileName))
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf(
"error parsing template %s: %s", templateFileName, err.Error()))
os.Exit(1)
return
}
tplBuffer := bytes.NewBuffer(nil)
err = tmpl.Execute(tplBuffer, meta)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf(
"error executing template %s: %s", templateFileName, err.Error()))
os.Exit(1)
return
}
outName := s + outFileName
err = ioutil.WriteFile(outName, tplBuffer.Bytes(), 0644)
if err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf(
"error writing file to %s, err: %s", templateFileName, err.Error()))
os.Exit(1)
return
}
err = codegen.FormatGoFile(outName)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}