From 9034590e873a1a0532b217467e167645745f16d4 Mon Sep 17 00:00:00 2001 From: Howard Yeh Date: Mon, 11 Dec 2017 17:15:31 +0800 Subject: [PATCH] variable expansion package --- cli.go | 16 ++++++++++++++++ deploy.go | 9 ++++++++- encode.go | 4 +++- varstr/expand.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 varstr/expand.go diff --git a/cli.go b/cli.go index f294660..5163e2a 100644 --- a/cli.go +++ b/cli.go @@ -1,6 +1,7 @@ package solar import ( + "encoding/hex" "fmt" "log" "net/url" @@ -13,6 +14,7 @@ import ( "github.com/qtumproject/solar/deployer" "github.com/qtumproject/solar/deployer/eth" "github.com/qtumproject/solar/deployer/qtum" + "github.com/qtumproject/solar/varstr" kingpin "gopkg.in/alecthomas/kingpin.v2" ) @@ -106,6 +108,20 @@ func (c *solarCLI) QtumRPC() *qtum.RPC { return rpc } +// ExpandJSONParams uses variable substitution syntax (e.g. $Foo, ${Foo}) to as placeholder for contract addresses +func (c *solarCLI) ExpandJSONParams(jsonParams string) string { + repo := c.ContractsRepository() + + return varstr.Expand(jsonParams, func(key string) string { + contract, found := repo.Get(key) + if !found { + panic(errors.Errorf("Invalid address expansion: %s", key)) + } + + return fmt.Sprintf("%#v", hex.EncodeToString(contract.Address)) + }) +} + func (c *solarCLI) Deployer() (deployer deployer.Deployer) { log := log.New(os.Stderr, "", log.Lshortfile) diff --git a/deploy.go b/deploy.go index e3dfe1b..864a691 100644 --- a/deploy.go +++ b/deploy.go @@ -68,7 +68,14 @@ func init() { fmt.Printf(" \033[36mdeploy\033[0m %s => %s\n", target.file, target.name) - err = deployer.CreateContract(contract, []byte(*jsonParams), target.name, *force, *aslib) + var params []byte + if jsonParams != nil { + jsonParams := solar.ExpandJSONParams(*jsonParams) + + params = []byte(jsonParams) + } + + err = deployer.CreateContract(contract, params, target.name, *force, *aslib) if err != nil { fmt.Println("\u2757\ufe0f \033[36mdeploy\033[0m", err) return diff --git a/encode.go b/encode.go index 655b806..e336764 100644 --- a/encode.go +++ b/encode.go @@ -30,7 +30,9 @@ func init() { var params []interface{} if jsonParams != nil { - err := json.Unmarshal([]byte(*jsonParams), ¶ms) + jsonParams := solar.ExpandJSONParams(*jsonParams) + + err := json.Unmarshal([]byte(jsonParams), ¶ms) if err != nil { return err } diff --git a/varstr/expand.go b/varstr/expand.go new file mode 100644 index 0000000..22c3f29 --- /dev/null +++ b/varstr/expand.go @@ -0,0 +1,48 @@ +package varstr + +// Modified from stdlib's os.Expand function. Remove special shell variable expansion. +// https://github.com/golang/go/blob/0da486dc72743faa6e601444dcc35728704a1545/src/os/env.go#L13 + +// Expand replaces ${var} or $var in the string based on the mapping function. +func Expand(s string, mapping func(string) string) string { + buf := make([]byte, 0, 2*len(s)) + // ${} is all ASCII, so bytes are fine for this operation. + i := 0 + for j := 0; j < len(s); j++ { + if s[j] == '$' && j+1 < len(s) { + buf = append(buf, s[i:j]...) + name, w := getVarName(s[j+1:]) + buf = append(buf, mapping(name)...) + j += w + i = j + 1 + } + } + return string(buf) + s[i:] +} + +// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore +func isAlphaNum(c uint8) bool { + return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' +} + +// getVarName returns the name that begins the string and the number of bytes +// consumed to extract it. If the name is enclosed in {}, it's part of a ${} +// expansion and two more bytes are needed than the length of the name. +func getVarName(s string) (string, int) { + if s[0] == '{' { + // Scan to closing brace + for i := 1; i < len(s); i++ { + if s[i] == '}' { + return s[1:i], i + 1 + } + } + return "", 1 // Bad syntax; just eat the brace. + + } + + // Scan alphanumerics. + var i int + for i = 0; i < len(s) && isAlphaNum(s[i]); i++ { + } + return s[:i], i +}