Skip to content

Commit 97c8358

Browse files
Add input/output flags and goreleaser config
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 774c520 commit 97c8358

15 files changed

Lines changed: 349 additions & 80 deletions

File tree

.github/workflows/release.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Generated by github.com/arran4/go-subcommand/cmd/gosubc
2+
name: Release
3+
4+
permissions:
5+
contents: write
6+
7+
on:
8+
push:
9+
tags:
10+
- 'v*'
11+
12+
jobs:
13+
goreleaser:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: stable
24+
- name: Login to GHCR
25+
uses: docker/login-action@v3
26+
with:
27+
registry: ghcr.io
28+
username: ${{ github.repository_owner }}
29+
password: ${{ secrets.GITHUB_TOKEN }}
30+
- name: Run GoReleaser
31+
uses: goreleaser/goreleaser-action@v5
32+
with:
33+
distribution: goreleaser
34+
version: latest
35+
args: release --clean
36+
env:
37+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.goreleaser.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Generated by github.com/arran4/go-subcommand/cmd/gosubc
2+
# .goreleaser.yml
3+
4+
before:
5+
hooks:
6+
- go mod tidy
7+
8+
builds:
9+
- id: strings2
10+
main: ./cmd/strings2
11+
binary: strings2
12+
env:
13+
- CGO_ENABLED=0
14+
goos:
15+
- linux
16+
- windows
17+
- darwin
18+
goarch:
19+
- amd64
20+
- arm64
21+
22+
archives:
23+
- format: tar.gz
24+
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
25+
files:
26+
- LICENSE
27+
- README.md
28+
29+
checksum:
30+
name_template: 'checksums.txt'
31+
32+
snapshot:
33+
name_template: "{{ .Tag }}-next"
34+
35+
changelog:
36+
sort: asc
37+
filters:
38+
exclude:
39+
- '^docs:'
40+
- '^test:'

cli/main.go

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,99 @@ package cli
22

33
import (
44
"fmt"
5+
"io"
56
"os"
7+
"strings"
68

79
"github.com/arran4/strings2"
810
)
911

12+
func process(input string, output string, args []string, fn func(string, ...any) (string, error)) {
13+
var in io.Reader
14+
if input == "-" {
15+
in = os.Stdin
16+
} else if input != "" {
17+
f, err := os.Open(input)
18+
if err != nil {
19+
fmt.Fprintf(os.Stderr, "Error opening input file: %v\n", err)
20+
os.Exit(1)
21+
}
22+
defer f.Close()
23+
in = f
24+
} else if len(args) > 0 {
25+
in = strings.NewReader(strings.Join(args, " "))
26+
} else {
27+
in = os.Stdin
28+
}
29+
30+
b, err := io.ReadAll(in)
31+
if err != nil {
32+
fmt.Fprintf(os.Stderr, "Error reading input: %v\n", err)
33+
os.Exit(1)
34+
}
35+
36+
res, err := fn(string(b))
37+
if err != nil {
38+
fmt.Fprintf(os.Stderr, "Error processing: %v\n", err)
39+
os.Exit(1)
40+
}
41+
42+
var out io.Writer
43+
if output == "-" || output == "" {
44+
out = os.Stdout
45+
} else {
46+
f, err := os.Create(output)
47+
if err != nil {
48+
fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
49+
os.Exit(1)
50+
}
51+
defer f.Close()
52+
out = f
53+
}
54+
55+
fmt.Fprintln(out, res)
56+
}
57+
1058
// Camel is a subcommand `strings2 camel`
1159
//
1260
// Flags:
1361
//
14-
// input: @1 Input string
15-
func Camel(input string) {
16-
res, err := strings2.ToCamel(input)
17-
if err != nil {
18-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
19-
os.Exit(1)
20-
}
21-
fmt.Println(res)
62+
// input: -i --input (default: "") Input file or - for stdin
63+
// output: -o --output (default: "") Output file or - for stdout
64+
// args: ... Positional arguments
65+
func Camel(input string, output string, args ...string) {
66+
process(input, output, args, strings2.ToCamel)
2267
}
2368

2469
// Snake is a subcommand `strings2 snake`
2570
//
2671
// Flags:
2772
//
28-
// input: @1 Input string
29-
func Snake(input string) {
30-
res, err := strings2.ToSnake(input)
31-
if err != nil {
32-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
33-
os.Exit(1)
34-
}
35-
fmt.Println(res)
73+
// input: -i --input (default: "") Input file or - for stdin
74+
// output: -o --output (default: "") Output file or - for stdout
75+
// args: ... Positional arguments
76+
func Snake(input string, output string, args ...string) {
77+
process(input, output, args, strings2.ToSnake)
3678
}
3779

3880
// Kebab is a subcommand `strings2 kebab`
3981
//
4082
// Flags:
4183
//
42-
// input: @1 Input string
43-
func Kebab(input string) {
44-
res, err := strings2.ToKebab(input)
45-
if err != nil {
46-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
47-
os.Exit(1)
48-
}
49-
fmt.Println(res)
84+
// input: -i --input (default: "") Input file or - for stdin
85+
// output: -o --output (default: "") Output file or - for stdout
86+
// args: ... Positional arguments
87+
func Kebab(input string, output string, args ...string) {
88+
process(input, output, args, strings2.ToKebab)
5089
}
5190

5291
// Pascal is a subcommand `strings2 pascal`
5392
//
5493
// Flags:
5594
//
56-
// input: @1 Input string
57-
func Pascal(input string) {
58-
res, err := strings2.ToPascal(input)
59-
if err != nil {
60-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
61-
os.Exit(1)
62-
}
63-
fmt.Println(res)
95+
// input: -i --input (default: "") Input file or - for stdin
96+
// output: -o --output (default: "") Output file or - for stdout
97+
// args: ... Positional arguments
98+
func Pascal(input string, output string, args ...string) {
99+
process(input, output, args, strings2.ToPascal)
64100
}

cmd/strings2/camel.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ type Camel struct {
1717
*RootCmd
1818
Flags *flag.FlagSet
1919
input string
20+
output string
21+
args []string
2022
SubCommands map[string]Cmd
2123
CommandAction func(c *Camel) error
2224
}
@@ -55,8 +57,38 @@ func (c *Camel) Execute(args []string) error {
5557
}
5658
if strings.HasPrefix(arg, "-") && arg != "-" {
5759
name := arg
60+
value := ""
61+
hasValue := false
62+
if strings.Contains(arg, "=") {
63+
parts := strings.SplitN(arg, "=", 2)
64+
name = parts[0]
65+
value = parts[1]
66+
hasValue = true
67+
}
5868
trimmedName := strings.TrimLeft(name, "-")
5969
switch trimmedName {
70+
71+
case "input", "i":
72+
if !hasValue {
73+
if i+1 < len(args) {
74+
value = args[i+1]
75+
i++
76+
} else {
77+
return fmt.Errorf("flag %s requires a value", name)
78+
}
79+
}
80+
c.input = value
81+
82+
case "output", "o":
83+
if !hasValue {
84+
if i+1 < len(args) {
85+
value = args[i+1]
86+
i++
87+
} else {
88+
return fmt.Errorf("flag %s requires a value", name)
89+
}
90+
}
91+
c.output = value
6092
case "help", "h":
6193
c.Usage()
6294
return nil
@@ -67,16 +99,14 @@ func (c *Camel) Execute(args []string) error {
6799
remainingArgs = append(remainingArgs, arg)
68100
}
69101
}
70-
if len(remainingArgs) < 1 {
71-
return fmt.Errorf("expected at least 1 positional arguments, got %d", len(remainingArgs))
72-
}
73-
// Handle positional argument input
102+
// Handle vararg args
74103
{
75-
argIndex := 0
76-
if argIndex >= 0 && argIndex < len(remainingArgs) {
77-
argVal := remainingArgs[argIndex]
78-
c.input = argVal
104+
varArgStart := 0
105+
if varArgStart > len(remainingArgs) {
106+
varArgStart = len(remainingArgs)
79107
}
108+
varArgs := remainingArgs[varArgStart:]
109+
c.args = varArgs
80110
}
81111

82112
if c.CommandAction != nil {
@@ -97,11 +127,17 @@ func (c *RootCmd) NewCamel() *Camel {
97127
Flags: set,
98128
SubCommands: make(map[string]Cmd),
99129
}
130+
131+
set.StringVar(&v.input, "input", "", "Input file or - for stdin")
132+
set.StringVar(&v.input, "i", "", "Input file or - for stdin")
133+
134+
set.StringVar(&v.output, "output", "", "Output file or - for stdout")
135+
set.StringVar(&v.output, "o", "", "Output file or - for stdout")
100136
set.Usage = v.Usage
101137

102138
v.CommandAction = func(c *Camel) error {
103139

104-
cli.Camel(c.input)
140+
cli.Camel(c.input, c.output, c.args...)
105141
return nil
106142
}
107143

cmd/strings2/camel_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ func TestCamel_Execute(t *testing.T) {
2222
}
2323

2424
args := []string{}
25-
args = append(args, "test")
2625

2726
err := cmd.Execute(args)
2827
if err != nil {

cmd/strings2/kebab.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ type Kebab struct {
1717
*RootCmd
1818
Flags *flag.FlagSet
1919
input string
20+
output string
21+
args []string
2022
SubCommands map[string]Cmd
2123
CommandAction func(c *Kebab) error
2224
}
@@ -55,8 +57,38 @@ func (c *Kebab) Execute(args []string) error {
5557
}
5658
if strings.HasPrefix(arg, "-") && arg != "-" {
5759
name := arg
60+
value := ""
61+
hasValue := false
62+
if strings.Contains(arg, "=") {
63+
parts := strings.SplitN(arg, "=", 2)
64+
name = parts[0]
65+
value = parts[1]
66+
hasValue = true
67+
}
5868
trimmedName := strings.TrimLeft(name, "-")
5969
switch trimmedName {
70+
71+
case "input", "i":
72+
if !hasValue {
73+
if i+1 < len(args) {
74+
value = args[i+1]
75+
i++
76+
} else {
77+
return fmt.Errorf("flag %s requires a value", name)
78+
}
79+
}
80+
c.input = value
81+
82+
case "output", "o":
83+
if !hasValue {
84+
if i+1 < len(args) {
85+
value = args[i+1]
86+
i++
87+
} else {
88+
return fmt.Errorf("flag %s requires a value", name)
89+
}
90+
}
91+
c.output = value
6092
case "help", "h":
6193
c.Usage()
6294
return nil
@@ -67,16 +99,14 @@ func (c *Kebab) Execute(args []string) error {
6799
remainingArgs = append(remainingArgs, arg)
68100
}
69101
}
70-
if len(remainingArgs) < 1 {
71-
return fmt.Errorf("expected at least 1 positional arguments, got %d", len(remainingArgs))
72-
}
73-
// Handle positional argument input
102+
// Handle vararg args
74103
{
75-
argIndex := 0
76-
if argIndex >= 0 && argIndex < len(remainingArgs) {
77-
argVal := remainingArgs[argIndex]
78-
c.input = argVal
104+
varArgStart := 0
105+
if varArgStart > len(remainingArgs) {
106+
varArgStart = len(remainingArgs)
79107
}
108+
varArgs := remainingArgs[varArgStart:]
109+
c.args = varArgs
80110
}
81111

82112
if c.CommandAction != nil {
@@ -97,11 +127,17 @@ func (c *RootCmd) NewKebab() *Kebab {
97127
Flags: set,
98128
SubCommands: make(map[string]Cmd),
99129
}
130+
131+
set.StringVar(&v.input, "input", "", "Input file or - for stdin")
132+
set.StringVar(&v.input, "i", "", "Input file or - for stdin")
133+
134+
set.StringVar(&v.output, "output", "", "Output file or - for stdout")
135+
set.StringVar(&v.output, "o", "", "Output file or - for stdout")
100136
set.Usage = v.Usage
101137

102138
v.CommandAction = func(c *Kebab) error {
103139

104-
cli.Kebab(c.input)
140+
cli.Kebab(c.input, c.output, c.args...)
105141
return nil
106142
}
107143

0 commit comments

Comments
 (0)