I have the following function I am trying to test:
import (
"github.com/spf13/pflag"
)
func parseCLIFlags() cliOptions {
mode := pflag.StringP("mode", "m", "json", "file format")
outType := pflag.StringP("out-type", "o", "stdout", "Output format")
outFile := pflag.String("out-file", "", "Output file. Only used if `--out-type` is not stdout")
inFiles := pflag.StringArrayP("file", "f", []string{}, "Files to compare. Use this flag multiple times, once for each file.")
pflag.Parse()
options := cliOptions{
mode: *mode,
outType: *outType,
outFile: *outFile,
inFiles: *inFiles,
}
return options
}
and I am trying to test with the following tests:
func TestFlagsAreParsedCorrectly(t *testing.T) {
os.Args = []string{"schmp", "-f", "testdata/yaml/yaml_1.yaml", "--file", "testdata/yaml/yaml_2.yaml", "--mode", "yaml", "-o", "json", "--out-file", "sample.json"}
cliOptions := parseCLIFlags()
if cliOptions.mode != "yaml" {
t.Fatalf("could not set mode")
}
if cliOptions.outType != "json" {
t.Fatalf("could not set outType")
}
if cliOptions.outFile != "sample.json" {
t.Fatalf("could not set outFile")
}
if !reflect.DeepEqual(cliOptions.inFiles, []string{"testdata/yaml/yaml_1.yaml", "testdata/yaml/yaml_2.yaml"}) {
fmt.Println("could not set inFiles")
}
}
func TestCheckDefaultFlags(t *testing.T) {
os.Args = []string{"schmp"}
cliOptions := parseCLIFlags()
if cliOptions.mode != "json" {
t.Fatalf("default mode is not `json`")
}
}
But my tests are panicing with flag redefined: mode
Any idea how I can fix this so I can test?
As per the comment by #Adrian, I was able to fix it by creating a FlagSet in parseCLIFlags:
func parseCLIFlags() cliOptions {
flag := pflag.FlagSet{}
mode := flag.StringP("mode", "m", "json", "file format")
outType := flag.StringP("out-type", "o", "stdout", "Output format")
outFile := flag.String("out-file", "", "Output file. Only used if `--out-type` is not stdout")
inFiles := flag.StringArrayP("file", "f", []string{}, "Files to compare. Use this flag multiple times, once for each file.")
flag.Parse(os.Args[1:])
options := cliOptions{
mode: *mode,
outType: *outType,
outFile: *outFile,
inFiles: *inFiles,
}
return options
}
Related
I have the requirement to write a cross-platform cli tool in go by leveraging the AWS SDKv2 GO.
I need to parse a json file like this:
{
"Tags": [
{
"Key": "global1",
"Value": "val1"
},
{
"Key": "global2",
"Value": "val2"
}
]
}
I have this function:
package lib
import (
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"encoding/json"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"io/ioutil"
"os"
)
//func CreateSecret(client *secretsmanager.Client, secretName string, description string, kmsKeyId string, secretString string) {
func CreateSecret(client *secretsmanager.Client) {
// Parse tags.json
jsonFile, err := os.Open("tags.json")
if err != nil {
fmt.Println(err)
}
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
tags := []*secretsmanager.Tag{}
json.Unmarshal(byteValue, &tags)
// rest of the code is truncated...
}
However, I receive this error:
lib/commands.go:58:28: undefined: secretsmanager.Tag
What am I doing wrong?
secretsmanager.Tag does not exist. But what I think you are looking for is this package: github.com/aws/aws-sdk-go-v2/service/secretsmanager/types. Import it and then you will have types.Tag, which is what you probably need.
I've test cases with a series of words like this :
{
input: "Halley's Comet",
expected: "HC",
},
{
input: "First In, First Out",
expected: "FIFO",
},
{
input: "The Road _Not_ Taken",
expected: "TRNT",
},
I want with one regex to match all first letters of these words, avoid char: "_" to be matched as a first letter and count single quote in the word.
Currently, I have this regex working on pcre syntax but not with Go regexp package : (?<![a-zA-Z0-9'])([a-zA-Z0-9'])
I know lookarounds aren't supported by Go but I'm looking for a good way to do that.
I also use this func to get an array of all strings : re.FindAllString(s, -1)
Thanks for helping.
Something that plays with character classes and word boundaries should suffice:
\b_*([a-z])[a-z]*(?:'s)?_*\b\W*
demo
Usage:
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`(?i)\b_*([a-z])[a-z]*(?:'s)?_*\b\W*`)
fmt.Println(re.ReplaceAllString("O'Brian's dog", "$1"))
}
ftr, regexp less solution
package main
import (
"fmt"
)
func main() {
inputs := []string{"Hallمرحباey's Comet", "First In, First Out", "The Road _Not_ Taken", "O'Brian's Dog"}
c := [][]string{}
w := [][]string{}
for _, input := range inputs {
c = append(c, firstLet(input))
w = append(w, words(input))
}
fmt.Printf("%#v\n", w)
fmt.Printf("%#v\n", c)
}
func firstLet(in string) (out []string) {
var inword bool
for _, r := range in {
if !inword {
if isChar(r) {
inword = true
out = append(out, string(r))
}
} else if r == ' ' {
inword = false
}
}
return out
}
func words(in string) (out []string) {
var inword bool
var w []rune
for _, r := range in {
if !inword {
if isChar(r) {
w = append(w, r)
inword = true
}
} else if r == ' ' {
if len(w) > 0 {
out = append(out, string(w))
w = w[:0]
}
inword = false
} else if r != '_' {
w = append(w, r)
}
}
if len(w) > 0 {
out = append(out, string(w))
}
return out
}
func isChar(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
}
outputs
[][]string{[]string{"Hallمرحباey's", "Comet"}, []string{"First", "In,", "First", "Out"}, []string{"The", "Road", "Not", "Taken"}, []string{"O'Brian's", "Dog"}}
[][]string{[]string{"H", "C"}, []string{"F", "I", "F", "O"}, []string{"T", "R", "N", "T"}, []string{"O", "D"}}
I'm using the following Go code to get only ONE registry in my dynamoDB table, but instead, it's returning all of them:
condition1 := expression.Name("id").Equal(expression.Value(id))
condition2 := expression.Name("apiKey").Equal(expression.Value(apiKey))
projection := expression.NamesList(
expression.Name("data"),
)
expr, err := expression.NewBuilder().
WithFilter(condition1).
WithFilter(condition2).
WithProjection(projection).
Build()
if err != nil {
return "", err
}
req := svc.ScanRequest(&dynamodb.ScanInput{
TableName: aws.String(awsEnv.Dynamo_Table),
ExpressionAttributeNames: expr.Names(),
ExpressionAttributeValues: expr.Values(),
FilterExpression: expr.Filter(),
ProjectionExpression: expr.Projection(),
})
result, err := req.Send()
if err != nil {
// TODO
}
fmt.Println(result.Items)
This should contain only one registry, since there is only one registry that satisfies the id filter condition, but instead, I'm getting ALL registries.
Am I missing something?
The ScanInput exist attribute Setlimit (receive int64), you did not declare it:
req := svc.ScanRequest(&dynamodb.ScanInput{
Setlimit: 1,
TableName: aws.String(awsEnv.Dynamo_Table),
ExpressionAttributeNames: expr.Names(),
ExpressionAttributeValues: expr.Values(),
FilterExpression: expr.Filter(),
ProjectionExpression: expr.Projection(),
})
read more:
https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#ScanInput.SetLimit
Given a string (a line in a log file):
Date=2017-06-29 03:10:01.140 -700 PDT,clientDataRate="12.0,18.0,24.0,36.0,48.0,54.0",host=superawesomehost.foo,foo=bar
I'd like to replace the commas with a single space, but only within double quotes.
Desired result:
Date=2017-06-29 03:10:01.140 -700 PDT,clientDataRate="12.0 18.0 24.0 36.0 48.0 54.0",host=superawesomehost.foo,foo=bar
I've begun with a basic combination of regex and ReplaceAllString but am rapidly realizing I don't understand how to implement the match group (?) needed to accomplish this.
package main
import (
"fmt"
"log"
"regexp"
)
func main() {
logLine := "Date=2017-06-29 03:10:01.140 -700 PDT,clientDataRate=\"12.0,18.0,24.0,36.0,48.0,54.0\",host=superawesomehost.foo,foo=bar"
fmt.Println("logLine: ", logLine)
reg, err := regexp.Compile("[^A-Za-z0-9=\"-:]+")
if err != nil {
log.Fatal(err)
}
repairedLogLine := reg.ReplaceAllString(logLine, ",")
fmt.Println("repairedLogLine:", repairedLogLine )
}
All help is much appreciated.
You'll want to use Regexp.ReplaceAllStringFunc, which allows you to use a function result as the replacement of a substring:
package main
import (
"fmt"
"log"
"regexp"
"strings"
)
func main() {
logLine := `Date=2017-06-29 03:10:01.140 -700 PDT,clientDataRate="12.0,18.0,24.0,36.0,48.0,54.0",host=superawesomehost.foo,foo=bar`
fmt.Println("logLine: ", logLine)
reg, err := regexp.Compile(`"([^"]*)"`)
if err != nil {
log.Fatal(err)
}
repairedLogLine := reg.ReplaceAllStringFunc(logLine, func(entry string) string {
return strings.Replace(entry, ",", " ", -1)
})
fmt.Println("repairedLogLine:", repairedLogLine)
}
https://play.golang.org/p/BsZxcrrvaR
Does anyone know how to concatenate strings from consul for consul-template?
If I have a service 'foo' registered in Consul
{
"Node": "node1",
"Address": "192.168.0.1",
"Port": 3333
},
{
"Node": "node2",
"Address": "192.168.0.2",
"Port": 4444
}
I would like consul-template to generate the following line:
servers=192.168.0.1:3333,192.168.0.2:4444/bogus
The following attempt does not work since it leaves a trailing comma ,
servers={{range service "foo"}}{{.Address}}{{.Port}},{{end}}/bogus
# renders
servers=192.168.0.1:3333,192.168.0.2:4444,/bogus
# What I actually want
servers=192.168.0.1:3333,192.168.0.2:4444/bogus
I know consul-template uses golang template syntax, but I simply cannot figure out the syntax to get this working. Its likely that I should use consul-template's join but how do I pass both .Address and .Port to join? This is just a trivial example, and I'm not using indexes intentionally since the number of services could be more than two. Any ideas?
This should work.
{{$foo_srv := service "foo"}}
{{if $foo_srv}}
{{$last := len $foo_srv | subtract 1}}
servers=
{{- range $i := loop $last}}
{{- with index $foo_srv $i}}{{.Address}}{{.Port}},{{end}}
{{- end}}
{{- with index $foo_srv last}}{{.Address}}{{.Port}}{{end}}/bogus
{{end}}
I was thinking if "join" can be used.
Note "{{-" means removing leading white spaces (such ' ', \t, \n).
You can use a custom plugin.
servers={{service "foo" | toJSON | plugin "path/to/plugin"}}
The plugin code:
package main
import (
"encoding/json"
"fmt"
"os"
)
type InputEntry struct {
Node string
Address string
Port int
}
func main() {
arg := []byte(os.Args[1])
var input []InputEntry
if err := json.Unmarshal(arg, &input); err != nil {
fmt.Fprintln(os.Stderr, fmt.Sprintf("err: %s", err))
os.Exit(1)
}
var output string
for i, entry := range input {
output += fmt.Sprintf("%v:%v", entry.Address, entry.Port)
if i != len(input)-1 {
output += ","
}
}
fmt.Fprintln(os.Stdout, string(output))
os.Exit(0)
}