Skip to content

Commit

Permalink
Add subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
akiomik committed Aug 14, 2022
1 parent 6fa526e commit c86acaf
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 208 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ A cli tool to get old tweets on twitter (inspired by [Jefferson-Henrique/GetOldT

## Usage

### Search for tweets

```
Usage:
squawks --out FILENAME [flags]
squawks search tweets --out FILENAME [flags]
Flags:
--exclude strings exclude tweets by type of tweet [hashtags|nativeretweets|retweets|replies] (default [])
--filter strings find tweets by type of account or tweet [verified|follows|media|images|twimg|videos|periscope|vine|consumer_video|pro_video|native_video|links|hashtags|nativeretweets|retweets|replies|safe|news] (default [])
--from string find tweets sent from a certain user
--geocode string find tweets sent from certain coordinates (e.g. 35.6851508,139.7526768,0.1km)
-h, --help help for squawks
-h, --help help for tweets
--include strings include tweets by type of tweet [hashtags|nativeretweets|retweets|replies] (default [])
--lang string find tweets by a certain language (e.g. en, es, fr)
--near string find tweets nearby a certain location (e.g. tokyo)
Expand All @@ -38,7 +40,6 @@ Flags:
--until string find tweets until a certain day (e.g. 2020-09-06)
--url string find tweets containing a certain url (e.g. www.example.com)
--user-agent string set custom user-agent
-v, --version version for squawks
--within string find tweets nearby a certain location (e.g. 1km)
```

Expand Down
2 changes: 1 addition & 1 deletion api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ package api
import (
"github.com/go-resty/resty/v2"

"github.com/akiomik/squawks/config"
"github.com/akiomik/squawks/api/json"
"github.com/akiomik/squawks/config"
)

type Client struct {
Expand Down
35 changes: 35 additions & 0 deletions cmd/flags/enum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2022 Akiomi Kamakura
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flags

import (
"fmt"
"strings"

"github.com/spf13/pflag"
)

func StringSliceEnumVarP(flags *pflag.FlagSet, p *[]string, name string, shorthand string, defaults []string, usage string, options []string) *pflag.Flag {
formattedOptions := "[" + strings.Join(options[:], "|") + "]"
validator := func(values []string) error {
if All(values, func(value string) bool { return Includes(options, value) }) {
return nil
}

return fmt.Errorf(`valid values are %s`, formattedOptions)
}

return StringSliceWithValidationVarP(flags, p, name, shorthand, defaults, usage+" "+formattedOptions, validator)
}
104 changes: 104 additions & 0 deletions cmd/flags/enum_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2022 Akiomi Kamakura
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flags

import (
"reflect"
"testing"

"github.com/spf13/pflag"
)

func TestStringSliceEnumVarP(t *testing.T) {
examples := map[string]struct {
input []string
expected []string
error string
}{
"none": {
input: []string{},
expected: []string{},
error: "",
},
"empty": {
input: []string{"--arg="},
expected: []string{},
error: "",
},
"valid-single": {
input: []string{"--arg=foo"},
expected: []string{"foo"},
error: "",
},
"invalid-single": {
input: []string{"--arg=bar"},
expected: []string{},
error: `invalid argument "bar" for "--arg" flag: valid values are [foo|foobar]`,
},
"valid-multiple-flags": {
input: []string{"--arg=foo", "--arg=foobar"},
expected: []string{"foo|foobar"},
error: "",
},
"invalid-multiple-flags": {
input: []string{"--arg=foo", "--arg=bar"},
expected: []string{"foo"},
error: `invalid argument "bar" for "--arg" flag: valid values are [foo|foobar]`,
},
"valid-multiple-values": {
input: []string{"--arg=foo,foobar"},
expected: []string{"foo|foobar"},
error: "",
},
"invalid-multiple-values": {
input: []string{"--arg=foo,bar"},
expected: []string{},
error: `invalid argument "foo,bar" for "--arg" flag: valid values are [foo|foobar]`,
},
}

for name, e := range examples {
t.Run(name, func(t *testing.T) {
var args []string

flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
StringSliceEnumVarP(flags, &args, "arg", "", []string{}, "args for testing", []string{"foo", "foobar"})
err := flags.Parse(e.input)

if err == nil {
if e.error != "" {
t.Errorf(`Expect error %v, got nil`, e.error)
return
}
} else {
if e.error != err.Error() {
t.Errorf(`Expect "%s", got "%v"`, e.error, err)
return
}
}

actual, err := flags.GetStringSlice("arg")
if err != nil {
t.Errorf(`Expect no error, got "%v"`, err)
return
}

if !reflect.DeepEqual(actual, e.expected) {
t.Errorf("Expect %v, got %v", e.expected, actual)
return
}
})
}
}
2 changes: 1 addition & 1 deletion cmd/helper.go → cmd/flags/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd
package flags

func All[T any](xs []T, f func(x T) bool) bool {
for _, x := range xs {
Expand Down
2 changes: 1 addition & 1 deletion cmd/helper_test.go → cmd/flags/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd
package flags

import (
"strings"
Expand Down
16 changes: 1 addition & 15 deletions cmd/flag.go → cmd/flags/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd
package flags

import (
"encoding/csv"
"fmt"
"strings"

"github.com/spf13/pflag"
)

func StringSliceEnumVarP(flags *pflag.FlagSet, p *[]string, name string, shorthand string, defaults []string, usage string, options []string) *pflag.Flag {
formattedOptions := "[" + strings.Join(options[:], "|") + "]"
validator := func(values []string) error {
if All(values, func(value string) bool { return Includes(options, value) }) {
return nil
}

return fmt.Errorf(`valid values are %s`, formattedOptions)
}

return StringSliceWithValidationVarP(flags, p, name, shorthand, defaults, usage+" "+formattedOptions, validator)
}

func StringSliceWithValidationVarP(flags *pflag.FlagSet, p *[]string, name string, shorthand string, defaults []string, usage string, validator func([]string) error) *pflag.Flag {
*p = defaults
v := &StringSliceValueWithValidation{Values: p, Validator: validator}
Expand Down
84 changes: 1 addition & 83 deletions cmd/flag_test.go → cmd/flags/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd
package flags

import (
"fmt"
Expand Down Expand Up @@ -113,85 +113,3 @@ func TestStringSliceWithValidationVarP(t *testing.T) {
})
}
}

func TestStringSliceEnumVarP(t *testing.T) {
examples := map[string]struct {
input []string
expected []string
error string
}{
"none": {
input: []string{},
expected: []string{},
error: "",
},
"empty": {
input: []string{"--arg="},
expected: []string{},
error: "",
},
"valid-single": {
input: []string{"--arg=foo"},
expected: []string{"foo"},
error: "",
},
"invalid-single": {
input: []string{"--arg=bar"},
expected: []string{},
error: `invalid argument "bar" for "--arg" flag: valid values are [foo|foobar]`,
},
"valid-multiple-flags": {
input: []string{"--arg=foo", "--arg=foobar"},
expected: []string{"foo|foobar"},
error: "",
},
"invalid-multiple-flags": {
input: []string{"--arg=foo", "--arg=bar"},
expected: []string{"foo"},
error: `invalid argument "bar" for "--arg" flag: valid values are [foo|foobar]`,
},
"valid-multiple-values": {
input: []string{"--arg=foo,foobar"},
expected: []string{"foo|foobar"},
error: "",
},
"invalid-multiple-values": {
input: []string{"--arg=foo,bar"},
expected: []string{},
error: `invalid argument "foo,bar" for "--arg" flag: valid values are [foo|foobar]`,
},
}

for name, e := range examples {
t.Run(name, func(t *testing.T) {
var args []string

flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
StringSliceEnumVarP(flags, &args, "arg", "", []string{}, "args for testing", []string{"foo", "foobar"})
err := flags.Parse(e.input)

if err == nil {
if e.error != "" {
t.Errorf(`Expect error %v, got nil`, e.error)
return
}
} else {
if e.error != err.Error() {
t.Errorf(`Expect "%s", got "%v"`, e.error, err)
return
}
}

actual, err := flags.GetStringSlice("arg")
if err != nil {
t.Errorf(`Expect no error, got "%v"`, err)
return
}

if !reflect.DeepEqual(actual, e.expected) {
t.Errorf("Expect %v, got %v", e.expected, actual)
return
}
})
}
}
Loading

0 comments on commit c86acaf

Please sign in to comment.