cmd/abigen: support for reading solc output from stdin (#16683)

Allow the --abi flag to be given - to indicate that it should read the
ABI information from standard input. It expects to read the solc output
with the --combined-json flag providing bin, abi, userdoc, devdoc, and
metadata, and works very similarly to the internal invocation of solc,
except it allows external invocation of solc.

This facilitates integration with more complex solc invocations, such
as invocations that require path remapping or --allow-paths tweaks.

Simple usage example:

    solc --combined-json bin,abi,userdoc,devdoc,metadata *.sol | abigen --abi -
pull/16760/merge
Antonio Salazar Cardozo 7 years ago committed by Felix Lange
parent 0029a869f0
commit 4cf2b4110e
  1. 26
      cmd/abigen/main.go
  2. 28
      common/compiler/solidity.go

@ -29,7 +29,7 @@ import (
) )
var ( var (
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind") abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN")
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)") binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)") typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
@ -75,17 +75,28 @@ func main() {
bins []string bins []string
types []string types []string
) )
if *solFlag != "" { if *solFlag != "" || *abiFlag == "-" {
// Generate the list of types to exclude from binding // Generate the list of types to exclude from binding
exclude := make(map[string]bool) exclude := make(map[string]bool)
for _, kind := range strings.Split(*excFlag, ",") { for _, kind := range strings.Split(*excFlag, ",") {
exclude[strings.ToLower(kind)] = true exclude[strings.ToLower(kind)] = true
} }
contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag)
var contracts map[string]*compiler.Contract
var err error
if *solFlag != "" {
contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag)
if err != nil { if err != nil {
fmt.Printf("Failed to build Solidity contract: %v\n", err) fmt.Printf("Failed to build Solidity contract: %v\n", err)
os.Exit(-1) os.Exit(-1)
} }
} else {
contracts, err = contractsFromStdin()
if err != nil {
fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err)
os.Exit(-1)
}
}
// Gather all non-excluded contract for binding // Gather all non-excluded contract for binding
for name, contract := range contracts { for name, contract := range contracts {
if exclude[strings.ToLower(name)] { if exclude[strings.ToLower(name)] {
@ -138,3 +149,12 @@ func main() {
os.Exit(-1) os.Exit(-1)
} }
} }
func contractsFromStdin() (map[string]*compiler.Contract, error) {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return nil, err
}
return compiler.ParseCombinedJSON(bytes, "", "", "", "")
}

@ -31,11 +31,17 @@ import (
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
// Contract contains information about a compiled contract, alongside its code.
type Contract struct { type Contract struct {
Code string `json:"code"` Code string `json:"code"`
Info ContractInfo `json:"info"` Info ContractInfo `json:"info"`
} }
// ContractInfo contains information about a compiled contract, including access
// to the ABI definition, user and developer docs, and metadata.
//
// Depending on the source, language version, compiler version, and compiler
// options will provide information about how the contract was compiled.
type ContractInfo struct { type ContractInfo struct {
Source string `json:"source"` Source string `json:"source"`
Language string `json:"language"` Language string `json:"language"`
@ -142,8 +148,22 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes()) return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
} }
return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
}
// ParseCombinedJSON takes the direct output of a solc --combined-output run and
// parses it into a map of string contract name to Contract structs. The
// provided source, language and compiler version, and compiler options are all
// passed through into the Contract structs.
//
// The solc output is expected to contain ABI, user docs, and dev docs.
//
// Returns an error if the JSON is malformed or missing data, or if the JSON
// embedded within the JSON is malformed.
func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutput var output solcOutput
if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { if err := json.Unmarshal(combinedJSON, &output); err != nil {
return nil, err return nil, err
} }
@ -168,9 +188,9 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
Info: ContractInfo{ Info: ContractInfo{
Source: source, Source: source,
Language: "Solidity", Language: "Solidity",
LanguageVersion: s.Version, LanguageVersion: languageVersion,
CompilerVersion: s.Version, CompilerVersion: compilerVersion,
CompilerOptions: strings.Join(s.makeArgs(), " "), CompilerOptions: compilerOptions,
AbiDefinition: abi, AbiDefinition: abi,
UserDoc: userdoc, UserDoc: userdoc,
DeveloperDoc: devdoc, DeveloperDoc: devdoc,

Loading…
Cancel
Save