From 33dc54002be2707f7415172cbc97f45c93f6d051 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:53:17 +0900 Subject: [PATCH 01/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20uncommitted?= =?UTF-8?q?Changes=20to=20UncommittedChanges,=20untrackedFiles=20to=20Untr?= =?UTF-8?q?ackedFiles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- add.go | 4 ++-- diff.go | 4 ++-- guard.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/add.go b/add.go index fee2af6..9dc7612 100644 --- a/add.go +++ b/add.go @@ -6,11 +6,11 @@ import ( ) func add() error { - uncommittedChanges, err := uncommittedChanges() + uncommittedChanges, err := UncommittedChanges() if err != nil { return fmt.Errorf("git diff failed: %+v", err) } - untrackedFiles, err := untrackedFiles() + untrackedFiles, err := UntrackedFiles() if err != nil { return fmt.Errorf("git ls-files failed: %+v", err) } diff --git a/diff.go b/diff.go index e7cf36b..4ffd62f 100644 --- a/diff.go +++ b/diff.go @@ -5,7 +5,7 @@ import ( "os/exec" ) -func uncommittedChanges() (string, error) { +func UncommittedChanges() (string, error) { output, err := exec.Command("git", "diff").CombinedOutput() if err != nil { return "", err @@ -13,7 +13,7 @@ func uncommittedChanges() (string, error) { return string(bytes.TrimSpace(output)), nil } -func untrackedFiles() (string, error) { +func UntrackedFiles() (string, error) { cmd := exec.Command("git", "ls-files", "--others", "--exclude-standard") output, err := cmd.Output() if err != nil { diff --git a/guard.go b/guard.go index c756b80..a1093a8 100644 --- a/guard.go +++ b/guard.go @@ -38,12 +38,12 @@ func (g *guardResult) Format() string { } func guard(opts *Options) (*guardResult, error) { - diff, err := uncommittedChanges() + diff, err := UncommittedChanges() if err != nil { return nil, err } - untrackedFiles, err := untrackedFiles() + untrackedFiles, err := UntrackedFiles() if err != nil { return nil, err } From f9e6291ef0978add3ec63cc7594c9db219e1a99f Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:55:17 +0900 Subject: [PATCH 02/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20UncommittedCh?= =?UTF-8?q?anges=20and=20UntrackedFiles=20to=20git=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- add.go | 6 ++++-- diff.go => git/diff.go | 2 +- guard.go | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) rename diff.go => git/diff.go (97%) diff --git a/add.go b/add.go index 9dc7612..92f5d5f 100644 --- a/add.go +++ b/add.go @@ -3,14 +3,16 @@ package main import ( "fmt" "os/exec" + + "github.com/akm/git-exec/git" ) func add() error { - uncommittedChanges, err := UncommittedChanges() + uncommittedChanges, err := git.UncommittedChanges() if err != nil { return fmt.Errorf("git diff failed: %+v", err) } - untrackedFiles, err := UntrackedFiles() + untrackedFiles, err := git.UntrackedFiles() if err != nil { return fmt.Errorf("git ls-files failed: %+v", err) } diff --git a/diff.go b/git/diff.go similarity index 97% rename from diff.go rename to git/diff.go index 4ffd62f..8865aad 100644 --- a/diff.go +++ b/git/diff.go @@ -1,4 +1,4 @@ -package main +package git import ( "bytes" diff --git a/guard.go b/guard.go index a1093a8..4ae2e4d 100644 --- a/guard.go +++ b/guard.go @@ -3,6 +3,8 @@ package main import ( "fmt" "strings" + + "github.com/akm/git-exec/git" ) type guardResult struct { @@ -38,12 +40,12 @@ func (g *guardResult) Format() string { } func guard(opts *Options) (*guardResult, error) { - diff, err := UncommittedChanges() + diff, err := git.UncommittedChanges() if err != nil { return nil, err } - untrackedFiles, err := UntrackedFiles() + untrackedFiles, err := git.UntrackedFiles() if err != nil { return nil, err } From d6cefd66f90da8e75f9ae85d57839c7fa1b284d6 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:55:45 +0900 Subject: [PATCH 03/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20add=20to=20?= =?UTF-8?q?Add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- add.go | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/add.go b/add.go index 92f5d5f..aa1d674 100644 --- a/add.go +++ b/add.go @@ -7,7 +7,7 @@ import ( "github.com/akm/git-exec/git" ) -func add() error { +func Add() error { uncommittedChanges, err := git.UncommittedChanges() if err != nil { return fmt.Errorf("git diff failed: %+v", err) diff --git a/main.go b/main.go index 8f7ff9f..789d77b 100644 --- a/main.go +++ b/main.go @@ -68,7 +68,7 @@ func process(options *Options, commandArgs []string) error { return err } - if err := add(); err != nil { + if err := Add(); err != nil { return err } From c02323ed4c7b3b0da7736d5a223bb7ae236db1f5 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:56:38 +0900 Subject: [PATCH 04/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20Add=20to=20gi?= =?UTF-8?q?t=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- add.go => git/add.go | 8 +++----- main.go | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) rename add.go => git/add.go (76%) diff --git a/add.go b/git/add.go similarity index 76% rename from add.go rename to git/add.go index aa1d674..6b3df27 100644 --- a/add.go +++ b/git/add.go @@ -1,18 +1,16 @@ -package main +package git import ( "fmt" "os/exec" - - "github.com/akm/git-exec/git" ) func Add() error { - uncommittedChanges, err := git.UncommittedChanges() + uncommittedChanges, err := UncommittedChanges() if err != nil { return fmt.Errorf("git diff failed: %+v", err) } - untrackedFiles, err := git.UntrackedFiles() + untrackedFiles, err := UntrackedFiles() if err != nil { return fmt.Errorf("git ls-files failed: %+v", err) } diff --git a/main.go b/main.go index 789d77b..77702bf 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,8 @@ import ( "log/slog" "os" "path/filepath" + + "github.com/akm/git-exec/git" ) func main() { @@ -68,7 +70,7 @@ func process(options *Options, commandArgs []string) error { return err } - if err := Add(); err != nil { + if err := git.Add(); err != nil { return err } From 5ce66f4b453185921f610856e890864dec75426e Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:57:22 +0900 Subject: [PATCH 05/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20guard=20to?= =?UTF-8?q?=20Guard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guard.go | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guard.go b/guard.go index 4ae2e4d..685a3a2 100644 --- a/guard.go +++ b/guard.go @@ -39,7 +39,7 @@ func (g *guardResult) Format() string { return strings.Join(parts, "\n\n") } -func guard(opts *Options) (*guardResult, error) { +func Guard(opts *Options) (*guardResult, error) { diff, err := git.UncommittedChanges() if err != nil { return nil, err diff --git a/main.go b/main.go index 77702bf..6033bd1 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ func main() { func process(options *Options, commandArgs []string) error { var guardMessage string - if guardResult, err := guard(options); err != nil { + if guardResult, err := Guard(options); err != nil { return err } else if guardResult != nil { if guardResult.skipped { From 6b6ffda4be07417a2b28fd9cd3ee9a79d3a3e108 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 18:59:18 +0900 Subject: [PATCH 06/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20guardResult?= =?UTF-8?q?=20to=20GuardResult?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guard.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/guard.go b/guard.go index 685a3a2..ee20aed 100644 --- a/guard.go +++ b/guard.go @@ -7,13 +7,13 @@ import ( "github.com/akm/git-exec/git" ) -type guardResult struct { +type GuardResult struct { uncommittedChanges string untrackedFiles string skipped bool } -func (g *guardResult) Message() string { +func (g *GuardResult) Message() string { var r string if len(g.uncommittedChanges) > 0 && len(g.untrackedFiles) > 0 { r = "There are uncommitted changes and untracked files" @@ -28,7 +28,7 @@ func (g *guardResult) Message() string { return r } -func (g *guardResult) Format() string { +func (g *GuardResult) Format() string { parts := []string{g.Message()} if len(g.uncommittedChanges) > 0 { parts = append(parts, fmt.Sprintf("Uncommitted changes:\n%s", g.uncommittedChanges)) @@ -39,7 +39,7 @@ func (g *guardResult) Format() string { return strings.Join(parts, "\n\n") } -func Guard(opts *Options) (*guardResult, error) { +func Guard(opts *Options) (*GuardResult, error) { diff, err := git.UncommittedChanges() if err != nil { return nil, err @@ -54,7 +54,7 @@ func Guard(opts *Options) (*guardResult, error) { return nil, nil } - return &guardResult{ + return &GuardResult{ uncommittedChanges: diff, untrackedFiles: untrackedFiles, skipped: opts.SkipGuard || From ac30c497efa1285f046675b9639068a67eb8576c Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 19:03:09 +0900 Subject: [PATCH 07/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20GuardOptio?= =?UTF-8?q?ns=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guard.go | 8 +++++++- main.go | 2 +- options.go | 4 +--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/guard.go b/guard.go index ee20aed..36f8f86 100644 --- a/guard.go +++ b/guard.go @@ -39,7 +39,13 @@ func (g *GuardResult) Format() string { return strings.Join(parts, "\n\n") } -func Guard(opts *Options) (*GuardResult, error) { +type GuardOptions struct { + SkipGuard bool + SkipGuardUncommittedChanges bool + SkipGuardUntrackedFiles bool +} + +func Guard(opts *GuardOptions) (*GuardResult, error) { diff, err := git.UncommittedChanges() if err != nil { return nil, err diff --git a/main.go b/main.go index 6033bd1..49cc76a 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ func main() { func process(options *Options, commandArgs []string) error { var guardMessage string - if guardResult, err := Guard(options); err != nil { + if guardResult, err := Guard(&options.GuardOptions); err != nil { return err } else if guardResult != nil { if guardResult.skipped { diff --git a/options.go b/options.go index 63b47ad..5b869f2 100644 --- a/options.go +++ b/options.go @@ -14,9 +14,7 @@ type Options struct { Prompt string Template string - SkipGuard bool - SkipGuardUncommittedChanges bool - SkipGuardUntrackedFiles bool + GuardOptions DebugLog bool Interactive bool From e623d5dc9b4e154ebdc51148fb2317b2447b9c00 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 19:05:26 +0900 Subject: [PATCH 08/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Capitalize=20GuardRe?= =?UTF-8?q?sult=20field=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guard.go | 26 +++++++++++++------------- main.go | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/guard.go b/guard.go index 36f8f86..fbec88d 100644 --- a/guard.go +++ b/guard.go @@ -8,21 +8,21 @@ import ( ) type GuardResult struct { - uncommittedChanges string - untrackedFiles string - skipped bool + UncommittedChanges string + UntrackedFiles string + Skipped bool } func (g *GuardResult) Message() string { var r string - if len(g.uncommittedChanges) > 0 && len(g.untrackedFiles) > 0 { + if len(g.UncommittedChanges) > 0 && len(g.UntrackedFiles) > 0 { r = "There are uncommitted changes and untracked files" - } else if len(g.untrackedFiles) > 0 { + } else if len(g.UntrackedFiles) > 0 { r = "There are untracked files" } else { r = "There are uncommitted changes" } - if g.skipped { + if g.Skipped { r += " but guard was skipped by options" } return r @@ -30,11 +30,11 @@ func (g *GuardResult) Message() string { func (g *GuardResult) Format() string { parts := []string{g.Message()} - if len(g.uncommittedChanges) > 0 { - parts = append(parts, fmt.Sprintf("Uncommitted changes:\n%s", g.uncommittedChanges)) + if len(g.UncommittedChanges) > 0 { + parts = append(parts, fmt.Sprintf("Uncommitted changes:\n%s", g.UncommittedChanges)) } - if len(g.untrackedFiles) > 0 { - parts = append(parts, fmt.Sprintf("Untracked files:\n%s", g.untrackedFiles)) + if len(g.UntrackedFiles) > 0 { + parts = append(parts, fmt.Sprintf("Untracked files:\n%s", g.UntrackedFiles)) } return strings.Join(parts, "\n\n") } @@ -61,9 +61,9 @@ func Guard(opts *GuardOptions) (*GuardResult, error) { } return &GuardResult{ - uncommittedChanges: diff, - untrackedFiles: untrackedFiles, - skipped: opts.SkipGuard || + UncommittedChanges: diff, + UntrackedFiles: untrackedFiles, + Skipped: opts.SkipGuard || (opts.SkipGuardUncommittedChanges && len(diff) > 0) || (opts.SkipGuardUntrackedFiles && len(untrackedFiles) > 0), }, nil diff --git a/main.go b/main.go index 49cc76a..c44f687 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,7 @@ func process(options *Options, commandArgs []string) error { if guardResult, err := Guard(&options.GuardOptions); err != nil { return err } else if guardResult != nil { - if guardResult.skipped { + if guardResult.Skipped { guardMessage = guardResult.Format() fmt.Fprintf(os.Stderr, "Guard skipped: %s\n", guardMessage) } else { From 77fb5fc808644da7284f46ef2cbc01393a0ed4b7 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 19:06:30 +0900 Subject: [PATCH 09/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20guard.go=20to?= =?UTF-8?q?=20git=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guard.go => git/guard.go | 8 +++----- main.go | 2 +- options.go | 4 +++- 3 files changed, 7 insertions(+), 7 deletions(-) rename guard.go => git/guard.go (91%) diff --git a/guard.go b/git/guard.go similarity index 91% rename from guard.go rename to git/guard.go index fbec88d..f66f6e6 100644 --- a/guard.go +++ b/git/guard.go @@ -1,10 +1,8 @@ -package main +package git import ( "fmt" "strings" - - "github.com/akm/git-exec/git" ) type GuardResult struct { @@ -46,12 +44,12 @@ type GuardOptions struct { } func Guard(opts *GuardOptions) (*GuardResult, error) { - diff, err := git.UncommittedChanges() + diff, err := UncommittedChanges() if err != nil { return nil, err } - untrackedFiles, err := git.UntrackedFiles() + untrackedFiles, err := UntrackedFiles() if err != nil { return nil, err } diff --git a/main.go b/main.go index c44f687..00c670c 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ func main() { func process(options *Options, commandArgs []string) error { var guardMessage string - if guardResult, err := Guard(&options.GuardOptions); err != nil { + if guardResult, err := git.Guard(&options.GuardOptions); err != nil { return err } else if guardResult != nil { if guardResult.Skipped { diff --git a/options.go b/options.go index 5b869f2..08b26e8 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "strings" + + "github.com/akm/git-exec/git" ) type Options struct { @@ -14,7 +16,7 @@ type Options struct { Prompt string Template string - GuardOptions + git.GuardOptions DebugLog bool Interactive bool From 040f3c3c4c201d374f75b549f93f2d77f74297b4 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 19:07:17 +0900 Subject: [PATCH 10/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20commit=20to?= =?UTF-8?q?=20Commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commit.go | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commit.go b/commit.go index 21116ce..e4bb53c 100644 --- a/commit.go +++ b/commit.go @@ -6,7 +6,7 @@ import ( "os/exec" ) -func commit(commitMessage *commitMessage) error { +func Commit(commitMessage *commitMessage) error { // 3. "git commit" を以下のオプションと標準力を指定して実行する。 msg, err := commitMessage.Build() if err != nil { diff --git a/main.go b/main.go index 00c670c..293bd16 100644 --- a/main.go +++ b/main.go @@ -78,7 +78,7 @@ func process(options *Options, commandArgs []string) error { commitMessage.Body = guardMessage + "\n\n" + commitMessage.Body } - if err := commit(commitMessage); err != nil { + if err := Commit(commitMessage); err != nil { return err } From 921f96e1cea4ad75fdc7c6559648beaccf628f9b Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 20:32:04 +0900 Subject: [PATCH 11/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Pass=20message=20str?= =?UTF-8?q?ing=20to=20Commit=20instead=20of=20*commitMessage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commit.go | 8 +------- main.go | 8 +++++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/commit.go b/commit.go index e4bb53c..632506d 100644 --- a/commit.go +++ b/commit.go @@ -6,13 +6,7 @@ import ( "os/exec" ) -func Commit(commitMessage *commitMessage) error { - // 3. "git commit" を以下のオプションと標準力を指定して実行する。 - msg, err := commitMessage.Build() - if err != nil { - return fmt.Errorf("Failed to build commit message: %+v", err) - } - +func Commit(msg string) error { // See https://tracpath.com/docs/git-commit/ commitCmd := exec.Command("git", "commit", "--file", "-") commitCmd.Stdin = bytes.NewBufferString(msg) diff --git a/main.go b/main.go index 293bd16..39cb610 100644 --- a/main.go +++ b/main.go @@ -78,7 +78,13 @@ func process(options *Options, commandArgs []string) error { commitMessage.Body = guardMessage + "\n\n" + commitMessage.Body } - if err := Commit(commitMessage); err != nil { + // 3. "git commit" を以下のオプションと標準力を指定して実行する。 + msg, err := commitMessage.Build() + if err != nil { + return fmt.Errorf("Failed to build commit message: %+v", err) + } + + if err := Commit(msg); err != nil { return err } From 7f2703a8f1dc040da4a2bd37a4d01a5a49fe2ea1 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 20:33:37 +0900 Subject: [PATCH 12/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20commit.go=20t?= =?UTF-8?q?o=20git=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commit.go => git/commit.go | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename commit.go => git/commit.go (96%) diff --git a/commit.go b/git/commit.go similarity index 96% rename from commit.go rename to git/commit.go index 632506d..5db742f 100644 --- a/commit.go +++ b/git/commit.go @@ -1,4 +1,4 @@ -package main +package git import ( "bytes" diff --git a/main.go b/main.go index 39cb610..65bbe37 100644 --- a/main.go +++ b/main.go @@ -84,7 +84,7 @@ func process(options *Options, commandArgs []string) error { return fmt.Errorf("Failed to build commit message: %+v", err) } - if err := Commit(msg); err != nil { + if err := git.Commit(msg); err != nil { return err } From 1a8ac7011770f4fd43c2d995a3468257b4549366 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 20:37:10 +0900 Subject: [PATCH 13/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Inline=20splitString?= =?UTF-8?q?sInto2=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- args.go | 13 ------------- command.go | 11 ++++++----- 2 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 args.go diff --git a/args.go b/args.go deleted file mode 100644 index db7de32..0000000 --- a/args.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -func splitStringsInto2(args []string, fn func(string) bool) ([]string, []string) { - var a, b []string - for _, arg := range args { - if fn(arg) { - a = append(a, arg) - } else { - b = append(b, arg) - } - } - return a, b -} diff --git a/command.go b/command.go index bef1834..e7831ed 100644 --- a/command.go +++ b/command.go @@ -20,12 +20,13 @@ func newCommand(args []string) *Command { func splitArgsToEnvsAndCommand(args []string) ([]string, []string) { equalNotFound := false - return splitStringsInto2(args, func(arg string) bool { + var a, b []string + for _, arg := range args { if !equalNotFound && strings.Contains(arg, "=") { - return true + a = append(a, arg) } else { - equalNotFound = true - return false + b = append(b, arg) } - }) + } + return a, b } From 1319bb45fb2c07cac4cc090e6b571332db7afe69 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 20:48:28 +0900 Subject: [PATCH 14/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20command.go=20?= =?UTF-8?q?to=20command=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command.go => command/command.go | 4 ++-- command_test.go => command/command_test.go | 2 +- commit_message.go | 4 +++- commit_message_test.go | 4 +++- main.go | 3 ++- runner.go | 6 +++++- standard_runner.go | 4 +++- tmux_runner.go | 4 +++- 8 files changed, 22 insertions(+), 9 deletions(-) rename command.go => command/command.go (89%) rename command_test.go => command/command_test.go (97%) diff --git a/command.go b/command/command.go similarity index 89% rename from command.go rename to command/command.go index e7831ed..287d33d 100644 --- a/command.go +++ b/command/command.go @@ -1,4 +1,4 @@ -package main +package command import ( "strings" @@ -10,7 +10,7 @@ type Command struct { Output string } -func newCommand(args []string) *Command { +func NewCommand(args []string) *Command { envs, commandArgs := splitArgsToEnvsAndCommand(args) return &Command{ Envs: envs, diff --git a/command_test.go b/command/command_test.go similarity index 97% rename from command_test.go rename to command/command_test.go index eb38c62..dc1b682 100644 --- a/command_test.go +++ b/command/command_test.go @@ -1,4 +1,4 @@ -package main +package command import ( "fmt" diff --git a/commit_message.go b/commit_message.go index 1d683cf..bfa1af1 100644 --- a/commit_message.go +++ b/commit_message.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" "text/template" + + "github.com/akm/git-exec/command" ) type commitMessage struct { @@ -17,7 +19,7 @@ type commitMessage struct { Body string } -func newCommitMessage(command *Command, options *Options) *commitMessage { +func newCommitMessage(command *command.Command, options *Options) *commitMessage { argParts := make([]string, len(command.Args)) for i, arg := range command.Args { if strings.Contains(arg, " ") && !(strings.HasPrefix(arg, "'") && strings.HasSuffix(arg, "'")) { diff --git a/commit_message_test.go b/commit_message_test.go index c35d34a..9c15eb3 100644 --- a/commit_message_test.go +++ b/commit_message_test.go @@ -4,6 +4,8 @@ import ( "os" "testing" + "github.com/akm/git-exec/command" + "github.com/stretchr/testify/assert" ) @@ -87,7 +89,7 @@ func TestCommitMessage(t *testing.T) { getLocation, bkGetLocation = func() (string, error) { return ptn.location, nil }, getLocation defer func() { getLocation = bkGetLocation }() - command := &Command{Envs: ptn.envs, Args: ptn.args, Output: ptn.output} + command := &command.Command{Envs: ptn.envs, Args: ptn.args, Output: ptn.output} commitMsg := newCommitMessage(command, newOptions()) actual, err := commitMsg.Build() diff --git a/main.go b/main.go index 65bbe37..1b14c3e 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" + "github.com/akm/git-exec/command" "github.com/akm/git-exec/git" ) @@ -50,7 +51,7 @@ func process(options *Options, commandArgs []string) error { } } - command := newCommand(commandArgs) + command := command.NewCommand(commandArgs) var runner Runner if options.Interactive { runner = newTmuxRunner(options.DebugLog) diff --git a/runner.go b/runner.go index e040d34..55cbe15 100644 --- a/runner.go +++ b/runner.go @@ -1,5 +1,9 @@ package main +import ( + "github.com/akm/git-exec/command" +) + type Runner interface { - Run(c *Command) error + Run(c *command.Command) error } diff --git a/standard_runner.go b/standard_runner.go index 9b027e3..8f38879 100644 --- a/standard_runner.go +++ b/standard_runner.go @@ -5,6 +5,8 @@ import ( "io" "os" "os/exec" + + "github.com/akm/git-exec/command" ) type StandardRunner struct { @@ -19,7 +21,7 @@ func newStandardRunner(debugLog bool) *StandardRunner { } } -func (x *StandardRunner) Run(c *Command) (rerr error) { +func (x *StandardRunner) Run(c *command.Command) (rerr error) { cmd := exec.Command(c.Args[0], c.Args[1:]...) cmd.Env = append(os.Environ(), c.Envs...) cmd.Stdin = os.Stdin diff --git a/tmux_runner.go b/tmux_runner.go index 304c4bc..9c69c1f 100644 --- a/tmux_runner.go +++ b/tmux_runner.go @@ -11,6 +11,8 @@ import ( "regexp" "strings" "time" + + "github.com/akm/git-exec/command" ) type TmuxRunner struct { @@ -37,7 +39,7 @@ func newTmuxRunner(debugLog bool) *TmuxRunner { } } -func (x *TmuxRunner) Run(c *Command) (rerr error) { +func (x *TmuxRunner) Run(c *command.Command) (rerr error) { if _, err := exec.LookPath("tmux"); err != nil { return fmt.Errorf("tmux is not installed. Please install tmux. See https://github.com/tmux/tmux/wiki/Installing") } From 542fa2754073ae0a14352b60093461a861fc9641 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 20:52:40 +0900 Subject: [PATCH 15/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20*runner.go=20?= =?UTF-8?q?to=20command=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- command/runner.go | 5 +++++ standard_runner.go => command/standard_runner.go | 8 +++----- tmux_runner.go => command/tmux_runner.go | 8 +++----- main.go | 14 +++++++------- runner.go | 9 --------- 5 files changed, 18 insertions(+), 26 deletions(-) create mode 100644 command/runner.go rename standard_runner.go => command/standard_runner.go (88%) rename tmux_runner.go => command/tmux_runner.go (96%) delete mode 100644 runner.go diff --git a/command/runner.go b/command/runner.go new file mode 100644 index 0000000..a4b9404 --- /dev/null +++ b/command/runner.go @@ -0,0 +1,5 @@ +package command + +type Runner interface { + Run(c *Command) error +} diff --git a/standard_runner.go b/command/standard_runner.go similarity index 88% rename from standard_runner.go rename to command/standard_runner.go index 8f38879..2b4bd38 100644 --- a/standard_runner.go +++ b/command/standard_runner.go @@ -1,12 +1,10 @@ -package main +package command import ( "bytes" "io" "os" "os/exec" - - "github.com/akm/git-exec/command" ) type StandardRunner struct { @@ -15,13 +13,13 @@ type StandardRunner struct { var _ Runner = (*StandardRunner)(nil) -func newStandardRunner(debugLog bool) *StandardRunner { +func NewStandardRunner(debugLog bool) *StandardRunner { return &StandardRunner{ debugLog: debugLog, } } -func (x *StandardRunner) Run(c *command.Command) (rerr error) { +func (x *StandardRunner) Run(c *Command) (rerr error) { cmd := exec.Command(c.Args[0], c.Args[1:]...) cmd.Env = append(os.Environ(), c.Envs...) cmd.Stdin = os.Stdin diff --git a/tmux_runner.go b/command/tmux_runner.go similarity index 96% rename from tmux_runner.go rename to command/tmux_runner.go index 9c69c1f..551ea81 100644 --- a/tmux_runner.go +++ b/command/tmux_runner.go @@ -1,4 +1,4 @@ -package main +package command import ( "bytes" @@ -11,8 +11,6 @@ import ( "regexp" "strings" "time" - - "github.com/akm/git-exec/command" ) type TmuxRunner struct { @@ -27,7 +25,7 @@ type TmuxRunner struct { var _ Runner = (*TmuxRunner)(nil) -func newTmuxRunner(debugLog bool) *TmuxRunner { +func NewTmuxRunner(debugLog bool) *TmuxRunner { doneStringPrefix := "git-exec-done" return &TmuxRunner{ session: "git-exec-session", @@ -39,7 +37,7 @@ func newTmuxRunner(debugLog bool) *TmuxRunner { } } -func (x *TmuxRunner) Run(c *command.Command) (rerr error) { +func (x *TmuxRunner) Run(c *Command) (rerr error) { if _, err := exec.LookPath("tmux"); err != nil { return fmt.Errorf("tmux is not installed. Please install tmux. See https://github.com/tmux/tmux/wiki/Installing") } diff --git a/main.go b/main.go index 1b14c3e..8b505de 100644 --- a/main.go +++ b/main.go @@ -51,21 +51,21 @@ func process(options *Options, commandArgs []string) error { } } - command := command.NewCommand(commandArgs) - var runner Runner + cmd := command.NewCommand(commandArgs) + var runner command.Runner if options.Interactive { - runner = newTmuxRunner(options.DebugLog) + runner = command.NewTmuxRunner(options.DebugLog) } else { - runner = newStandardRunner(options.DebugLog) + runner = command.NewStandardRunner(options.DebugLog) } var commitMessage *commitMessage if err := changeDir((options.Directory), func() error { - if err := runner.Run(command); err != nil { + if err := runner.Run(cmd); err != nil { slog.Error("Command execution failed", "error", err) - return fmt.Errorf("Command execution failed: %+v\n%s", err, command.Output) + return fmt.Errorf("Command execution failed: %+v\n%s", err, cmd.Output) } - commitMessage = newCommitMessage(command, options) + commitMessage = newCommitMessage(cmd, options) return nil }); err != nil { return err diff --git a/runner.go b/runner.go deleted file mode 100644 index 55cbe15..0000000 --- a/runner.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/akm/git-exec/command" -) - -type Runner interface { - Run(c *command.Command) error -} From 1e1005ba0c8898d5410f784196341f1843d8e18f Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:05:49 +0900 Subject: [PATCH 16/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20newOpt=20f?= =?UTF-8?q?unction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/options.go b/options.go index 08b26e8..3498f7d 100644 --- a/options.go +++ b/options.go @@ -37,19 +37,21 @@ func newOptions() *Options { } type OptionType struct { - ShortName string - LongName string - HasValue bool - SetFunc func(*Options, string) - WithoutEnv bool + envKeyPrefix string + ShortName string + LongName string + HasValue bool + SetFunc func(*Options, string) + WithoutEnv bool } -func newOptionType(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { +func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { return &OptionType{ - ShortName: shortName, - LongName: longName, - HasValue: hasValue, - SetFunc: setFunc, + envKeyPrefix: envKeyPrefix, + ShortName: shortName, + LongName: longName, + HasValue: hasValue, + SetFunc: setFunc, } } @@ -57,10 +59,8 @@ func (o *OptionType) setValue(opts *Options, value string) { o.SetFunc(opts, value) } -const envKeyPrefix = "GIT_EXEC_" - func (o *OptionType) envKey() string { - return envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) + return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } func (o *OptionType) withoutEnv() *OptionType { @@ -68,6 +68,12 @@ func (o *OptionType) withoutEnv() *OptionType { return o } +const envKeyPrefix = "GIT_EXEC_" + +func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { + return newOptionType(envKeyPrefix, shortName, longName, hasValue, setFunc) +} + var defaultOptions = &Options{ Help: false, Version: false, @@ -80,20 +86,20 @@ var defaultOptions = &Options{ } var ( - optDirectory = newOptionType("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).withoutEnv() - optEmoji = newOptionType("-e", "--emoji", true, func(o *Options, v string) { o.Emoji = v }) - optPrompt = newOptionType("-p", "--prompt", true, func(o *Options, v string) { o.Prompt = v }) - optTemplate = newOptionType("-t", "--template", true, func(o *Options, v string) { o.Template = v }) + optDirectory = newOpt("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).withoutEnv() + optEmoji = newOpt("-e", "--emoji", true, func(o *Options, v string) { o.Emoji = v }) + optPrompt = newOpt("-p", "--prompt", true, func(o *Options, v string) { o.Prompt = v }) + optTemplate = newOpt("-t", "--template", true, func(o *Options, v string) { o.Template = v }) - optSkipGuard = newOptionType("", "--skip-guard", false, func(o *Options, _ string) { o.SkipGuard = true }) - optSkipGuardUncommittedChanges = newOptionType("", "--skip-guard-uncommitted-changes", false, func(o *Options, _ string) { o.SkipGuardUncommittedChanges = true }) - optSkipGuardUntrackedFiles = newOptionType("", "--skip-guard-untracked-files", false, func(o *Options, _ string) { o.SkipGuardUntrackedFiles = true }) + optSkipGuard = newOpt("", "--skip-guard", false, func(o *Options, _ string) { o.SkipGuard = true }) + optSkipGuardUncommittedChanges = newOpt("", "--skip-guard-uncommitted-changes", false, func(o *Options, _ string) { o.SkipGuardUncommittedChanges = true }) + optSkipGuardUntrackedFiles = newOpt("", "--skip-guard-untracked-files", false, func(o *Options, _ string) { o.SkipGuardUntrackedFiles = true }) - optDebugLog = newOptionType("-D", "--debug-log", false, func(o *Options, _ string) { o.DebugLog = true }) - optInteractive = newOptionType("-i", "--interactive", false, func(o *Options, _ string) { o.Interactive = true }) + optDebugLog = newOpt("-D", "--debug-log", false, func(o *Options, _ string) { o.DebugLog = true }) + optInteractive = newOpt("-i", "--interactive", false, func(o *Options, _ string) { o.Interactive = true }) - optHelp = newOptionType("-h", "--help", false, func(o *Options, _ string) { o.Help = true }).withoutEnv() - optVersion = newOptionType("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).withoutEnv() + optHelp = newOpt("-h", "--help", false, func(o *Options, _ string) { o.Help = true }).withoutEnv() + optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).withoutEnv() ) var optionTypes = []*OptionType{ From 2b3a1568f6e4bad68b9cebb419fea1ca28a1e836 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:08:25 +0900 Subject: [PATCH 17/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20option=5Ft?= =?UTF-8?q?ype.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- option_type.go | 35 +++++++++++++++++++++++++++++++++++ options.go | 32 -------------------------------- 2 files changed, 35 insertions(+), 32 deletions(-) create mode 100644 option_type.go diff --git a/option_type.go b/option_type.go new file mode 100644 index 0000000..53dacc2 --- /dev/null +++ b/option_type.go @@ -0,0 +1,35 @@ +package main + +import "strings" + +type OptionType struct { + envKeyPrefix string + ShortName string + LongName string + HasValue bool + SetFunc func(*Options, string) + WithoutEnv bool +} + +func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { + return &OptionType{ + envKeyPrefix: envKeyPrefix, + ShortName: shortName, + LongName: longName, + HasValue: hasValue, + SetFunc: setFunc, + } +} + +func (o *OptionType) setValue(opts *Options, value string) { + o.SetFunc(opts, value) +} + +func (o *OptionType) envKey() string { + return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) +} + +func (o *OptionType) withoutEnv() *OptionType { + o.WithoutEnv = true + return o +} diff --git a/options.go b/options.go index 3498f7d..da5c341 100644 --- a/options.go +++ b/options.go @@ -36,38 +36,6 @@ func newOptions() *Options { return r } -type OptionType struct { - envKeyPrefix string - ShortName string - LongName string - HasValue bool - SetFunc func(*Options, string) - WithoutEnv bool -} - -func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { - return &OptionType{ - envKeyPrefix: envKeyPrefix, - ShortName: shortName, - LongName: longName, - HasValue: hasValue, - SetFunc: setFunc, - } -} - -func (o *OptionType) setValue(opts *Options, value string) { - o.SetFunc(opts, value) -} - -func (o *OptionType) envKey() string { - return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) -} - -func (o *OptionType) withoutEnv() *OptionType { - o.WithoutEnv = true - return o -} - const envKeyPrefix = "GIT_EXEC_" func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { From 48ba0ae8dc261010484f284f4e86413e23890f8c Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:12:55 +0900 Subject: [PATCH 18/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20option=5Ft?= =?UTF-8?q?ypes.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- option_types.go | 3 +++ options.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 option_types.go diff --git a/option_types.go b/option_types.go new file mode 100644 index 0000000..be7a66b --- /dev/null +++ b/option_types.go @@ -0,0 +1,3 @@ +package main + +type OptionTypes []*OptionType diff --git a/options.go b/options.go index da5c341..094be15 100644 --- a/options.go +++ b/options.go @@ -70,7 +70,7 @@ var ( optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).withoutEnv() ) -var optionTypes = []*OptionType{ +var optionTypes = OptionTypes{ optDirectory, optEmoji, optPrompt, From 04e39764d2550f33f00acf82062ab9d9aa9c2c10 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:28:42 +0900 Subject: [PATCH 19/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20SetValue=20?= =?UTF-8?q?method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- option_type.go | 4 ---- options.go | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/option_type.go b/option_type.go index 53dacc2..004eb4d 100644 --- a/option_type.go +++ b/option_type.go @@ -21,10 +21,6 @@ func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setF } } -func (o *OptionType) setValue(opts *Options, value string) { - o.SetFunc(opts, value) -} - func (o *OptionType) envKey() string { return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } diff --git a/options.go b/options.go index 094be15..ef7f990 100644 --- a/options.go +++ b/options.go @@ -30,7 +30,7 @@ func newOptions() *Options { continue } if v := os.Getenv(opt.envKey()); v != "" { - opt.setValue(r, v) + opt.SetFunc(r, v) } } return r @@ -100,7 +100,7 @@ func parseOptions(args []string) (*Options, []string, error) { var pendingOptionType *OptionType for _, arg := range args { if pendingOptionType != nil { - pendingOptionType.setValue(options, arg) + pendingOptionType.SetFunc(options, arg) pendingOptionType = nil continue } @@ -112,7 +112,7 @@ func parseOptions(args []string) (*Options, []string, error) { if optionType.HasValue { pendingOptionType = optionType } else { - optionType.setValue(options, "") + optionType.SetFunc(options, "") } } else { inOptions = false From 9b252ae86fdd3f6bc7e1973c7778c09d9954815a Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:31:49 +0900 Subject: [PATCH 20/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20Generics=20for?= =?UTF-8?q?=20reference=20from=20OptionType=20to=20Options?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- option_type.go | 12 ++++++------ option_types.go | 2 +- options.go | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/option_type.go b/option_type.go index 004eb4d..f55baa8 100644 --- a/option_type.go +++ b/option_type.go @@ -2,17 +2,17 @@ package main import "strings" -type OptionType struct { +type OptionType[T any] struct { envKeyPrefix string ShortName string LongName string HasValue bool - SetFunc func(*Options, string) + SetFunc func(*T, string) WithoutEnv bool } -func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { - return &OptionType{ +func newOptionType[T any](envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*T, string)) *OptionType[T] { + return &OptionType[T]{ envKeyPrefix: envKeyPrefix, ShortName: shortName, LongName: longName, @@ -21,11 +21,11 @@ func newOptionType(envKeyPrefix, shortName, longName string, hasValue bool, setF } } -func (o *OptionType) envKey() string { +func (o *OptionType[T]) envKey() string { return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } -func (o *OptionType) withoutEnv() *OptionType { +func (o *OptionType[T]) withoutEnv() *OptionType[T] { o.WithoutEnv = true return o } diff --git a/option_types.go b/option_types.go index be7a66b..e186697 100644 --- a/option_types.go +++ b/option_types.go @@ -1,3 +1,3 @@ package main -type OptionTypes []*OptionType +type OptionTypes[T any] []*OptionType[T] diff --git a/options.go b/options.go index ef7f990..a910b89 100644 --- a/options.go +++ b/options.go @@ -38,7 +38,7 @@ func newOptions() *Options { const envKeyPrefix = "GIT_EXEC_" -func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType { +func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType[Options] { return newOptionType(envKeyPrefix, shortName, longName, hasValue, setFunc) } @@ -70,7 +70,7 @@ var ( optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).withoutEnv() ) -var optionTypes = OptionTypes{ +var optionTypes = OptionTypes[Options]{ optDirectory, optEmoji, optPrompt, @@ -84,8 +84,8 @@ var optionTypes = OptionTypes{ optVersion, } -var optionKeyMap = func() map[string]*OptionType { - m := map[string]*OptionType{} +var optionKeyMap = func() map[string]*OptionType[Options] { + m := map[string]*OptionType[Options]{} for _, opt := range optionTypes { m[opt.ShortName] = opt m[opt.LongName] = opt @@ -97,7 +97,7 @@ func parseOptions(args []string) (*Options, []string, error) { options := newOptions() commandArgs := []string{} inOptions := true - var pendingOptionType *OptionType + var pendingOptionType *OptionType[Options] for _, arg := range args { if pendingOptionType != nil { pendingOptionType.SetFunc(options, arg) From 692fe94c5b23ad7d21d4d1cd53b25004339922dc Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:40:51 +0900 Subject: [PATCH 21/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts=20pac?= =?UTF-8?q?kage=20with=20OptionType=20and=20OptionTypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- help.go | 4 ++-- options.go | 23 ++++++++++++----------- option_type.go => opts/option_type.go | 15 +++++++++------ option_types.go => opts/option_types.go | 2 +- 4 files changed, 24 insertions(+), 20 deletions(-) rename option_type.go => opts/option_type.go (64%) rename option_types.go => opts/option_types.go (76%) diff --git a/help.go b/help.go index 31b602a..fba06b8 100644 --- a/help.go +++ b/help.go @@ -41,8 +41,8 @@ func help() { } optionItems[i] = item - if !opt.WithoutEnv { - envVarItems = append(envVarItems, fmt.Sprintf(longNameFormat+" %s", opt.LongName, opt.envKey())) + if !opt.GetWithoutEnv() { + envVarItems = append(envVarItems, fmt.Sprintf(longNameFormat+" %s", opt.LongName, opt.EnvKey())) } } options := "Options:\n" + strings.Join(optionItems, "\n") diff --git a/options.go b/options.go index a910b89..cac4d90 100644 --- a/options.go +++ b/options.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/akm/git-exec/git" + "github.com/akm/git-exec/opts" ) type Options struct { @@ -26,10 +27,10 @@ func newOptions() *Options { defaultOptionsCopy := *defaultOptions r := &defaultOptionsCopy for _, opt := range optionTypes { - if opt.WithoutEnv { + if opt.GetWithoutEnv() { continue } - if v := os.Getenv(opt.envKey()); v != "" { + if v := os.Getenv(opt.EnvKey()); v != "" { opt.SetFunc(r, v) } } @@ -38,8 +39,8 @@ func newOptions() *Options { const envKeyPrefix = "GIT_EXEC_" -func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *OptionType[Options] { - return newOptionType(envKeyPrefix, shortName, longName, hasValue, setFunc) +func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.OptionType[Options] { + return opts.NewOptionType(envKeyPrefix, shortName, longName, hasValue, setFunc) } var defaultOptions = &Options{ @@ -54,7 +55,7 @@ var defaultOptions = &Options{ } var ( - optDirectory = newOpt("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).withoutEnv() + optDirectory = newOpt("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).WithoutEnv() optEmoji = newOpt("-e", "--emoji", true, func(o *Options, v string) { o.Emoji = v }) optPrompt = newOpt("-p", "--prompt", true, func(o *Options, v string) { o.Prompt = v }) optTemplate = newOpt("-t", "--template", true, func(o *Options, v string) { o.Template = v }) @@ -66,11 +67,11 @@ var ( optDebugLog = newOpt("-D", "--debug-log", false, func(o *Options, _ string) { o.DebugLog = true }) optInteractive = newOpt("-i", "--interactive", false, func(o *Options, _ string) { o.Interactive = true }) - optHelp = newOpt("-h", "--help", false, func(o *Options, _ string) { o.Help = true }).withoutEnv() - optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).withoutEnv() + optHelp = newOpt("-h", "--help", false, func(o *Options, _ string) { o.Help = true }).WithoutEnv() + optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).WithoutEnv() ) -var optionTypes = OptionTypes[Options]{ +var optionTypes = opts.OptionTypes[Options]{ optDirectory, optEmoji, optPrompt, @@ -84,8 +85,8 @@ var optionTypes = OptionTypes[Options]{ optVersion, } -var optionKeyMap = func() map[string]*OptionType[Options] { - m := map[string]*OptionType[Options]{} +var optionKeyMap = func() map[string]*opts.OptionType[Options] { + m := map[string]*opts.OptionType[Options]{} for _, opt := range optionTypes { m[opt.ShortName] = opt m[opt.LongName] = opt @@ -97,7 +98,7 @@ func parseOptions(args []string) (*Options, []string, error) { options := newOptions() commandArgs := []string{} inOptions := true - var pendingOptionType *OptionType[Options] + var pendingOptionType *opts.OptionType[Options] for _, arg := range args { if pendingOptionType != nil { pendingOptionType.SetFunc(options, arg) diff --git a/option_type.go b/opts/option_type.go similarity index 64% rename from option_type.go rename to opts/option_type.go index f55baa8..e6a2bd3 100644 --- a/option_type.go +++ b/opts/option_type.go @@ -1,4 +1,4 @@ -package main +package opts import "strings" @@ -8,10 +8,10 @@ type OptionType[T any] struct { LongName string HasValue bool SetFunc func(*T, string) - WithoutEnv bool + withoutEnv bool } -func newOptionType[T any](envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*T, string)) *OptionType[T] { +func NewOptionType[T any](envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*T, string)) *OptionType[T] { return &OptionType[T]{ envKeyPrefix: envKeyPrefix, ShortName: shortName, @@ -21,11 +21,14 @@ func newOptionType[T any](envKeyPrefix, shortName, longName string, hasValue boo } } -func (o *OptionType[T]) envKey() string { +func (o *OptionType[T]) EnvKey() string { return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } -func (o *OptionType[T]) withoutEnv() *OptionType[T] { - o.WithoutEnv = true +func (o *OptionType[T]) WithoutEnv() *OptionType[T] { + o.withoutEnv = true return o } +func (o *OptionType[T]) GetWithoutEnv() bool { + return o.withoutEnv +} diff --git a/option_types.go b/opts/option_types.go similarity index 76% rename from option_types.go rename to opts/option_types.go index e186697..0867dad 100644 --- a/option_types.go +++ b/opts/option_types.go @@ -1,3 +1,3 @@ -package main +package opts type OptionTypes[T any] []*OptionType[T] From ae41750f939beaf828bdbf2d39c6c60edc7c2d95 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:42:44 +0900 Subject: [PATCH 22/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20OptionType?= =?UTF-8?q?=20to=20Definition,=20OptionTypes=20to=20Definitions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 12 ++++++------ opts/option_type.go | 12 ++++++------ opts/option_types.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/options.go b/options.go index cac4d90..f14c91f 100644 --- a/options.go +++ b/options.go @@ -39,8 +39,8 @@ func newOptions() *Options { const envKeyPrefix = "GIT_EXEC_" -func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.OptionType[Options] { - return opts.NewOptionType(envKeyPrefix, shortName, longName, hasValue, setFunc) +func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, hasValue, setFunc) } var defaultOptions = &Options{ @@ -71,7 +71,7 @@ var ( optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).WithoutEnv() ) -var optionTypes = opts.OptionTypes[Options]{ +var optionTypes = opts.Definitions[Options]{ optDirectory, optEmoji, optPrompt, @@ -85,8 +85,8 @@ var optionTypes = opts.OptionTypes[Options]{ optVersion, } -var optionKeyMap = func() map[string]*opts.OptionType[Options] { - m := map[string]*opts.OptionType[Options]{} +var optionKeyMap = func() map[string]*opts.Definition[Options] { + m := map[string]*opts.Definition[Options]{} for _, opt := range optionTypes { m[opt.ShortName] = opt m[opt.LongName] = opt @@ -98,7 +98,7 @@ func parseOptions(args []string) (*Options, []string, error) { options := newOptions() commandArgs := []string{} inOptions := true - var pendingOptionType *opts.OptionType[Options] + var pendingOptionType *opts.Definition[Options] for _, arg := range args { if pendingOptionType != nil { pendingOptionType.SetFunc(options, arg) diff --git a/opts/option_type.go b/opts/option_type.go index e6a2bd3..5aae683 100644 --- a/opts/option_type.go +++ b/opts/option_type.go @@ -2,7 +2,7 @@ package opts import "strings" -type OptionType[T any] struct { +type Definition[T any] struct { envKeyPrefix string ShortName string LongName string @@ -11,8 +11,8 @@ type OptionType[T any] struct { withoutEnv bool } -func NewOptionType[T any](envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*T, string)) *OptionType[T] { - return &OptionType[T]{ +func NewDefinition[T any](envKeyPrefix, shortName, longName string, hasValue bool, setFunc func(*T, string)) *Definition[T] { + return &Definition[T]{ envKeyPrefix: envKeyPrefix, ShortName: shortName, LongName: longName, @@ -21,14 +21,14 @@ func NewOptionType[T any](envKeyPrefix, shortName, longName string, hasValue boo } } -func (o *OptionType[T]) EnvKey() string { +func (o *Definition[T]) EnvKey() string { return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } -func (o *OptionType[T]) WithoutEnv() *OptionType[T] { +func (o *Definition[T]) WithoutEnv() *Definition[T] { o.withoutEnv = true return o } -func (o *OptionType[T]) GetWithoutEnv() bool { +func (o *Definition[T]) GetWithoutEnv() bool { return o.withoutEnv } diff --git a/opts/option_types.go b/opts/option_types.go index 0867dad..5b6b7c8 100644 --- a/opts/option_types.go +++ b/opts/option_types.go @@ -1,3 +1,3 @@ package opts -type OptionTypes[T any] []*OptionType[T] +type Definitions[T any] []*Definition[T] From 5443296cfb661f5f250fe7c7736935c3534508c7 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:51:18 +0900 Subject: [PATCH 23/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20option=5Fty?= =?UTF-8?q?pe.go=20to=20definition.go=20and=20options=5Ftypes.go=20to=20de?= =?UTF-8?q?finitions.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opts/{option_type.go => definition.go} | 0 opts/{option_types.go => definitions.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename opts/{option_type.go => definition.go} (100%) rename opts/{option_types.go => definitions.go} (100%) diff --git a/opts/option_type.go b/opts/definition.go similarity index 100% rename from opts/option_type.go rename to opts/definition.go diff --git a/opts/option_types.go b/opts/definitions.go similarity index 100% rename from opts/option_types.go rename to opts/definitions.go From 2c078f585dd8f72379c624593d957a18d24de372 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:52:47 +0900 Subject: [PATCH 24/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts.Build?= =?UTF-8?q?KeyMap=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 10 +--------- opts/definitions.go | 9 +++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/options.go b/options.go index f14c91f..500f469 100644 --- a/options.go +++ b/options.go @@ -85,19 +85,11 @@ var optionTypes = opts.Definitions[Options]{ optVersion, } -var optionKeyMap = func() map[string]*opts.Definition[Options] { - m := map[string]*opts.Definition[Options]{} - for _, opt := range optionTypes { - m[opt.ShortName] = opt - m[opt.LongName] = opt - } - return m -}() - func parseOptions(args []string) (*Options, []string, error) { options := newOptions() commandArgs := []string{} inOptions := true + optionKeyMap := opts.BuildKeyMap(optionTypes) var pendingOptionType *opts.Definition[Options] for _, arg := range args { if pendingOptionType != nil { diff --git a/opts/definitions.go b/opts/definitions.go index 5b6b7c8..a29e09f 100644 --- a/opts/definitions.go +++ b/opts/definitions.go @@ -1,3 +1,12 @@ package opts type Definitions[T any] []*Definition[T] + +func BuildKeyMap[T any](defs Definitions[T]) map[string]*Definition[T] { + m := make(map[string]*Definition[T], len(defs)) + for _, def := range defs { + m[def.LongName] = def + m[def.ShortName] = def + } + return m +} From 47e274c0b3466103f983e50d1b78fe0c68bd262d Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 21:57:48 +0900 Subject: [PATCH 25/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts.Parse?= =?UTF-8?q?=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 33 +-------------------------------- opts/definitions.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/options.go b/options.go index 500f469..49c683e 100644 --- a/options.go +++ b/options.go @@ -1,9 +1,7 @@ package main import ( - "fmt" "os" - "strings" "github.com/akm/git-exec/git" "github.com/akm/git-exec/opts" @@ -86,34 +84,5 @@ var optionTypes = opts.Definitions[Options]{ } func parseOptions(args []string) (*Options, []string, error) { - options := newOptions() - commandArgs := []string{} - inOptions := true - optionKeyMap := opts.BuildKeyMap(optionTypes) - var pendingOptionType *opts.Definition[Options] - for _, arg := range args { - if pendingOptionType != nil { - pendingOptionType.SetFunc(options, arg) - pendingOptionType = nil - continue - } - if inOptions && strings.HasPrefix(arg, "-") { - optionType, ok := optionKeyMap[arg] - if !ok { - return nil, nil, fmt.Errorf("Unknown option: %s", arg) - } - if optionType.HasValue { - pendingOptionType = optionType - } else { - optionType.SetFunc(options, "") - } - } else { - inOptions = false - commandArgs = append(commandArgs, arg) - } - } - if pendingOptionType != nil { - return nil, nil, fmt.Errorf("no value given for option %s", pendingOptionType.LongName) - } - return options, commandArgs, nil + return opts.Parse(newOptions, optionTypes, args...) } diff --git a/opts/definitions.go b/opts/definitions.go index a29e09f..990bb7a 100644 --- a/opts/definitions.go +++ b/opts/definitions.go @@ -1,5 +1,10 @@ package opts +import ( + "fmt" + "strings" +) + type Definitions[T any] []*Definition[T] func BuildKeyMap[T any](defs Definitions[T]) map[string]*Definition[T] { @@ -10,3 +15,36 @@ func BuildKeyMap[T any](defs Definitions[T]) map[string]*Definition[T] { } return m } + +func Parse[T any](factory func() *T, defs Definitions[T], args ...string) (*T, []string, error) { + options := factory() + commandArgs := []string{} + inOptions := true + optionKeyMap := BuildKeyMap(defs) + var pendingOptionType *Definition[T] + for _, arg := range args { + if pendingOptionType != nil { + pendingOptionType.SetFunc(options, arg) + pendingOptionType = nil + continue + } + if inOptions && strings.HasPrefix(arg, "-") { + optionType, ok := optionKeyMap[arg] + if !ok { + return nil, nil, fmt.Errorf("Unknown option: %s", arg) + } + if optionType.HasValue { + pendingOptionType = optionType + } else { + optionType.SetFunc(options, "") + } + } else { + inOptions = false + commandArgs = append(commandArgs, arg) + } + } + if pendingOptionType != nil { + return nil, nil, fmt.Errorf("no value given for option %s", pendingOptionType.LongName) + } + return options, commandArgs, nil +} From f9880923caac67d767935840f7b0d7b825b23ba1 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:00:16 +0900 Subject: [PATCH 26/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20opts.Defini?= =?UTF-8?q?tions=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 2 +- opts/definitions.go | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/options.go b/options.go index 49c683e..0caeba6 100644 --- a/options.go +++ b/options.go @@ -69,7 +69,7 @@ var ( optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).WithoutEnv() ) -var optionTypes = opts.Definitions[Options]{ +var optionTypes = []*opts.Definition[Options]{ optDirectory, optEmoji, optPrompt, diff --git a/opts/definitions.go b/opts/definitions.go index 990bb7a..f67462d 100644 --- a/opts/definitions.go +++ b/opts/definitions.go @@ -5,22 +5,11 @@ import ( "strings" ) -type Definitions[T any] []*Definition[T] - -func BuildKeyMap[T any](defs Definitions[T]) map[string]*Definition[T] { - m := make(map[string]*Definition[T], len(defs)) - for _, def := range defs { - m[def.LongName] = def - m[def.ShortName] = def - } - return m -} - -func Parse[T any](factory func() *T, defs Definitions[T], args ...string) (*T, []string, error) { +func Parse[T any](factory func() *T, defs []*Definition[T], args ...string) (*T, []string, error) { options := factory() commandArgs := []string{} inOptions := true - optionKeyMap := BuildKeyMap(defs) + optionKeyMap := buildKeyMap(defs) var pendingOptionType *Definition[T] for _, arg := range args { if pendingOptionType != nil { @@ -48,3 +37,12 @@ func Parse[T any](factory func() *T, defs Definitions[T], args ...string) (*T, [ } return options, commandArgs, nil } + +func buildKeyMap[T any](defs []*Definition[T]) map[string]*Definition[T] { + m := make(map[string]*Definition[T], len(defs)) + for _, def := range defs { + m[def.LongName] = def + m[def.ShortName] = def + } + return m +} From 286be7c130ba7571a37c73300e2fa2c906897a78 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:01:07 +0900 Subject: [PATCH 27/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20definitions?= =?UTF-8?q?.go=20to=20parse.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opts/{definitions.go => parse.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename opts/{definitions.go => parse.go} (100%) diff --git a/opts/definitions.go b/opts/parse.go similarity index 100% rename from opts/definitions.go rename to opts/parse.go From 6c989eb9694e51e6f603d07dfb4dc3794f7563ea Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:15:22 +0900 Subject: [PATCH 28/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts.NewOp?= =?UTF-8?q?tions=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 22 +++++----------------- opts/parse.go | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/options.go b/options.go index 0caeba6..1030f05 100644 --- a/options.go +++ b/options.go @@ -1,8 +1,6 @@ package main import ( - "os" - "github.com/akm/git-exec/git" "github.com/akm/git-exec/opts" ) @@ -21,20 +19,6 @@ type Options struct { Interactive bool } -func newOptions() *Options { - defaultOptionsCopy := *defaultOptions - r := &defaultOptionsCopy - for _, opt := range optionTypes { - if opt.GetWithoutEnv() { - continue - } - if v := os.Getenv(opt.EnvKey()); v != "" { - opt.SetFunc(r, v) - } - } - return r -} - const envKeyPrefix = "GIT_EXEC_" func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.Definition[Options] { @@ -83,6 +67,10 @@ var optionTypes = []*opts.Definition[Options]{ optVersion, } +func newOptions() *Options { + return opts.NewOptions(optionTypes, defaultOptions) +} + func parseOptions(args []string) (*Options, []string, error) { - return opts.Parse(newOptions, optionTypes, args...) + return opts.Parse(defaultOptions, optionTypes, args...) } diff --git a/opts/parse.go b/opts/parse.go index f67462d..6fa3caf 100644 --- a/opts/parse.go +++ b/opts/parse.go @@ -2,11 +2,12 @@ package opts import ( "fmt" + "os" "strings" ) -func Parse[T any](factory func() *T, defs []*Definition[T], args ...string) (*T, []string, error) { - options := factory() +func Parse[T any](defualtOptions *T, defs []*Definition[T], args ...string) (*T, []string, error) { + options := NewOptions(defs, defualtOptions) commandArgs := []string{} inOptions := true optionKeyMap := buildKeyMap(defs) @@ -38,6 +39,20 @@ func Parse[T any](factory func() *T, defs []*Definition[T], args ...string) (*T, return options, commandArgs, nil } +func NewOptions[T any](defs []*Definition[T], defaultOptions *T) *T { + copy := *defaultOptions + r := © + for _, opt := range defs { + if opt.GetWithoutEnv() { + continue + } + if v := os.Getenv(opt.EnvKey()); v != "" { + opt.SetFunc(r, v) + } + } + return r +} + func buildKeyMap[T any](defs []*Definition[T]) map[string]*Definition[T] { m := make(map[string]*Definition[T], len(defs)) for _, def := range defs { From 7ffc964e9142e8ca26b7530fa5e300d3dc18effd Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:17:26 +0900 Subject: [PATCH 29/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20newOpt=20defi?= =?UTF-8?q?nition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/options.go b/options.go index 1030f05..fcfbf42 100644 --- a/options.go +++ b/options.go @@ -19,12 +19,6 @@ type Options struct { Interactive bool } -const envKeyPrefix = "GIT_EXEC_" - -func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, hasValue, setFunc) -} - var defaultOptions = &Options{ Help: false, Version: false, @@ -36,6 +30,12 @@ var defaultOptions = &Options{ Interactive: false, } +const envKeyPrefix = "GIT_EXEC_" + +func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, hasValue, setFunc) +} + var ( optDirectory = newOpt("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).WithoutEnv() optEmoji = newOpt("-e", "--emoji", true, func(o *Options, v string) { o.Emoji = v }) From 58ed4f10d94c8140366cd71342ac342ac86ccd1a Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:48:07 +0900 Subject: [PATCH 30/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20boolOpt=20?= =?UTF-8?q?and=20strOpt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/options.go b/options.go index fcfbf42..79ba5b3 100644 --- a/options.go +++ b/options.go @@ -32,25 +32,29 @@ var defaultOptions = &Options{ const envKeyPrefix = "GIT_EXEC_" -func newOpt(shortName, longName string, hasValue bool, setFunc func(*Options, string)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, hasValue, setFunc) +func boolOpt(shortName, longName string, setFunc func(*Options)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setFunc(o) }) +} + +func strOpt(shortName, longName string, setFunc func(*Options, string)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setFunc) } var ( - optDirectory = newOpt("-C", "--directory", true, func(o *Options, v string) { o.Directory = v }).WithoutEnv() - optEmoji = newOpt("-e", "--emoji", true, func(o *Options, v string) { o.Emoji = v }) - optPrompt = newOpt("-p", "--prompt", true, func(o *Options, v string) { o.Prompt = v }) - optTemplate = newOpt("-t", "--template", true, func(o *Options, v string) { o.Template = v }) + optDirectory = strOpt("-C", "--directory", func(o *Options, v string) { o.Directory = v }).WithoutEnv() + optEmoji = strOpt("-e", "--emoji", func(o *Options, v string) { o.Emoji = v }) + optPrompt = strOpt("-p", "--prompt", func(o *Options, v string) { o.Prompt = v }) + optTemplate = strOpt("-t", "--template", func(o *Options, v string) { o.Template = v }) - optSkipGuard = newOpt("", "--skip-guard", false, func(o *Options, _ string) { o.SkipGuard = true }) - optSkipGuardUncommittedChanges = newOpt("", "--skip-guard-uncommitted-changes", false, func(o *Options, _ string) { o.SkipGuardUncommittedChanges = true }) - optSkipGuardUntrackedFiles = newOpt("", "--skip-guard-untracked-files", false, func(o *Options, _ string) { o.SkipGuardUntrackedFiles = true }) + optSkipGuard = boolOpt("", "--skip-guard", func(o *Options) { o.SkipGuard = true }) + optSkipGuardUncommittedChanges = boolOpt("", "--skip-guard-uncommitted-changes", func(o *Options) { o.SkipGuardUncommittedChanges = true }) + optSkipGuardUntrackedFiles = boolOpt("", "--skip-guard-untracked-files", func(o *Options) { o.SkipGuardUntrackedFiles = true }) - optDebugLog = newOpt("-D", "--debug-log", false, func(o *Options, _ string) { o.DebugLog = true }) - optInteractive = newOpt("-i", "--interactive", false, func(o *Options, _ string) { o.Interactive = true }) + optDebugLog = boolOpt("-D", "--debug-log", func(o *Options) { o.DebugLog = true }) + optInteractive = boolOpt("-i", "--interactive", func(o *Options) { o.Interactive = true }) - optHelp = newOpt("-h", "--help", false, func(o *Options, _ string) { o.Help = true }).WithoutEnv() - optVersion = newOpt("-v", "--version", false, func(o *Options, _ string) { o.Version = true }).WithoutEnv() + optHelp = boolOpt("-h", "--help", func(o *Options) { o.Help = true }).WithoutEnv() + optVersion = boolOpt("-v", "--version", func(o *Options) { o.Version = true }).WithoutEnv() ) var optionTypes = []*opts.Definition[Options]{ From d97a03314fd8b3fcc5f384403bcccd091434f6b7 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 22:59:49 +0900 Subject: [PATCH 31/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20under=20score?= =?UTF-8?q?=20for=20unused=20type=20parameter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opts/definition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opts/definition.go b/opts/definition.go index 5aae683..3fa86e4 100644 --- a/opts/definition.go +++ b/opts/definition.go @@ -21,7 +21,7 @@ func NewDefinition[T any](envKeyPrefix, shortName, longName string, hasValue boo } } -func (o *Definition[T]) EnvKey() string { +func (o *Definition[_]) EnvKey() string { return o.envKeyPrefix + strings.ToUpper(strings.ReplaceAll(strings.TrimLeft(o.LongName, "-"), "-", "_")) } @@ -29,6 +29,6 @@ func (o *Definition[T]) WithoutEnv() *Definition[T] { o.withoutEnv = true return o } -func (o *Definition[T]) GetWithoutEnv() bool { +func (o *Definition[_]) GetWithoutEnv() bool { return o.withoutEnv } From 53d11ab9e3ae0b6436e72c9fa9fd3f865986b40a Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:35:45 +0900 Subject: [PATCH 32/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20variables?= =?UTF-8?q?=20for=20optionTypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/options.go b/options.go index 79ba5b3..711c801 100644 --- a/options.go +++ b/options.go @@ -40,36 +40,24 @@ func strOpt(shortName, longName string, setFunc func(*Options, string)) *opts.De return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setFunc) } -var ( - optDirectory = strOpt("-C", "--directory", func(o *Options, v string) { o.Directory = v }).WithoutEnv() - optEmoji = strOpt("-e", "--emoji", func(o *Options, v string) { o.Emoji = v }) - optPrompt = strOpt("-p", "--prompt", func(o *Options, v string) { o.Prompt = v }) - optTemplate = strOpt("-t", "--template", func(o *Options, v string) { o.Template = v }) +var optionTypes = func() []*opts.Definition[Options] { + return []*opts.Definition[Options]{ + strOpt("-C", "--directory", func(o *Options, v string) { o.Directory = v }).WithoutEnv(), + strOpt("-e", "--emoji", func(o *Options, v string) { o.Emoji = v }), + strOpt("-p", "--prompt", func(o *Options, v string) { o.Prompt = v }), + strOpt("-t", "--template", func(o *Options, v string) { o.Template = v }), - optSkipGuard = boolOpt("", "--skip-guard", func(o *Options) { o.SkipGuard = true }) - optSkipGuardUncommittedChanges = boolOpt("", "--skip-guard-uncommitted-changes", func(o *Options) { o.SkipGuardUncommittedChanges = true }) - optSkipGuardUntrackedFiles = boolOpt("", "--skip-guard-untracked-files", func(o *Options) { o.SkipGuardUntrackedFiles = true }) + boolOpt("", "--skip-guard", func(o *Options) { o.SkipGuard = true }), + boolOpt("", "--skip-guard-uncommitted-changes", func(o *Options) { o.SkipGuardUncommittedChanges = true }), + boolOpt("", "--skip-guard-untracked-files", func(o *Options) { o.SkipGuardUntrackedFiles = true }), - optDebugLog = boolOpt("-D", "--debug-log", func(o *Options) { o.DebugLog = true }) - optInteractive = boolOpt("-i", "--interactive", func(o *Options) { o.Interactive = true }) + boolOpt("-D", "--debug-log", func(o *Options) { o.DebugLog = true }), + boolOpt("-i", "--interactive", func(o *Options) { o.Interactive = true }), - optHelp = boolOpt("-h", "--help", func(o *Options) { o.Help = true }).WithoutEnv() - optVersion = boolOpt("-v", "--version", func(o *Options) { o.Version = true }).WithoutEnv() -) - -var optionTypes = []*opts.Definition[Options]{ - optDirectory, - optEmoji, - optPrompt, - optTemplate, - optSkipGuard, - optSkipGuardUncommittedChanges, - optSkipGuardUntrackedFiles, - optDebugLog, - optInteractive, - optHelp, - optVersion, -} + boolOpt("-h", "--help", func(o *Options) { o.Help = true }).WithoutEnv(), + boolOpt("-v", "--version", func(o *Options) { o.Version = true }).WithoutEnv(), + } +}() func newOptions() *Options { return opts.NewOptions(optionTypes, defaultOptions) From 2d23a6df5e590031c614abb9b195c6ac416d3419 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:37:22 +0900 Subject: [PATCH 33/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20move=20const=20and?= =?UTF-8?q?=20function=20into=20optionTypes=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/options.go b/options.go index 711c801..3ceebb1 100644 --- a/options.go +++ b/options.go @@ -30,17 +30,15 @@ var defaultOptions = &Options{ Interactive: false, } -const envKeyPrefix = "GIT_EXEC_" - -func boolOpt(shortName, longName string, setFunc func(*Options)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setFunc(o) }) -} - -func strOpt(shortName, longName string, setFunc func(*Options, string)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setFunc) -} - var optionTypes = func() []*opts.Definition[Options] { + envKeyPrefix := "GIT_EXEC_" + boolOpt := func(shortName, longName string, setFunc func(*Options)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setFunc(o) }) + } + strOpt := func(shortName, longName string, setFunc func(*Options, string)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setFunc) + } + return []*opts.Definition[Options]{ strOpt("-C", "--directory", func(o *Options, v string) { o.Directory = v }).WithoutEnv(), strOpt("-e", "--emoji", func(o *Options, v string) { o.Emoji = v }), From 7f13a6c7478dfe4286289ade099d4e764c975aae Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:40:21 +0900 Subject: [PATCH 34/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20SetFunc=20t?= =?UTF-8?q?o=20Setter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opts/definition.go | 4 ++-- opts/parse.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opts/definition.go b/opts/definition.go index 3fa86e4..9920f71 100644 --- a/opts/definition.go +++ b/opts/definition.go @@ -7,7 +7,7 @@ type Definition[T any] struct { ShortName string LongName string HasValue bool - SetFunc func(*T, string) + Setter func(*T, string) withoutEnv bool } @@ -17,7 +17,7 @@ func NewDefinition[T any](envKeyPrefix, shortName, longName string, hasValue boo ShortName: shortName, LongName: longName, HasValue: hasValue, - SetFunc: setFunc, + Setter: setFunc, } } diff --git a/opts/parse.go b/opts/parse.go index 6fa3caf..bad7b47 100644 --- a/opts/parse.go +++ b/opts/parse.go @@ -14,7 +14,7 @@ func Parse[T any](defualtOptions *T, defs []*Definition[T], args ...string) (*T, var pendingOptionType *Definition[T] for _, arg := range args { if pendingOptionType != nil { - pendingOptionType.SetFunc(options, arg) + pendingOptionType.Setter(options, arg) pendingOptionType = nil continue } @@ -26,7 +26,7 @@ func Parse[T any](defualtOptions *T, defs []*Definition[T], args ...string) (*T, if optionType.HasValue { pendingOptionType = optionType } else { - optionType.SetFunc(options, "") + optionType.Setter(options, "") } } else { inOptions = false @@ -47,7 +47,7 @@ func NewOptions[T any](defs []*Definition[T], defaultOptions *T) *T { continue } if v := os.Getenv(opt.EnvKey()); v != "" { - opt.SetFunc(r, v) + opt.Setter(r, v) } } return r From 0a2523986473ac4c46cc462983f6bf0e32c1c3e2 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:42:30 +0900 Subject: [PATCH 35/45] =?UTF-8?q?=E2=9C=A8=20Add=20getter=20and=20help=20t?= =?UTF-8?q?o=20opts.Definition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opts/definition.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/opts/definition.go b/opts/definition.go index 9920f71..78cdb98 100644 --- a/opts/definition.go +++ b/opts/definition.go @@ -8,6 +8,8 @@ type Definition[T any] struct { LongName string HasValue bool Setter func(*T, string) + getter func(*T) string + help string withoutEnv bool } @@ -32,3 +34,19 @@ func (o *Definition[T]) WithoutEnv() *Definition[T] { func (o *Definition[_]) GetWithoutEnv() bool { return o.withoutEnv } + +func (o *Definition[T]) Getter(getter func(*T) string) *Definition[T] { + o.getter = getter + return o +} +func (o *Definition[T]) GetGetter() func(*T) string { + return o.getter +} + +func (o *Definition[T]) Help(help string) *Definition[T] { + o.help = help + return o +} +func (o *Definition[T]) GetHelp() string { + return o.help +} From 0dec5574c0e752bc6428c5dac438eecf6cae58ee Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:43:19 +0900 Subject: [PATCH 36/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20setFunc=20t?= =?UTF-8?q?o=20setter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/options.go b/options.go index 3ceebb1..c2088ad 100644 --- a/options.go +++ b/options.go @@ -32,11 +32,11 @@ var defaultOptions = &Options{ var optionTypes = func() []*opts.Definition[Options] { envKeyPrefix := "GIT_EXEC_" - boolOpt := func(shortName, longName string, setFunc func(*Options)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setFunc(o) }) + boolOpt := func(shortName, longName string, setter func(*Options)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setter(o) }) } - strOpt := func(shortName, longName string, setFunc func(*Options, string)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setFunc) + strOpt := func(shortName, longName string, setter func(*Options, string)) *opts.Definition[Options] { + return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setter) } return []*opts.Definition[Options]{ From aefc8beee5d47eca03b0a63e6d5259b1a6c10dd6 Mon Sep 17 00:00:00 2001 From: akm Date: Sat, 7 Dec 2024 23:59:56 +0900 Subject: [PATCH 37/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Define=20getter=20an?= =?UTF-8?q?d=20help=20message=20with=20optionTypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- help.go | 46 +++---------------------------- options.go | 81 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 57 deletions(-) diff --git a/help.go b/help.go index fba06b8..b826fce 100644 --- a/help.go +++ b/help.go @@ -26,6 +26,7 @@ func help() { } } + defaultOptions := newOptions() envVarItems := []string{} longNameFormat := "%-" + fmt.Sprintf("%ds", maxLongNameLength) for i, opt := range optionTypes { @@ -35,9 +36,9 @@ func help() { } else { item = fmt.Sprintf("%s%s, "+longNameFormat, indent, opt.ShortName, opt.LongName) } - item += " " + optionMessageMap[opt.LongName] - if defaultGetter, ok := defaultValueGetterMap[opt.LongName]; ok { - item += fmt.Sprintf(" (default: %s)", defaultGetter()) + item += " " + opt.GetHelp() + if getter := opt.GetGetter(); getter != nil { + item += fmt.Sprintf(" (default: %s)", getter(defaultOptions)) } optionItems[i] = item @@ -52,42 +53,3 @@ func help() { // 以後は 複数の引数を指定可能です。 fmt.Println(firstLine + "\n\n" + options + "\n\n" + envVars + "\n\n" + examples) } - -var optionMessageMap = map[string]string{ - "--help": "Show this message.", - "--version": "Show version.", - "--directory": "Specify the directory where the command is executed.", - "--emoji": "Specify the emoji used in commit message.", - "--prompt": "Specify the prompt used in commit message.", - "--template": "Specify the template to build commit message.", - "--skip-guard": "Skip the guard check for uncommitted changes and untracked files before executing command.", - "--skip-guard-uncommitted-changes": "Skip the guard check for uncommitted changes before executing command.", - "--skip-guard-untracked-files": "Skip the guard check for untracked files before executing command.", - "--debug-log": "Output debug log.", - "--interactive": "Interactive mode for command which requires input. tmux is required to use.", -} - -var defaultValueGetterMap = func() map[string]func() string { - boolToString := func(b bool) string { - if b { - return "true" - } else { - return "false" - } - } - quote := func(s string) string { - return fmt.Sprintf("%q", s) - } - - o := defaultOptions - return map[string]func() string{ - "--directory": func() string { return quote(o.Directory) }, - "--emoji": func() string { return quote(o.Emoji) }, - "--prompt": func() string { return quote(o.Prompt) }, - "--template": func() string { return quote(o.Template) }, - // skip guard - "--skip-guard": func() string { return boolToString(o.SkipGuard) }, - "--skip-guard-uncommitted-changes": func() string { return boolToString(o.SkipGuardUncommittedChanges) }, - "--skip-guard-untracked-files": func() string { return boolToString(o.SkipGuardUntrackedFiles) }, - } -}() diff --git a/options.go b/options.go index c2088ad..c8137e8 100644 --- a/options.go +++ b/options.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "github.com/akm/git-exec/git" "github.com/akm/git-exec/opts" ) @@ -31,29 +33,78 @@ var defaultOptions = &Options{ } var optionTypes = func() []*opts.Definition[Options] { + boolToString := func(b bool) string { + if b { + return "true" + } else { + return "false" + } + } + quote := func(s string) string { + return fmt.Sprintf("%q", s) + } + envKeyPrefix := "GIT_EXEC_" - boolOpt := func(shortName, longName string, setter func(*Options)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, false, func(o *Options, v string) { setter(o) }) + boolOpt := func(shortName, longName string, help string, getter func(*Options) bool, setter func(*Options)) *opts.Definition[Options] { + var actualGetter func(o *Options) string + if getter != nil { + actualGetter = func(o *Options) string { return boolToString(getter(o)) } + } + return opts.NewDefinition(envKeyPrefix, shortName, longName, false, + func(o *Options, v string) { setter(o) }). + Getter(actualGetter).Help(help) } - strOpt := func(shortName, longName string, setter func(*Options, string)) *opts.Definition[Options] { - return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setter) + strOpt := func(shortName, longName string, help string, getter func(*Options) string, setter func(*Options, string)) *opts.Definition[Options] { + var actualGetter func(o *Options) string + if getter != nil { + actualGetter = func(o *Options) string { return quote(getter(o)) } + } + return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setter). + Getter(actualGetter).Help(help) } return []*opts.Definition[Options]{ - strOpt("-C", "--directory", func(o *Options, v string) { o.Directory = v }).WithoutEnv(), - strOpt("-e", "--emoji", func(o *Options, v string) { o.Emoji = v }), - strOpt("-p", "--prompt", func(o *Options, v string) { o.Prompt = v }), - strOpt("-t", "--template", func(o *Options, v string) { o.Template = v }), + strOpt("-C", "--directory", "Specify the directory where the command is executed.", + func(o *Options) string { return o.Directory }, + func(o *Options, v string) { o.Directory = v }, + ).WithoutEnv(), + strOpt("-e", "--emoji", "Specify the emoji used in commit message.", + func(o *Options) string { return o.Emoji }, + func(o *Options, v string) { o.Emoji = v }, + ), + strOpt("-p", "--prompt", "Specify the prompt used in commit message.", + func(o *Options) string { return o.Prompt }, + func(o *Options, v string) { o.Prompt = v }, + ), + strOpt("-t", "--template", "Specify the template to build commit message.", + func(o *Options) string { return o.Template }, + func(o *Options, v string) { o.Template = v }, + ), - boolOpt("", "--skip-guard", func(o *Options) { o.SkipGuard = true }), - boolOpt("", "--skip-guard-uncommitted-changes", func(o *Options) { o.SkipGuardUncommittedChanges = true }), - boolOpt("", "--skip-guard-untracked-files", func(o *Options) { o.SkipGuardUntrackedFiles = true }), + boolOpt("", "--skip-guard", "Skip the guard check for uncommitted changes and untracked files before executing command.", + func(o *Options) bool { return o.SkipGuard }, + func(o *Options) { o.SkipGuard = true }, + ), + boolOpt("", "--skip-guard-uncommitted-changes", "Skip the guard check for uncommitted changes before executing command.", + func(o *Options) bool { return o.SkipGuardUncommittedChanges }, + func(o *Options) { o.SkipGuardUncommittedChanges = true }, + ), + boolOpt("", "--skip-guard-untracked-files", "Skip the guard check for untracked files before executing command.", + func(o *Options) bool { return o.SkipGuardUntrackedFiles }, + func(o *Options) { o.SkipGuardUntrackedFiles = true }, + ), - boolOpt("-D", "--debug-log", func(o *Options) { o.DebugLog = true }), - boolOpt("-i", "--interactive", func(o *Options) { o.Interactive = true }), + boolOpt("-D", "--debug-log", "Output debug log.", + func(o *Options) bool { return o.DebugLog }, + func(o *Options) { o.DebugLog = true }, + ), + boolOpt("-i", "--interactive", "Interactive mode for command which requires input. tmux is required to use.", + func(o *Options) bool { return o.Interactive }, + func(o *Options) { o.Interactive = true }, + ), - boolOpt("-h", "--help", func(o *Options) { o.Help = true }).WithoutEnv(), - boolOpt("-v", "--version", func(o *Options) { o.Version = true }).WithoutEnv(), + boolOpt("-h", "--help", "Show this message.", nil, func(o *Options) { o.Help = true }).WithoutEnv(), + boolOpt("-v", "--version", "Show version.", nil, func(o *Options) { o.Version = true }).WithoutEnv(), } }() From 01ed914ac33082d75ae874e162378bca9faf8a46 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:27:43 +0900 Subject: [PATCH 38/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts.HelpI?= =?UTF-8?q?temsAndEnvVarMappings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- help.go | 31 +++---------------------------- opts/help.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 opts/help.go diff --git a/help.go b/help.go index b826fce..1997fe5 100644 --- a/help.go +++ b/help.go @@ -3,6 +3,8 @@ package main import ( "fmt" "strings" + + "github.com/akm/git-exec/opts" ) func help() { @@ -17,35 +19,8 @@ func help() { * Use interactive mode for command which requires input such as "npx sv create" for SvelteKit. git exec -i npx sv create my-app ` - indent := " " - optionItems := make([]string, len(optionTypes)) - maxLongNameLength := 0 - for _, opt := range optionTypes { - if maxLongNameLength < len(opt.LongName) { - maxLongNameLength = len(opt.LongName) - } - } - - defaultOptions := newOptions() - envVarItems := []string{} - longNameFormat := "%-" + fmt.Sprintf("%ds", maxLongNameLength) - for i, opt := range optionTypes { - var item string - if opt.ShortName == "" { - item = fmt.Sprintf("%s "+longNameFormat, indent, opt.LongName) - } else { - item = fmt.Sprintf("%s%s, "+longNameFormat, indent, opt.ShortName, opt.LongName) - } - item += " " + opt.GetHelp() - if getter := opt.GetGetter(); getter != nil { - item += fmt.Sprintf(" (default: %s)", getter(defaultOptions)) - } + optionItems, envVarItems := opts.HelpItemsAndEnvVarMappings[Options](defaultOptions, optionTypes) - optionItems[i] = item - if !opt.GetWithoutEnv() { - envVarItems = append(envVarItems, fmt.Sprintf(longNameFormat+" %s", opt.LongName, opt.EnvKey())) - } - } options := "Options:\n" + strings.Join(optionItems, "\n") envVars := "Environment variable mapping:\n" + strings.Join(envVarItems, "\n") diff --git a/opts/help.go b/opts/help.go new file mode 100644 index 0000000..c217039 --- /dev/null +++ b/opts/help.go @@ -0,0 +1,36 @@ +package opts + +import "fmt" + +func HelpItemsAndEnvVarMappings[T any](defaultOptions *T, defs []*Definition[T]) ([]string, []string) { + optionItems := make([]string, len(defs)) + envVarItems := []string{} + + maxLongNameLength := 0 + for _, opt := range defs { + if maxLongNameLength < len(opt.LongName) { + maxLongNameLength = len(opt.LongName) + } + } + indent := " " + + longNameFormat := "%-" + fmt.Sprintf("%ds", maxLongNameLength) + for i, opt := range defs { + var item string + if opt.ShortName == "" { + item = fmt.Sprintf("%s "+longNameFormat, indent, opt.LongName) + } else { + item = fmt.Sprintf("%s%s, "+longNameFormat, indent, opt.ShortName, opt.LongName) + } + item += " " + opt.GetHelp() + if getter := opt.GetGetter(); getter != nil { + item += fmt.Sprintf(" (default: %s)", getter(defaultOptions)) + } + optionItems[i] = item + + if !opt.GetWithoutEnv() { + envVarItems = append(envVarItems, fmt.Sprintf(longNameFormat+" %s", opt.LongName, opt.EnvKey())) + } + } + return optionItems, envVarItems +} From 1961c3cd7a0c3373394b2fc3435c01b468762295 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:39:43 +0900 Subject: [PATCH 39/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20opts.Facto?= =?UTF-8?q?ry=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- options.go | 54 +++++++++++-------------------------------------- opts/factory.go | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 42 deletions(-) create mode 100644 opts/factory.go diff --git a/options.go b/options.go index c8137e8..16723dd 100644 --- a/options.go +++ b/options.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/akm/git-exec/git" "github.com/akm/git-exec/opts" ) @@ -33,78 +31,50 @@ var defaultOptions = &Options{ } var optionTypes = func() []*opts.Definition[Options] { - boolToString := func(b bool) string { - if b { - return "true" - } else { - return "false" - } - } - quote := func(s string) string { - return fmt.Sprintf("%q", s) - } - - envKeyPrefix := "GIT_EXEC_" - boolOpt := func(shortName, longName string, help string, getter func(*Options) bool, setter func(*Options)) *opts.Definition[Options] { - var actualGetter func(o *Options) string - if getter != nil { - actualGetter = func(o *Options) string { return boolToString(getter(o)) } - } - return opts.NewDefinition(envKeyPrefix, shortName, longName, false, - func(o *Options, v string) { setter(o) }). - Getter(actualGetter).Help(help) - } - strOpt := func(shortName, longName string, help string, getter func(*Options) string, setter func(*Options, string)) *opts.Definition[Options] { - var actualGetter func(o *Options) string - if getter != nil { - actualGetter = func(o *Options) string { return quote(getter(o)) } - } - return opts.NewDefinition(envKeyPrefix, shortName, longName, true, setter). - Getter(actualGetter).Help(help) - } + f := opts.NewFactory[Options]("GIT_EXEC_") return []*opts.Definition[Options]{ - strOpt("-C", "--directory", "Specify the directory where the command is executed.", + f.String("-C", "--directory", "Specify the directory where the command is executed.", func(o *Options) string { return o.Directory }, func(o *Options, v string) { o.Directory = v }, ).WithoutEnv(), - strOpt("-e", "--emoji", "Specify the emoji used in commit message.", + f.String("-e", "--emoji", "Specify the emoji used in commit message.", func(o *Options) string { return o.Emoji }, func(o *Options, v string) { o.Emoji = v }, ), - strOpt("-p", "--prompt", "Specify the prompt used in commit message.", + f.String("-p", "--prompt", "Specify the prompt used in commit message.", func(o *Options) string { return o.Prompt }, func(o *Options, v string) { o.Prompt = v }, ), - strOpt("-t", "--template", "Specify the template to build commit message.", + f.String("-t", "--template", "Specify the template to build commit message.", func(o *Options) string { return o.Template }, func(o *Options, v string) { o.Template = v }, ), - boolOpt("", "--skip-guard", "Skip the guard check for uncommitted changes and untracked files before executing command.", + f.Bool("", "--skip-guard", "Skip the guard check for uncommitted changes and untracked files before executing command.", func(o *Options) bool { return o.SkipGuard }, func(o *Options) { o.SkipGuard = true }, ), - boolOpt("", "--skip-guard-uncommitted-changes", "Skip the guard check for uncommitted changes before executing command.", + f.Bool("", "--skip-guard-uncommitted-changes", "Skip the guard check for uncommitted changes before executing command.", func(o *Options) bool { return o.SkipGuardUncommittedChanges }, func(o *Options) { o.SkipGuardUncommittedChanges = true }, ), - boolOpt("", "--skip-guard-untracked-files", "Skip the guard check for untracked files before executing command.", + f.Bool("", "--skip-guard-untracked-files", "Skip the guard check for untracked files before executing command.", func(o *Options) bool { return o.SkipGuardUntrackedFiles }, func(o *Options) { o.SkipGuardUntrackedFiles = true }, ), - boolOpt("-D", "--debug-log", "Output debug log.", + f.Bool("-D", "--debug-log", "Output debug log.", func(o *Options) bool { return o.DebugLog }, func(o *Options) { o.DebugLog = true }, ), - boolOpt("-i", "--interactive", "Interactive mode for command which requires input. tmux is required to use.", + f.Bool("-i", "--interactive", "Interactive mode for command which requires input. tmux is required to use.", func(o *Options) bool { return o.Interactive }, func(o *Options) { o.Interactive = true }, ), - boolOpt("-h", "--help", "Show this message.", nil, func(o *Options) { o.Help = true }).WithoutEnv(), - boolOpt("-v", "--version", "Show version.", nil, func(o *Options) { o.Version = true }).WithoutEnv(), + f.Bool("-h", "--help", "Show this message.", nil, func(o *Options) { o.Help = true }).WithoutEnv(), + f.Bool("-v", "--version", "Show version.", nil, func(o *Options) { o.Version = true }).WithoutEnv(), } }() diff --git a/opts/factory.go b/opts/factory.go new file mode 100644 index 0000000..c5c656e --- /dev/null +++ b/opts/factory.go @@ -0,0 +1,43 @@ +package opts + +import "fmt" + +type Factory[T any] struct { + envKeyPrefix string + + boolToString func(bool) string + quote func(string) string +} + +func NewFactory[T any](envKeyPrefix string) *Factory[T] { + return &Factory[T]{ + envKeyPrefix: envKeyPrefix, + boolToString: func(b bool) string { + if b { + return "true" + } else { + return "false" + } + }, + quote: func(s string) string { return fmt.Sprintf("%q", s) }, + } +} + +func (f *Factory[T]) Bool(shortName, longName string, help string, getter func(*T) bool, setter func(*T)) *Definition[T] { + var actualGetter func(o *T) string + if getter != nil { + actualGetter = func(o *T) string { return f.boolToString(getter(o)) } + } + return NewDefinition(f.envKeyPrefix, shortName, longName, false, + func(o *T, v string) { setter(o) }). + Getter(actualGetter).Help(help) +} + +func (f *Factory[T]) String(shortName, longName string, help string, getter func(*T) string, setter func(*T, string)) *Definition[T] { + var actualGetter func(o *T) string + if getter != nil { + actualGetter = func(o *T) string { return f.quote(getter(o)) } + } + return NewDefinition(f.envKeyPrefix, shortName, longName, true, setter). + Getter(actualGetter).Help(help) +} From 93c8a9dfd6d3428018b737f16ffb12a9f8a5269a Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:47:14 +0900 Subject: [PATCH 40/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20process=20f?= =?UTF-8?q?unction=20to=20Run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 8b505de..f578801 100644 --- a/main.go +++ b/main.go @@ -32,13 +32,13 @@ func main() { } } - if err := process(options, commandArgs); err != nil { + if err := Run(options, commandArgs); err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } } -func process(options *Options, commandArgs []string) error { +func Run(options *Options, commandArgs []string) error { var guardMessage string if guardResult, err := git.Guard(&options.GuardOptions); err != nil { return err From efc4b2aef3c26e0fa1c6c08e3c98b7da8697ca1d Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:50:51 +0900 Subject: [PATCH 41/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20run.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 85 ----------------------------------------------------- run.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 85 deletions(-) create mode 100644 run.go diff --git a/main.go b/main.go index f578801..880b720 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,8 @@ package main import ( "fmt" - "log/slog" "os" "path/filepath" - - "github.com/akm/git-exec/command" - "github.com/akm/git-exec/git" ) func main() { @@ -37,84 +33,3 @@ func main() { os.Exit(1) } } - -func Run(options *Options, commandArgs []string) error { - var guardMessage string - if guardResult, err := git.Guard(&options.GuardOptions); err != nil { - return err - } else if guardResult != nil { - if guardResult.Skipped { - guardMessage = guardResult.Format() - fmt.Fprintf(os.Stderr, "Guard skipped: %s\n", guardMessage) - } else { - return fmt.Errorf("Quit processing because %s", guardResult.Format()) - } - } - - cmd := command.NewCommand(commandArgs) - var runner command.Runner - if options.Interactive { - runner = command.NewTmuxRunner(options.DebugLog) - } else { - runner = command.NewStandardRunner(options.DebugLog) - } - - var commitMessage *commitMessage - if err := changeDir((options.Directory), func() error { - if err := runner.Run(cmd); err != nil { - slog.Error("Command execution failed", "error", err) - return fmt.Errorf("Command execution failed: %+v\n%s", err, cmd.Output) - } - commitMessage = newCommitMessage(cmd, options) - return nil - }); err != nil { - return err - } - - if err := git.Add(); err != nil { - return err - } - - if guardMessage != "" { - commitMessage.Body = guardMessage + "\n\n" + commitMessage.Body - } - - // 3. "git commit" を以下のオプションと標準力を指定して実行する。 - msg, err := commitMessage.Build() - if err != nil { - return fmt.Errorf("Failed to build commit message: %+v", err) - } - - if err := git.Commit(msg); err != nil { - return err - } - - return nil -} - -func changeDir(dir string, cb func() error) (rerr error) { - if dir == "" { - return cb() - } - var origDir string - if dir != "" { - { - var err error - origDir, err = os.Getwd() - if err != nil { - return fmt.Errorf("Failed to get current directory: %s", err.Error()) - } - } - if err := os.Chdir(dir); err != nil { - return fmt.Errorf("Failed to change directory: %s", err.Error()) - } - } - if origDir != "" { - defer func() { - if err := os.Chdir(origDir); err != nil { - rerr = fmt.Errorf("Failed to change directory: %s", err.Error()) - } - }() - } - return cb() -} diff --git a/run.go b/run.go new file mode 100644 index 0000000..de7369b --- /dev/null +++ b/run.go @@ -0,0 +1,91 @@ +package main + +import ( + "fmt" + "log/slog" + "os" + + "github.com/akm/git-exec/command" + "github.com/akm/git-exec/git" +) + +func Run(options *Options, commandArgs []string) error { + var guardMessage string + if guardResult, err := git.Guard(&options.GuardOptions); err != nil { + return err + } else if guardResult != nil { + if guardResult.Skipped { + guardMessage = guardResult.Format() + fmt.Fprintf(os.Stderr, "Guard skipped: %s\n", guardMessage) + } else { + return fmt.Errorf("Quit processing because %s", guardResult.Format()) + } + } + + cmd := command.NewCommand(commandArgs) + var runner command.Runner + if options.Interactive { + runner = command.NewTmuxRunner(options.DebugLog) + } else { + runner = command.NewStandardRunner(options.DebugLog) + } + + var commitMessage *commitMessage + if err := changeDir((options.Directory), func() error { + if err := runner.Run(cmd); err != nil { + slog.Error("Command execution failed", "error", err) + return fmt.Errorf("Command execution failed: %+v\n%s", err, cmd.Output) + } + commitMessage = newCommitMessage(cmd, options) + return nil + }); err != nil { + return err + } + + if err := git.Add(); err != nil { + return err + } + + if guardMessage != "" { + commitMessage.Body = guardMessage + "\n\n" + commitMessage.Body + } + + // 3. "git commit" を以下のオプションと標準力を指定して実行する。 + msg, err := commitMessage.Build() + if err != nil { + return fmt.Errorf("Failed to build commit message: %+v", err) + } + + if err := git.Commit(msg); err != nil { + return err + } + + return nil +} + +func changeDir(dir string, cb func() error) (rerr error) { + if dir == "" { + return cb() + } + var origDir string + if dir != "" { + { + var err error + origDir, err = os.Getwd() + if err != nil { + return fmt.Errorf("Failed to get current directory: %s", err.Error()) + } + } + if err := os.Chdir(dir); err != nil { + return fmt.Errorf("Failed to change directory: %s", err.Error()) + } + } + if origDir != "" { + defer func() { + if err := os.Chdir(origDir); err != nil { + rerr = fmt.Errorf("Failed to change directory: %s", err.Error()) + } + }() + } + return cb() +} From 58402d1e76174818ee9e6f084b8774aeb65fc0d6 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:54:19 +0900 Subject: [PATCH 42/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20parseOption?= =?UTF-8?q?s=20function=20to=20ParseOptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 2 +- options.go | 2 +- options_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 880b720..f291920 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ func main() { os.Exit(1) } - options, commandArgs, err := parseOptions(os.Args[1:]) + options, commandArgs, err := ParseOptions(os.Args[1:]) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse arguments: %s\n", err.Error()) } diff --git a/options.go b/options.go index 16723dd..3d5d80e 100644 --- a/options.go +++ b/options.go @@ -82,6 +82,6 @@ func newOptions() *Options { return opts.NewOptions(optionTypes, defaultOptions) } -func parseOptions(args []string) (*Options, []string, error) { +func ParseOptions(args []string) (*Options, []string, error) { return opts.Parse(defaultOptions, optionTypes, args...) } diff --git a/options_test.go b/options_test.go index 1ca1d44..aa0c011 100644 --- a/options_test.go +++ b/options_test.go @@ -189,7 +189,7 @@ func TestParseOptions(t *testing.T) { defer func() { os.Setenv(key, envBackup) }() } - options, commandArgs, err := parseOptions(ptn.args) + options, commandArgs, err := ParseOptions(ptn.args) assert.Equal(t, ptn.options, options) assert.Equal(t, ptn.commandArgs, commandArgs) if ptn.error == "" { From 8724ed584d33fb67eddf150c35974e5d5d07add6 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:54:48 +0900 Subject: [PATCH 43/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Rename=20help=20func?= =?UTF-8?q?tion=20to=20Help?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- help.go | 2 +- main.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/help.go b/help.go index 1997fe5..ed12fce 100644 --- a/help.go +++ b/help.go @@ -7,7 +7,7 @@ import ( "github.com/akm/git-exec/opts" ) -func help() { +func Help() { firstLine := `Usage: git-exec [options ...] [key=value ...] [args ...]` examples := `Examples: * Specify environment variables. diff --git a/main.go b/main.go index f291920..06dae0e 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( func main() { if len(os.Args) < 2 { - help() + Help() os.Exit(1) } @@ -17,7 +17,7 @@ func main() { fmt.Fprintf(os.Stderr, "Failed to parse arguments: %s\n", err.Error()) } if options.Help { - help() + Help() os.Exit(0) } else if options.Version { if len(commandArgs) == 0 { From 186e2e3d29d37a238200e4f9871f24cb0e35ead7 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 07:56:42 +0900 Subject: [PATCH 44/45] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Move=20business=20lo?= =?UTF-8?q?gic=20to=20core=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commit_message.go => core/commit_message.go | 2 +- commit_message_test.go => core/commit_message_test.go | 2 +- help.go => core/help.go | 2 +- location.go => core/location.go | 2 +- options.go => core/options.go | 2 +- options_test.go => core/options_test.go | 2 +- run.go => core/run.go | 2 +- main.go | 10 ++++++---- 8 files changed, 13 insertions(+), 11 deletions(-) rename commit_message.go => core/commit_message.go (99%) rename commit_message_test.go => core/commit_message_test.go (99%) rename help.go => core/help.go (98%) rename location.go => core/location.go (98%) rename options.go => core/options.go (99%) rename options_test.go => core/options_test.go (99%) rename run.go => core/run.go (99%) diff --git a/commit_message.go b/core/commit_message.go similarity index 99% rename from commit_message.go rename to core/commit_message.go index bfa1af1..1622aba 100644 --- a/commit_message.go +++ b/core/commit_message.go @@ -1,4 +1,4 @@ -package main +package core import ( "bytes" diff --git a/commit_message_test.go b/core/commit_message_test.go similarity index 99% rename from commit_message_test.go rename to core/commit_message_test.go index 9c15eb3..af90947 100644 --- a/commit_message_test.go +++ b/core/commit_message_test.go @@ -1,4 +1,4 @@ -package main +package core import ( "os" diff --git a/help.go b/core/help.go similarity index 98% rename from help.go rename to core/help.go index ed12fce..0893485 100644 --- a/help.go +++ b/core/help.go @@ -1,4 +1,4 @@ -package main +package core import ( "fmt" diff --git a/location.go b/core/location.go similarity index 98% rename from location.go rename to core/location.go index 7ec9e78..e98ad61 100644 --- a/location.go +++ b/core/location.go @@ -1,4 +1,4 @@ -package main +package core import ( "os" diff --git a/options.go b/core/options.go similarity index 99% rename from options.go rename to core/options.go index 3d5d80e..acbb548 100644 --- a/options.go +++ b/core/options.go @@ -1,4 +1,4 @@ -package main +package core import ( "github.com/akm/git-exec/git" diff --git a/options_test.go b/core/options_test.go similarity index 99% rename from options_test.go rename to core/options_test.go index aa0c011..d71cd0f 100644 --- a/options_test.go +++ b/core/options_test.go @@ -1,4 +1,4 @@ -package main +package core import ( "fmt" diff --git a/run.go b/core/run.go similarity index 99% rename from run.go rename to core/run.go index de7369b..2ea8cb5 100644 --- a/run.go +++ b/core/run.go @@ -1,4 +1,4 @@ -package main +package core import ( "fmt" diff --git a/main.go b/main.go index 06dae0e..321778a 100644 --- a/main.go +++ b/main.go @@ -4,20 +4,22 @@ import ( "fmt" "os" "path/filepath" + + "github.com/akm/git-exec/core" ) func main() { if len(os.Args) < 2 { - Help() + core.Help() os.Exit(1) } - options, commandArgs, err := ParseOptions(os.Args[1:]) + options, commandArgs, err := core.ParseOptions(os.Args[1:]) if err != nil { fmt.Fprintf(os.Stderr, "Failed to parse arguments: %s\n", err.Error()) } if options.Help { - Help() + core.Help() os.Exit(0) } else if options.Version { if len(commandArgs) == 0 { @@ -28,7 +30,7 @@ func main() { } } - if err := Run(options, commandArgs); err != nil { + if err := core.Run(options, commandArgs); err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } From f1069c33ce907b6d3185582347d3339dc413044c Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 8 Dec 2024 08:04:29 +0900 Subject: [PATCH 45/45] =?UTF-8?q?=F0=9F=8E=89=20Bump=20up=20from=200.1.1?= =?UTF-8?q?=20to=200.1.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 627e791..f1b6067 100644 --- a/version.go +++ b/version.go @@ -2,7 +2,7 @@ package main import "fmt" -const Version = "0.1.1" +const Version = "0.1.2" func showVersion() { fmt.Println(Version)