github.com/klaytn/klaytn@v1.10.2/rlp/rlpgen/main.go (about)

     1  // Modifications Copyright 2022 The klaytn Authors
     2  // Copyright 2021 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from rlp/rlpgen/main.go(2022/05/19)
    19  // Modified and improved for the klaytn development.
    20  
    21  package main
    22  
    23  import (
    24  	"bytes"
    25  	"errors"
    26  	"flag"
    27  	"fmt"
    28  	"go/types"
    29  	"io/ioutil"
    30  	"os"
    31  
    32  	"golang.org/x/tools/go/packages"
    33  )
    34  
    35  const pathOfPackageRLP = "github.com/klaytn/klaytn/rlp"
    36  
    37  func main() {
    38  	var (
    39  		pkgdir     = flag.String("dir", ".", "input package")
    40  		output     = flag.String("out", "-", "output file (default is stdout)")
    41  		genEncoder = flag.Bool("encoder", true, "generate EncodeRLP?")
    42  		genDecoder = flag.Bool("decoder", false, "generate DecodeRLP?")
    43  		typename   = flag.String("type", "", "type to generate methods for")
    44  	)
    45  	flag.Parse()
    46  
    47  	cfg := Config{
    48  		Dir:             *pkgdir,
    49  		Type:            *typename,
    50  		GenerateEncoder: *genEncoder,
    51  		GenerateDecoder: *genDecoder,
    52  	}
    53  	code, err := cfg.process()
    54  	if err != nil {
    55  		fatal(err)
    56  	}
    57  	if *output == "-" {
    58  		os.Stdout.Write(code)
    59  	} else if err := ioutil.WriteFile(*output, code, 0o644); err != nil {
    60  		fatal(err)
    61  	}
    62  }
    63  
    64  func fatal(args ...interface{}) {
    65  	fmt.Fprintln(os.Stderr, args...)
    66  	os.Exit(1)
    67  }
    68  
    69  type Config struct {
    70  	Dir  string // input package directory
    71  	Type string
    72  
    73  	GenerateEncoder bool
    74  	GenerateDecoder bool
    75  }
    76  
    77  // process generates the Go code.
    78  func (cfg *Config) process() (code []byte, err error) {
    79  	// Load packages.
    80  	pcfg := &packages.Config{
    81  		Mode:       packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps,
    82  		Dir:        cfg.Dir,
    83  		BuildFlags: []string{"-tags", "norlpgen"},
    84  	}
    85  	ps, err := packages.Load(pcfg, pathOfPackageRLP, ".")
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	if len(ps) == 0 {
    90  		return nil, fmt.Errorf("no Go package found in %s", cfg.Dir)
    91  	}
    92  	packages.PrintErrors(ps)
    93  
    94  	// Find the packages that were loaded.
    95  	var (
    96  		pkg        *types.Package
    97  		packageRLP *types.Package
    98  	)
    99  	for _, p := range ps {
   100  		if len(p.Errors) > 0 {
   101  			return nil, fmt.Errorf("package %s has errors", p.PkgPath)
   102  		}
   103  		if p.PkgPath == pathOfPackageRLP {
   104  			packageRLP = p.Types
   105  		} else {
   106  			pkg = p.Types
   107  		}
   108  	}
   109  	bctx := newBuildContext(packageRLP)
   110  
   111  	// Find the type and generate.
   112  	typ, err := lookupStructType(pkg.Scope(), cfg.Type)
   113  	if err != nil {
   114  		return nil, fmt.Errorf("can't find %s in %s: %v", typ, pkg, err)
   115  	}
   116  	code, err = bctx.generate(typ, cfg.GenerateEncoder, cfg.GenerateDecoder)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	// Add build comments.
   122  	// This is done here to avoid processing these lines with gofmt.
   123  	var header bytes.Buffer
   124  	fmt.Fprint(&header, "// Code generated by rlpgen. DO NOT EDIT.\n\n")
   125  	fmt.Fprint(&header, "//go:build !norlpgen\n")
   126  	fmt.Fprint(&header, "// +build !norlpgen\n\n")
   127  	return append(header.Bytes(), code...), nil
   128  }
   129  
   130  func lookupStructType(scope *types.Scope, name string) (*types.Named, error) {
   131  	typ, err := lookupType(scope, name)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	_, ok := typ.Underlying().(*types.Struct)
   136  	if !ok {
   137  		return nil, errors.New("not a struct type")
   138  	}
   139  	return typ, nil
   140  }
   141  
   142  func lookupType(scope *types.Scope, name string) (*types.Named, error) {
   143  	obj := scope.Lookup(name)
   144  	if obj == nil {
   145  		return nil, errors.New("no such identifier")
   146  	}
   147  	typ, ok := obj.(*types.TypeName)
   148  	if !ok {
   149  		return nil, errors.New("not a type")
   150  	}
   151  	return typ.Type().(*types.Named), nil
   152  }