github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/common/compiler/vyper.go (about) 1 package compiler 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os/exec" 9 "strconv" 10 "strings" 11 ) 12 13 type Vyper struct { 14 Path, Version, FullVersion string 15 Major, Minor, Patch int 16 } 17 18 func (s *Vyper) makeArgs() []string { 19 p := []string{ 20 "-f", "combined_json", 21 } 22 return p 23 } 24 25 func VyperVersion(vyper string) (*Vyper, error) { 26 if vyper == "" { 27 vyper = "vyper" 28 } 29 var out bytes.Buffer 30 cmd := exec.Command(vyper, "--version") 31 cmd.Stdout = &out 32 err := cmd.Run() 33 if err != nil { 34 return nil, err 35 } 36 matches := versionRegexp.FindStringSubmatch(out.String()) 37 if len(matches) != 4 { 38 return nil, fmt.Errorf("can't parse vyper version %q", out.String()) 39 } 40 s := &Vyper{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]} 41 if s.Major, err = strconv.Atoi(matches[1]); err != nil { 42 return nil, err 43 } 44 if s.Minor, err = strconv.Atoi(matches[2]); err != nil { 45 return nil, err 46 } 47 if s.Patch, err = strconv.Atoi(matches[3]); err != nil { 48 return nil, err 49 } 50 return s, nil 51 } 52 53 func CompileVyper(vyper string, sourcefiles ...string) (map[string]*Contract, error) { 54 if len(sourcefiles) == 0 { 55 return nil, errors.New("vyper: no source files") 56 } 57 source, err := slurpFiles(sourcefiles) 58 if err != nil { 59 return nil, err 60 } 61 s, err := VyperVersion(vyper) 62 if err != nil { 63 return nil, err 64 } 65 args := s.makeArgs() 66 cmd := exec.Command(s.Path, append(args, sourcefiles...)...) 67 return s.run(cmd, source) 68 } 69 70 func (s *Vyper) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) { 71 var stderr, stdout bytes.Buffer 72 cmd.Stderr = &stderr 73 cmd.Stdout = &stdout 74 if err := cmd.Run(); err != nil { 75 return nil, fmt.Errorf("vyper: %v\n%s", err, stderr.Bytes()) 76 } 77 78 return ParseVyperJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " ")) 79 } 80 81 func ParseVyperJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) { 82 var output map[string]interface{} 83 if err := json.Unmarshal(combinedJSON, &output); err != nil { 84 return nil, err 85 } 86 87 contracts := make(map[string]*Contract) 88 for name, info := range output { 89 90 if name == "version" { 91 continue 92 } 93 c := info.(map[string]interface{}) 94 95 contracts[name] = &Contract{ 96 Code: c["bytecode"].(string), 97 RuntimeCode: c["bytecode_runtime"].(string), 98 Info: ContractInfo{ 99 Source: source, 100 Language: "Vyper", 101 LanguageVersion: languageVersion, 102 CompilerVersion: compilerVersion, 103 CompilerOptions: compilerOptions, 104 SrcMap: c["source_map"], 105 SrcMapRuntime: "", 106 AbiDefinition: c["abi"], 107 UserDoc: "", 108 DeveloperDoc: "", 109 Metadata: "", 110 }, 111 } 112 } 113 return contracts, nil 114 }