From 18f5453e17522cefbfd05f3337aec75359367549 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 13:53:51 -0500 Subject: [PATCH 01/43] Add Implement in Go --- doc/decisions.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/decisions.md b/doc/decisions.md index f8231bda..e2994a73 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -23,7 +23,9 @@ Repo Management Tool, or "marmot" for short. shell commands for a category of repositories as if they are all part of a single unit. - Store meta data about categories externally, instead of in the Git repositories themselves. -## 01: Target Z Shell +## 01: ~~Target Z Shell~~ + +Superseded by: [Implement in Go](#06-implement-in-go). Implement marmot in *nix tools that are widely-available on the platforms I use - e.g. MacOS, Linux, and Windows Subsystem for Linux. Writing it in Z Shell can make it easier to try new ideas, while @@ -119,3 +121,28 @@ Source: to `source` dependencies and transitive dependencies. - This is approach is intended to avoid any complexities in the same code being sourced twice. I have no idea what could happen then, and I'd rather not have to find out. + +## 06: Implement in Go + +Supersedes: [Target Z Shell](#01-target-z-shell). + +Compartmentalizing and organizing scripts helped with maintenance and extension, but it still became +difficult to split machine- and repository-specific data into separate files. Use of an external +data migration script provided a limited means to detect bugs by including some semi-formal test +automation, but it relied heavily upon the development platform; e.g. it used real Git repositories +on specific paths. This approach did not offer a sufficiently-granular approach to testing, and +prior experiences with formal testing tools–i.e. +[`bats`](https://github.com/sstephenson/bats)–proved impractical for team sizes greater than one. + +These factors led to some thinking about which language could replace the shell scripts. It would +need to be capable of targeting the same platforms, while offering a better means to structure data, +look up references, and refactor call sites. It would also need robust tools for test automation +and for creating Command Line Interfaces. Go offers all of those, while currently being a bit +easier to deploy to end users than Python or Ruby. Go also has potentially-compelling libraries +such as [`bubbletea`](https://github.com/charmbracelet/bubbletea), which raises the possibility of +making `marmot` more interactive and easier to use. + +### Decisions + +- Sprout a new codebase written in Go, until it has enough features to replace the ZSH version. +- Automate tests on core logic; e.g. "test from the middle". From 59de921e775d9f8f3527c78af3298fe5d4d697fe Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 14:55:29 -0500 Subject: [PATCH 02/43] Add Go package structure --- doc/decisions.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/doc/decisions.md b/doc/decisions.md index e2994a73..28dfb653 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -146,3 +146,55 @@ making `marmot` more interactive and easier to use. - Sprout a new codebase written in Go, until it has enough features to replace the ZSH version. - Automate tests on core logic; e.g. "test from the middle". + +## 07: Go package structure + +Developers will need a safe and effective way to add new entities and CLI commands, in order to add +new features. Distinguishing core entities (e.g. repositories and categories) and behavior (e.g. +categorizing Git repositories) from implementation details (e.g. interaction with the file system) +minimizes the amount of existing code that has to be modified in order to add new entities. It also +offers a practical means to distinguish test automation that is more highly rewarding (e.g. tests on +invariants and core logic, which are easier to write and tend to last longer) from that which is +somewhat less rewarding (e.g. tests on wiring and implementation details, which tend to be harder to +write and are more readily thrown out). + +### Decisions + +Structure Go code along these dimensions: + +- Put all code in one repository. Use Go packages to distinguish the parts. +- Create `core` packages like `corerepository` for basic entities, data structures, and interfaces. +- Create `use` packages like `userepository` for operations upon each context. +- Create `svc` packages like `svcfs` for service implementations, such as using the file system. +- Create `main` package(s) like `mainfactory` to create dependencies and wire everything together. +- Create additional packages such as `corerepositorymock` and `testsupport` as-needed, to separate + test automation code from production code. + +This should lead to package dependencies such as the following: + +```mermaid +graph LR + +%% Core and dependencies +core(core) +svc(svc
Services) +use(use
Use Cases) + +svc --> core +use --> core + +%% Main program +cmd(cmd
CLI) +mainfactory(mainfactory
Factories) + +cmd --> core +cmd --> mainfactory +mainfactory --> use +mainfactory --> svc + +%% Test support +cuke(cuke
Cucumber tests) + +cuke --> core +cuke --> use +``` From bc170b5805415ccc14c1bcc4d24760e48c6de220 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 15:02:16 -0500 Subject: [PATCH 03/43] Annotate --- doc/decisions.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index 28dfb653..e6ecd1f9 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -170,31 +170,34 @@ Structure Go code along these dimensions: - Create additional packages such as `corerepositorymock` and `testsupport` as-needed, to separate test automation code from production code. -This should lead to package dependencies such as the following: +This leads to the following compile-time dependencies among top-level packages: ```mermaid graph LR %% Core and dependencies -core(core) +core(core
Data structures
Service interfaces) svc(svc
Services) use(use
Use Cases) -svc --> core -use --> core +svc -->|implement| core +use -->|CRUD| core %% Main program cmd(cmd
CLI) mainfactory(mainfactory
Factories) +marmot(marmot
main program) cmd --> core cmd --> mainfactory -mainfactory --> use -mainfactory --> svc +mainfactory -->|create| use +mainfactory -->|create| svc +marmot --> cmd +marmot --> mainfactory %% Test support cuke(cuke
Cucumber tests) cuke --> core -cuke --> use +cuke --> mainfactory ``` From c72acedbeecc24902a930c8bb2e736fd4e5905c4 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 15:04:30 -0500 Subject: [PATCH 04/43] Cleanup --- doc/decisions.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index e6ecd1f9..e082d076 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -194,10 +194,4 @@ mainfactory -->|create| use mainfactory -->|create| svc marmot --> cmd marmot --> mainfactory - -%% Test support -cuke(cuke
Cucumber tests) - -cuke --> core -cuke --> mainfactory ``` From 858881ef68ba837e45b8aaf02e177812d4f55f2a Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 16:11:38 -0500 Subject: [PATCH 05/43] Add runtime dependency --- doc/decisions.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index e082d076..707ea4e9 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -180,15 +180,16 @@ core(core
Data structures
Service interfaces) svc(svc
Services) use(use
Use Cases) -svc -->|implement| core +svc -->|CRUD
implement| core use -->|CRUD| core +use -.->|runtime| svc %% Main program cmd(cmd
CLI) mainfactory(mainfactory
Factories) -marmot(marmot
main program) +marmot(marmot
Executable) -cmd --> core +cmd -->|CRUD| core cmd --> mainfactory mainfactory -->|create| use mainfactory -->|create| svc From 8d13600aad133d168684806fd4b402ea957d3db5 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:27:20 -0500 Subject: [PATCH 06/43] Describe test structure --- doc/decisions.md | 110 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index 707ea4e9..6c901d88 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -52,7 +52,7 @@ back, or even share with teammates. ### Decisions - Store meta data in JSON files. -- Use tools like `jq` and `jo` to query and construct JSON data from marmot. +- ~~Use tools like `jq` and `jo` to query and construct JSON data from marmot.~~ - Store meta data in its own Git repository. ## 03: Directory Structure in the Meta Repo @@ -84,7 +84,9 @@ over what changes merit what kind of version bump. - Minor version: Increment when adding a new feature (e.g. a command or sub-command). - Patch version: Increment when refactoring to prepare for another feature. -## 05: Apply Single Responsibility Principle to scripts +## 05: ~~Apply Single Responsibility Principle to scripts~~ + +Superseded by: [Implement in Go](#06-implement-in-go). Scripts are getting more complex, leading to duplication of concepts and algorithms. Applying the Single Responsibility Principle (SRP) can help manage complexity and avoid unnecessary duplication. @@ -130,9 +132,7 @@ Compartmentalizing and organizing scripts helped with maintenance and extension, difficult to split machine- and repository-specific data into separate files. Use of an external data migration script provided a limited means to detect bugs by including some semi-formal test automation, but it relied heavily upon the development platform; e.g. it used real Git repositories -on specific paths. This approach did not offer a sufficiently-granular approach to testing, and -prior experiences with formal testing tools–i.e. -[`bats`](https://github.com/sstephenson/bats)–proved impractical for team sizes greater than one. +on specific paths. These factors led to some thinking about which language could replace the shell scripts. It would need to be capable of targeting the same platforms, while offering a better means to structure data, @@ -142,21 +142,16 @@ easier to deploy to end users than Python or Ruby. Go also has potentially-comp such as [`bubbletea`](https://github.com/charmbracelet/bubbletea), which raises the possibility of making `marmot` more interactive and easier to use. -### Decisions +### Decision -- Sprout a new codebase written in Go, until it has enough features to replace the ZSH version. -- Automate tests on core logic; e.g. "test from the middle". +Sprout a new codebase written in Go, until it has enough features to replace the ZSH version. ## 07: Go package structure Developers will need a safe and effective way to add new entities and CLI commands, in order to add new features. Distinguishing core entities (e.g. repositories and categories) and behavior (e.g. categorizing Git repositories) from implementation details (e.g. interaction with the file system) -minimizes the amount of existing code that has to be modified in order to add new entities. It also -offers a practical means to distinguish test automation that is more highly rewarding (e.g. tests on -invariants and core logic, which are easier to write and tend to last longer) from that which is -somewhat less rewarding (e.g. tests on wiring and implementation details, which tend to be harder to -write and are more readily thrown out). +minimizes the amount of existing code that has to be modified in order to add new entities. ### Decisions @@ -167,10 +162,9 @@ Structure Go code along these dimensions: - Create `use` packages like `userepository` for operations upon each context. - Create `svc` packages like `svcfs` for service implementations, such as using the file system. - Create `main` package(s) like `mainfactory` to create dependencies and wire everything together. -- Create additional packages such as `corerepositorymock` and `testsupport` as-needed, to separate - test automation code from production code. -This leads to the following compile-time dependencies among top-level packages: +This leads to the following dependencies (compile-time; runtime dependencies are dashed lines) among +top-level packages: ```mermaid graph LR @@ -196,3 +190,87 @@ mainfactory -->|create| svc marmot --> cmd marmot --> mainfactory ``` + +## 08: Go test strategy + +As described in [Implement in Go](#06-implement-in-go), using a script-based architecture did not +offer a sufficiently-granular approach to testing. Prior experiences with formal testing tools–i.e. +[`bats`](https://github.com/sstephenson/bats)–proved impractical for team sizes greater than one. + +Another factor involved in [Go package structure](#07-go-package-structure) relates to test +automation: Separating packages by bounded context also offers a practical means to distinguish test +automation that is more highly rewarding from that which is somewhat less rewarding. In other +words, tests on invariants and core logic tend to be easier to write and survive refactoring, while +tests on wiring and implementation details tend to be harder to write and are more readily thrown +out during refactoring. + +### Decisions + +- Focus test automation on core logic; e.g. "test from the middle". +- For small- to medium-sized tests of regular code: + - **Sources**: Co-locate with production code and package as `_test`, according to Go conventions. + - **Support code**: Add `testsupport` packages as necessary. + - **Test doubles**: Create additional `*mock` packages as necessary, such as `corerepositorymock`. + - **Tools**: Use `ginkgo` to clearly describe behavior. +- For medium- to large-sized tests of user-facing features: + - **Sources**: place sources in separate `cuke*` packages. + - **Support code**: Add `cukesupport` as necessary. + - **Tools**: Use `godog` to clearly describe features in Gherkin. + +### Control Flow + +```mermaid +graph LR + +%% Production code: Core and dependencies + +subgraph MarmotCore [Production Code: Functional Core] + core(core
Data structures) + mainfactory(mainfactory
Factories) + svc(svc
Services) + use(use
Use Cases) +end + +svc -.-> core +use -.-> core +use -.-> svc + +%% Tests + +subgraph SmallTests [Small Tests] + direction TB + ginkgotests(_test
Ginkgo tests) + ginkgomocks(*mock
Test doubles) + ginkgosupport(testsupport*
Test support) + + ginkgotests -.-> ginkgomocks + ginkgotests -.-> ginkgosupport +end + +SmallTests -->|verify| svc +SmallTests -->|verify| use + +subgraph LargeTests [Large Tests] + direction LR + godogfeatures(cukefeature
godog scenarios) + godogsteps(cukesteps
Step definitions) + godogsupport(cukesupport
Helpers
Hooks) + + godogfeatures -.-> godogsupport + godogfeatures -.-> godogsteps + godogsteps -.-> godogsupport +end + +LargeTests -->|validate| MarmotCore +``` + +### Not Tested + +```mermaid +graph LR + +subgraph ImperativeShell [Production Code: Imperative Shell] + cmd(cmd
CLI) + marmot(marmot
Executable) +end +``` From 3039412e041c917e48a122a8a87b2d1a6574b55d Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:29:49 -0500 Subject: [PATCH 07/43] Distinguish core and shell --- doc/decisions.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index 6c901d88..d91cbbb2 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -170,27 +170,34 @@ top-level packages: graph LR %% Core and dependencies -core(core
Data structures
Service interfaces) -svc(svc
Services) -use(use
Use Cases) +subgraph FunctionalCore [Functional Core] + core(core
Data structures
Service interfaces) + svc(svc
Services) + use(use
Use Cases) -svc -->|CRUD
implement| core -use -->|CRUD| core -use -.->|runtime| svc + svc -->|CRUD
implement| core + use -->|CRUD| core + use -.->|runtime| svc +end %% Main program -cmd(cmd
CLI) -mainfactory(mainfactory
Factories) -marmot(marmot
Executable) - -cmd -->|CRUD| core -cmd --> mainfactory -mainfactory -->|create| use -mainfactory -->|create| svc -marmot --> cmd -marmot --> mainfactory +subgraph ImperativeShell [Imperative Shell] + cmd(cmd
CLI) + mainfactory(mainfactory
Factories) + marmot(marmot
Executable) + + cmd -->|CRUD| core + cmd --> mainfactory + mainfactory -->|create| use + mainfactory -->|create| svc + marmot --> cmd + marmot --> mainfactory +end ``` +Note: The code in the "functional core" is not always necessarily written in a functional style, +although that's an idea worth considering. + ## 08: Go test strategy As described in [Implement in Go](#06-implement-in-go), using a script-based architecture did not From 683c06cec908e2be5490a3482149c2e03a0ec393 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:37:13 -0500 Subject: [PATCH 08/43] Make more accurate --- doc/decisions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/decisions.md b/doc/decisions.md index d91cbbb2..82f1a8a6 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -187,7 +187,8 @@ subgraph ImperativeShell [Imperative Shell] marmot(marmot
Executable) cmd -->|CRUD| core - cmd --> mainfactory + cmd --> use + %%mainfactory -->|create| cmd mainfactory -->|create| use mainfactory -->|create| svc marmot --> cmd From a609d114b2b099742466b5b38ae99f6eba0e5af0 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:45:04 -0500 Subject: [PATCH 09/43] Organize diagram test code --- doc/decisions.md | 61 +++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/doc/decisions.md b/doc/decisions.md index 82f1a8a6..ef99e930 100644 --- a/doc/decisions.md +++ b/doc/decisions.md @@ -228,48 +228,45 @@ out during refactoring. ### Control Flow ```mermaid -graph LR - -%% Production code: Core and dependencies +graph TB -subgraph MarmotCore [Production Code: Functional Core] +subgraph MarmotCore [Functional Core] + direction LR core(core
Data structures) - mainfactory(mainfactory
Factories) svc(svc
Services) use(use
Use Cases) -end - -svc -.-> core -use -.-> core -use -.-> svc - -%% Tests - -subgraph SmallTests [Small Tests] - direction TB - ginkgotests(_test
Ginkgo tests) - ginkgomocks(*mock
Test doubles) - ginkgosupport(testsupport*
Test support) - ginkgotests -.-> ginkgomocks - ginkgotests -.-> ginkgosupport + svc -.-> core + use -.-> core + use -.-> svc end -SmallTests -->|verify| svc -SmallTests -->|verify| use - -subgraph LargeTests [Large Tests] - direction LR - godogfeatures(cukefeature
godog scenarios) - godogsteps(cukesteps
Step definitions) - godogsupport(cukesupport
Helpers
Hooks) - - godogfeatures -.-> godogsupport - godogfeatures -.-> godogsteps - godogsteps -.-> godogsupport +subgraph Tests + subgraph SmallTests [Small Tests] + direction LR + ginkgotests(_test
Ginkgo tests) + ginkgomocks(*mock
Test doubles) + ginkgosupport(testsupport*
Test support) + + ginkgotests -.-> ginkgomocks + ginkgotests -.-> ginkgosupport + end + + subgraph LargeTests [Large Tests] + direction LR + godogfeatures(cukefeature
godog scenarios) + godogsteps(cukesteps
Step definitions) + godogsupport(cukesupport
Helpers
Hooks) + + godogfeatures -.-> godogsupport + godogfeatures -.-> godogsteps + godogsteps -.-> godogsupport + end end LargeTests -->|validate| MarmotCore +SmallTests -->|verify| svc +SmallTests -->|verify| use ``` ### Not Tested From f2a8f90562ab716ca0000d5f99545c1e43f91876 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:55:33 -0500 Subject: [PATCH 10/43] Clean up dependencies --- src/go/cmd/root_command.go | 4 ++-- src/go/cmdinit/init_command.go | 7 ++++++- src/go/mainfactory/cli_factory.go | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 2fe5fbca..4d0028cd 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -40,9 +40,9 @@ const ( metaRepoGroup = "meta-repo" ) -func AddMetaRepoCommand(child *cobra.Command) { +func AddMetaRepoCommand(child cobra.Command) { child.GroupID = metaRepoGroup - rootCmd.AddCommand(child) + rootCmd.AddCommand(&child) } /* Configuration */ diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 868a6c19..23414174 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -3,6 +3,7 @@ package cmdinit import ( "fmt" + "github.com/kkrull/marmot/cmd" "github.com/kkrull/marmot/usemetarepo" "github.com/spf13/cobra" ) @@ -20,7 +21,11 @@ type initCommand struct { path string } -func (cliCmd *initCommand) ToCobraCommand() *cobra.Command { +func (cliCmd *initCommand) RegisterWithCobra() { + cmd.AddMetaRepoCommand(*cliCmd.toCobraCommand()) +} + +func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo in the configured directory, if none is already present.", RunE: func(cmd *cobra.Command, args []string) error { diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index 8bd86ced..4ef71a70 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -39,7 +39,7 @@ func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { return nil, appFactoryErr } else { initCliCmd := cmdinit.NewInitCommand(initAppCmd, cliFactory.appFactory.MetaRepoPath()) - cmd.AddMetaRepoCommand(initCliCmd.ToCobraCommand()) + initCliCmd.RegisterWithCobra() return rootCmd, nil } } From ccebf718593d52cb78939e769c6b6386ba0f88ae Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:58:40 -0500 Subject: [PATCH 11/43] Avoid initializer fucntions --- src/go/cmd/root_command.go | 40 ++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 4d0028cd..6da1dae7 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -9,7 +9,12 @@ import ( var ( debugFlag *bool - rootCmd = &cobra.Command{ + rootCmd *cobra.Command +) + +// Configure the root command with the given I/O and version identifier, then return for use. +func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.Command { + rootCmd = &cobra.Command{ Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", RunE: func(cmd *cobra.Command, args []string) error { if *debugFlag { @@ -21,16 +26,21 @@ var ( return nil } }, - Short: "Meta Repo Management Tool", - Use: "marmot [--help|--version]", + Short: "Meta Repo Management Tool", + Use: "marmot [--help|--version]", + Version: version, } -) -// Configure the root command with the given I/O and version identifier, then return for use. -func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.Command { + // Flags + debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") + rootCmd.PersistentFlags().Lookup("debug").Hidden = true + + // Groups + rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) + + // I/O rootCmd.SetOut(stdout) rootCmd.SetErr(stderr) - rootCmd.Version = version return rootCmd } @@ -45,22 +55,6 @@ func AddMetaRepoCommand(child cobra.Command) { rootCmd.AddCommand(&child) } -/* Configuration */ - -func init() { - initFlags() - initGroups() -} - -func initFlags() { - debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") - rootCmd.PersistentFlags().Lookup("debug").Hidden = true -} - -func initGroups() { - rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) -} - /* Pseudo-commands */ func printDebug() { From ff694981602a7196f3e312605bed243b95223c2b Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 17:59:46 -0500 Subject: [PATCH 12/43] Add TODO --- src/go/cmd/root_command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 6da1dae7..e44a5ad4 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -31,6 +31,7 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C Version: version, } + //TODO KDK: Add flag for using a different home directory // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true From c04c097963f7e864d3ab4233d7ee8c8cabe816f8 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 18:00:02 -0500 Subject: [PATCH 13/43] Format --- src/go/cmd/root_command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index e44a5ad4..bfae1b0a 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -31,7 +31,7 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C Version: version, } - //TODO KDK: Add flag for using a different home directory + // TODO KDK: Add flag for using a different home directory // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true From 6ab6955db2ab385a426f8e6e9a1dd79ca7495599 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 23:46:17 -0500 Subject: [PATCH 14/43] Case --- src/go/cmdinit/init_command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 23414174..10e7914e 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -36,7 +36,7 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return nil } }, - Short: "initialize a meta repo", + Short: "Initialize a meta repo", Use: "init", } } From dd2f2a5292891448fa9da72d063d2ddd561f8fad Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 23:46:51 -0500 Subject: [PATCH 15/43] Add flag for metaRepoHome --- src/go/cmd/root_command.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index bfae1b0a..94a00454 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -8,8 +8,9 @@ import ( ) var ( - debugFlag *bool - rootCmd *cobra.Command + debugFlag *bool + metaRepoHomeFlag *string + rootCmd *cobra.Command ) // Configure the root command with the given I/O and version identifier, then return for use. @@ -35,6 +36,11 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true + metaRepoHomeFlag = rootCmd.PersistentFlags().String( + "meta-home", + appConfig.MetaRepoHome().DefaultValue(), + "set Marmot meta repo directory", + ) // Groups rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) @@ -60,4 +66,5 @@ func AddMetaRepoCommand(child cobra.Command) { func printDebug() { fmt.Printf("--debug: %v\n", *debugFlag) + fmt.Printf("--meta-home: %v\n", *metaRepoHomeFlag) } From d81545f357d63cdffa9a2604fe7c1519d1f61579 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 23:47:06 -0500 Subject: [PATCH 16/43] Add singleton Config --- src/go/cmd/config.go | 33 +++++++++++++++++++++++++++++++++ src/go/cmd/root_command.go | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 src/go/cmd/config.go diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go new file mode 100644 index 00000000..cbe541c9 --- /dev/null +++ b/src/go/cmd/config.go @@ -0,0 +1,33 @@ +package cmd + +func AppConfig() Config { + return &TheConfig{} +} + +type TheConfig struct{} + +func (config *TheConfig) MetaRepoHome() Setting[string] { + return &StringSetting{ + Def: "/home/me/meta-default", + Val: "/home/me/meta", + } +} + +type StringSetting struct { + Def string + Val string +} + +func (setting *StringSetting) DefaultValue() string { return setting.Def } +func (setting *StringSetting) Value() string { return setting.Val } + +type Config interface { + MetaRepoHome() Setting[string] +} + +type Setting[V Value] interface { + DefaultValue() V + Value() V +} + +type Value interface{ string } diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 94a00454..3beadaa8 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -32,6 +32,8 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C Version: version, } + appConfig := AppConfig() + // TODO KDK: Add flag for using a different home directory // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") From 17f65453704152169a91882305d076d79791b81a Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Tue, 23 Jul 2024 23:55:10 -0500 Subject: [PATCH 17/43] Look up flag --- src/go/cmdinit/init_command.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 10e7914e..051646c4 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -29,6 +29,9 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo in the configured directory, if none is already present.", RunE: func(cmd *cobra.Command, args []string) error { + metaHomeFlag := cmd.Flags().Lookup("meta-home") + fmt.Printf("- meta-home: %s\n", metaHomeFlag.Value) + if runErr := cliCmd.initApp.Run(cliCmd.path); runErr != nil { return fmt.Errorf("failed to initialize meta repo at %s; %w", cliCmd.path, runErr) } else { From 5e814a35e2bb546c3b081ccb577dc2c638d622d5 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 08:50:11 -0500 Subject: [PATCH 18/43] Add godoc --- src/go/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/go/Makefile b/src/go/Makefile index 3795cf1e..7b2df7c4 100644 --- a/src/go/Makefile +++ b/src/go/Makefile @@ -55,8 +55,9 @@ ginkgo-watch: install-tools: go install github.com/go-delve/delve/cmd/dlv@latest go install github.com/onsi/ginkgo/v2/ginkgo - go install mvdan.cc/gofumpt@latest go install github.com/spf13/cobra-cli@latest + go install golang.org/x/tools/cmd/godoc@latest + go install mvdan.cc/gofumpt@latest .PHONY: run run: From b02e5b74fcc50a557c67b7b7f6fe29ae374347dc Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 09:06:46 -0500 Subject: [PATCH 19/43] Debug more --- src/go/cmd/root_command.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 3beadaa8..f4b68a75 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -67,6 +67,7 @@ func AddMetaRepoCommand(child cobra.Command) { /* Pseudo-commands */ func printDebug() { - fmt.Printf("--debug: %v\n", *debugFlag) - fmt.Printf("--meta-home: %v\n", *metaRepoHomeFlag) + fmt.Printf("Flags:\n") + fmt.Printf("- debug [%v]: %v\n", rootCmd.Flags().Lookup("debug").DefValue, *debugFlag) + fmt.Printf("- meta-home [%v]: %v\n", rootCmd.Flags().Lookup("meta-home").DefValue, *metaRepoHomeFlag) } From 47f17c925ffabf95f9df0d725fdcf6308184475d Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 10:27:15 -0500 Subject: [PATCH 20/43] Organize --- src/go/cmd/config.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index cbe541c9..d3f20c6f 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -1,29 +1,33 @@ package cmd +/* Configuration */ + func AppConfig() Config { - return &TheConfig{} + return &theConfig{} +} + +type Config interface { + MetaRepoHome() Setting[string] } -type TheConfig struct{} +type theConfig struct{} -func (config *TheConfig) MetaRepoHome() Setting[string] { +func (config *theConfig) MetaRepoHome() Setting[string] { return &StringSetting{ Def: "/home/me/meta-default", Val: "/home/me/meta", } } +/* Settings */ + type StringSetting struct { Def string Val string } -func (setting *StringSetting) DefaultValue() string { return setting.Def } -func (setting *StringSetting) Value() string { return setting.Val } - -type Config interface { - MetaRepoHome() Setting[string] -} +func (setting StringSetting) DefaultValue() string { return setting.Def } +func (setting StringSetting) Value() string { return setting.Val } type Setting[V Value] interface { DefaultValue() V From 363950c65f8b51035fdd62deae30ead6494f9fb9 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 10:45:07 -0500 Subject: [PATCH 21/43] Get path at runtime --- src/go/cmd/root_command.go | 5 ++--- src/go/cmdinit/init_command.go | 26 +++++++++++--------------- src/go/mainfactory/cli_factory.go | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index f4b68a75..44c61fba 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -32,15 +32,14 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C Version: version, } - appConfig := AppConfig() + defaultValues := DefaultGlobalFlags() - // TODO KDK: Add flag for using a different home directory // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true metaRepoHomeFlag = rootCmd.PersistentFlags().String( "meta-home", - appConfig.MetaRepoHome().DefaultValue(), + defaultValues.MetaRepoHome, "set Marmot meta repo directory", ) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 051646c4..3c3ce882 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -8,17 +8,13 @@ import ( "github.com/spf13/cobra" ) -// Construct a CLI command to initialize a meta repo at the specified path -func NewInitCommand(initApp *usemetarepo.InitCommand, metaRepoHome string) *initCommand { - return &initCommand{ - initApp: initApp, - path: metaRepoHome, - } +// Construct a CLI command to initialize a meta repo +func NewInitCommand(initApp *usemetarepo.InitCommand) *initCommand { + return &initCommand{initAppCmd: initApp} } type initCommand struct { - initApp *usemetarepo.InitCommand - path string + initAppCmd *usemetarepo.InitCommand } func (cliCmd *initCommand) RegisterWithCobra() { @@ -27,15 +23,15 @@ func (cliCmd *initCommand) RegisterWithCobra() { func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ - Long: "Initialize a new Meta Repo in the configured directory, if none is already present.", - RunE: func(cmd *cobra.Command, args []string) error { - metaHomeFlag := cmd.Flags().Lookup("meta-home") - fmt.Printf("- meta-home: %s\n", metaHomeFlag.Value) + Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", + RunE: func(cobraCmd *cobra.Command, _args []string) error { + config := cmd.ParseGlobalFlags(cobraCmd) + fmt.Printf("- meta-home: %s\n", config.MetaRepoHome) - if runErr := cliCmd.initApp.Run(cliCmd.path); runErr != nil { - return fmt.Errorf("failed to initialize meta repo at %s; %w", cliCmd.path, runErr) + if runErr := cliCmd.initAppCmd.Run(config.MetaRepoHome); runErr != nil { + return fmt.Errorf("failed to initialize meta repo at %s; %w", config.MetaRepoHome, runErr) } else { - fmt.Printf("Initialized meta repo at %s\n", cliCmd.path) + fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoHome) return nil } }, diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index 4ef71a70..1c5f112c 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -38,7 +38,7 @@ func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { if initAppCmd, appFactoryErr := cliFactory.appFactory.InitCommand(); appFactoryErr != nil { return nil, appFactoryErr } else { - initCliCmd := cmdinit.NewInitCommand(initAppCmd, cliFactory.appFactory.MetaRepoPath()) + initCliCmd := cmdinit.NewInitCommand(initAppCmd) initCliCmd.RegisterWithCobra() return rootCmd, nil } From 2bf9093a087eb588e7e24e4a3d4690d7180333ee Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 10:45:28 -0500 Subject: [PATCH 22/43] Remove unnecessary code --- src/go/cmd/config.go | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index d3f20c6f..9368a269 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -1,37 +1,22 @@ package cmd -/* Configuration */ +import "github.com/spf13/cobra" -func AppConfig() Config { - return &theConfig{} -} - -type Config interface { - MetaRepoHome() Setting[string] -} - -type theConfig struct{} +/* Flags */ -func (config *theConfig) MetaRepoHome() Setting[string] { - return &StringSetting{ - Def: "/home/me/meta-default", - Val: "/home/me/meta", +func DefaultGlobalFlags() *GlobalConfig { + return &GlobalConfig{ + MetaRepoHome: "/home/me/meta-default", } } -/* Settings */ - -type StringSetting struct { - Def string - Val string +func ParseGlobalFlags(cmd *cobra.Command) *GlobalConfig { + metaHomeFlag := cmd.Flags().Lookup("meta-home") + return &GlobalConfig{ + MetaRepoHome: metaHomeFlag.Value.String(), + } } -func (setting StringSetting) DefaultValue() string { return setting.Def } -func (setting StringSetting) Value() string { return setting.Val } - -type Setting[V Value] interface { - DefaultValue() V - Value() V +type GlobalConfig struct { + MetaRepoHome string } - -type Value interface{ string } From 312027dd985227e6a0de424ff7e82deb28ebd5ec Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 10:55:45 -0500 Subject: [PATCH 23/43] Move path information out of AppFactory --- src/go/main.go | 27 ++++++++++++++++++++++++++- src/go/mainfactory/app_factory.go | 29 ----------------------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/go/main.go b/src/go/main.go index b94dd41f..d57a79b5 100644 --- a/src/go/main.go +++ b/src/go/main.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "os" + "path/filepath" "github.com/kkrull/marmot/mainfactory" ) @@ -21,7 +22,7 @@ func main() { } func doMain() error { - if appFactory, appErr := mainfactory.DefaultAppFactory(); appErr != nil { + if appFactory, appErr := defaultAppFactory(); appErr != nil { return appErr } else if cliFactory, cliErr := newCliFactory(appFactory); cliErr != nil { return cliErr @@ -34,6 +35,30 @@ func doMain() error { } } +/* App factory */ + +func defaultAppFactory() (*mainfactory.AppFactory, error) { + if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + return nil, pathErr + } else { + return newAppFactory().ForLocalMetaRepo(metaRepoPath), nil + } +} + +func newAppFactory() *mainfactory.AppFactory { + return &mainfactory.AppFactory{} +} + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } +} + +/* CLI factory */ + func newCliFactory(appFactory *mainfactory.AppFactory) (*mainfactory.CliFactory, error) { return mainfactory. NewCliFactory(appFactory). diff --git a/src/go/mainfactory/app_factory.go b/src/go/mainfactory/app_factory.go index aadc424f..f94695e5 100644 --- a/src/go/mainfactory/app_factory.go +++ b/src/go/mainfactory/app_factory.go @@ -2,9 +2,6 @@ package mainfactory import ( "errors" - "fmt" - "os" - "path/filepath" "github.com/kkrull/marmot/coremetarepo" "github.com/kkrull/marmot/corerepository" @@ -13,44 +10,18 @@ import ( repository "github.com/kkrull/marmot/userepository" ) -func DefaultAppFactory() (*AppFactory, error) { - if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { - return nil, pathErr - } else { - return newAppFactory().ForLocalMetaRepo(metaRepoPath), nil - } -} - -func newAppFactory() *AppFactory { - return &AppFactory{} -} - -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } -} - // Constructs application commands and queries with configurable services. type AppFactory struct { MetaDataAdmin coremetarepo.MetaDataAdmin - metaRepoPath string RepositorySource corerepository.RepositorySource } // Configure a local, file-based meta repo at the specified path func (factory *AppFactory) ForLocalMetaRepo(metaRepoPath string) *AppFactory { - factory.metaRepoPath = metaRepoPath factory.RepositorySource = svcfs.NewJsonMetaRepo(metaRepoPath) return factory } -func (factory *AppFactory) MetaRepoPath() string { - return factory.metaRepoPath -} - /* Administration */ func (factory *AppFactory) InitCommand() (*metarepo.InitCommand, error) { From 63f9d2f838f0b9820cb22863179d2cb2af96b133 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 10:56:42 -0500 Subject: [PATCH 24/43] Update error messages --- src/go/mainfactory/app_factory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/go/mainfactory/app_factory.go b/src/go/mainfactory/app_factory.go index f94695e5..90d0a13d 100644 --- a/src/go/mainfactory/app_factory.go +++ b/src/go/mainfactory/app_factory.go @@ -36,7 +36,7 @@ func (factory *AppFactory) InitCommand() (*metarepo.InitCommand, error) { func (factory *AppFactory) ListRemoteRepositoriesQuery() (repository.ListRemoteRepositoriesQuery, error) { if factory.RepositorySource == nil { - return nil, errors.New("CommandFactory: missing RepositorySource") + return nil, errors.New("AppFactory: missing RepositorySource") } return factory.RepositorySource.ListRemote, nil @@ -46,7 +46,7 @@ func (factory *AppFactory) RegisterRemoteRepositoriesCommand() ( *repository.RegisterRemoteRepositoriesCommand, error, ) { if factory.RepositorySource == nil { - return nil, errors.New("CommandFactory: missing RepositorySource") + return nil, errors.New("AppFactory: missing RepositorySource") } return &repository.RegisterRemoteRepositoriesCommand{Source: factory.RepositorySource}, nil From 307a98ce6335b82d64af78c05bfe4f0409055f8d Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:01:07 -0500 Subject: [PATCH 25/43] Inline --- src/go/mainfactory/cli_factory.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index 1c5f112c..d0c868c7 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -38,8 +38,9 @@ func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { if initAppCmd, appFactoryErr := cliFactory.appFactory.InitCommand(); appFactoryErr != nil { return nil, appFactoryErr } else { - initCliCmd := cmdinit.NewInitCommand(initAppCmd) - initCliCmd.RegisterWithCobra() + cmdinit. + NewInitCommand(initAppCmd). + RegisterWithCobra() return rootCmd, nil } } From cc5a82efaeedae876d3f64e84890375c5fdaf288 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:08:32 -0500 Subject: [PATCH 26/43] Remove unnecessary code --- src/go/cmd/config.go | 22 ---------------------- src/go/cmd/root_command.go | 4 +--- src/go/cmdinit/init_command.go | 11 ++++++----- 3 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 src/go/cmd/config.go diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go deleted file mode 100644 index 9368a269..00000000 --- a/src/go/cmd/config.go +++ /dev/null @@ -1,22 +0,0 @@ -package cmd - -import "github.com/spf13/cobra" - -/* Flags */ - -func DefaultGlobalFlags() *GlobalConfig { - return &GlobalConfig{ - MetaRepoHome: "/home/me/meta-default", - } -} - -func ParseGlobalFlags(cmd *cobra.Command) *GlobalConfig { - metaHomeFlag := cmd.Flags().Lookup("meta-home") - return &GlobalConfig{ - MetaRepoHome: metaHomeFlag.Value.String(), - } -} - -type GlobalConfig struct { - MetaRepoHome string -} diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 44c61fba..672abee9 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -32,14 +32,12 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C Version: version, } - defaultValues := DefaultGlobalFlags() - // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true metaRepoHomeFlag = rootCmd.PersistentFlags().String( "meta-home", - defaultValues.MetaRepoHome, + "/home/me/meta-default", "set Marmot meta repo directory", ) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 3c3ce882..9e51c251 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -25,13 +25,14 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", RunE: func(cobraCmd *cobra.Command, _args []string) error { - config := cmd.ParseGlobalFlags(cobraCmd) - fmt.Printf("- meta-home: %s\n", config.MetaRepoHome) + metaHomeFlag := cobraCmd.Flags().Lookup("meta-home") + metaHomePath := metaHomeFlag.Value.String() + fmt.Printf("[init_command] meta-home: %s\n", metaHomePath) - if runErr := cliCmd.initAppCmd.Run(config.MetaRepoHome); runErr != nil { - return fmt.Errorf("failed to initialize meta repo at %s; %w", config.MetaRepoHome, runErr) + if runErr := cliCmd.initAppCmd.Run(metaHomePath); runErr != nil { + return fmt.Errorf("failed to initialize meta repo at %s; %w", metaHomePath, runErr) } else { - fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoHome) + fmt.Printf("Initialized meta repo at %s\n", metaHomePath) return nil } }, From 6c4bbf1049521d92f07a137d31462e0bd98f6d22 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:17:35 -0500 Subject: [PATCH 27/43] Sort --- src/go/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/go/main.go b/src/go/main.go index d57a79b5..150ae7ca 100644 --- a/src/go/main.go +++ b/src/go/main.go @@ -45,10 +45,6 @@ func defaultAppFactory() (*mainfactory.AppFactory, error) { } } -func newAppFactory() *mainfactory.AppFactory { - return &mainfactory.AppFactory{} -} - func defaultMetaRepoPath() (string, error) { if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { return "", fmt.Errorf("failed to locate home directory; %w", homeErr) @@ -57,6 +53,10 @@ func defaultMetaRepoPath() (string, error) { } } +func newAppFactory() *mainfactory.AppFactory { + return &mainfactory.AppFactory{} +} + /* CLI factory */ func newCliFactory(appFactory *mainfactory.AppFactory) (*mainfactory.CliFactory, error) { From eccbe273b8b540099da26bcf4fda3db3dba77313 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:38:58 -0500 Subject: [PATCH 28/43] DRY --- src/go/mainfactory/app_factory.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/go/mainfactory/app_factory.go b/src/go/mainfactory/app_factory.go index 90d0a13d..274b2371 100644 --- a/src/go/mainfactory/app_factory.go +++ b/src/go/mainfactory/app_factory.go @@ -25,29 +25,33 @@ func (factory *AppFactory) ForLocalMetaRepo(metaRepoPath string) *AppFactory { /* Administration */ func (factory *AppFactory) InitCommand() (*metarepo.InitCommand, error) { - if factory.MetaDataAdmin == nil { - factory.MetaDataAdmin = svcfs.NewJsonMetaRepoAdmin() - } - return &metarepo.InitCommand{MetaDataAdmin: factory.MetaDataAdmin}, nil } /* Repositories */ func (factory *AppFactory) ListRemoteRepositoriesQuery() (repository.ListRemoteRepositoriesQuery, error) { - if factory.RepositorySource == nil { - return nil, errors.New("AppFactory: missing RepositorySource") + if repositorySource, err := factory.repositorySource(); err != nil { + return nil, err + } else { + return repositorySource.ListRemote, nil } - - return factory.RepositorySource.ListRemote, nil } func (factory *AppFactory) RegisterRemoteRepositoriesCommand() ( *repository.RegisterRemoteRepositoriesCommand, error, ) { + if repositorySource, err := factory.repositorySource(); err != nil { + return nil, err + } else { + return &repository.RegisterRemoteRepositoriesCommand{Source: repositorySource}, nil + } +} + +func (factory *AppFactory) repositorySource() (corerepository.RepositorySource, error) { if factory.RepositorySource == nil { return nil, errors.New("AppFactory: missing RepositorySource") + } else { + return factory.RepositorySource, nil } - - return &repository.RegisterRemoteRepositoriesCommand{Source: factory.RepositorySource}, nil } From a657026370773a1885b1dfda7c11af9ecf51f5ca Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:57:47 -0500 Subject: [PATCH 29/43] Move path for now --- src/go/cmd/root_command.go | 11 ++--------- src/go/cmdinit/init_command.go | 22 +++++++++++++++------- src/go/main.go | 33 +++------------------------------ 3 files changed, 20 insertions(+), 46 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 672abee9..15f39163 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -8,9 +8,8 @@ import ( ) var ( - debugFlag *bool - metaRepoHomeFlag *string - rootCmd *cobra.Command + debugFlag *bool + rootCmd *cobra.Command ) // Configure the root command with the given I/O and version identifier, then return for use. @@ -35,11 +34,6 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true - metaRepoHomeFlag = rootCmd.PersistentFlags().String( - "meta-home", - "/home/me/meta-default", - "set Marmot meta repo directory", - ) // Groups rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) @@ -66,5 +60,4 @@ func AddMetaRepoCommand(child cobra.Command) { func printDebug() { fmt.Printf("Flags:\n") fmt.Printf("- debug [%v]: %v\n", rootCmd.Flags().Lookup("debug").DefValue, *debugFlag) - fmt.Printf("- meta-home [%v]: %v\n", rootCmd.Flags().Lookup("meta-home").DefValue, *metaRepoHomeFlag) } diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 9e51c251..87026bc0 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -2,6 +2,8 @@ package cmdinit import ( "fmt" + "os" + "path/filepath" "github.com/kkrull/marmot/cmd" "github.com/kkrull/marmot/usemetarepo" @@ -25,14 +27,12 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", RunE: func(cobraCmd *cobra.Command, _args []string) error { - metaHomeFlag := cobraCmd.Flags().Lookup("meta-home") - metaHomePath := metaHomeFlag.Value.String() - fmt.Printf("[init_command] meta-home: %s\n", metaHomePath) - - if runErr := cliCmd.initAppCmd.Run(metaHomePath); runErr != nil { - return fmt.Errorf("failed to initialize meta repo at %s; %w", metaHomePath, runErr) + if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + return pathErr + } else if runErr := cliCmd.initAppCmd.Run(metaRepoPath); runErr != nil { + return runErr } else { - fmt.Printf("Initialized meta repo at %s\n", metaHomePath) + fmt.Printf("Initialized meta repo at %s\n", metaRepoPath) return nil } }, @@ -40,3 +40,11 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { Use: "init", } } + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } +} diff --git a/src/go/main.go b/src/go/main.go index 150ae7ca..de58df37 100644 --- a/src/go/main.go +++ b/src/go/main.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "os" - "path/filepath" "github.com/kkrull/marmot/mainfactory" ) @@ -22,9 +21,7 @@ func main() { } func doMain() error { - if appFactory, appErr := defaultAppFactory(); appErr != nil { - return appErr - } else if cliFactory, cliErr := newCliFactory(appFactory); cliErr != nil { + if cliFactory, cliErr := newCliFactory(); cliErr != nil { return cliErr } else if rootCmd, buildErr := cliFactory.CommandTree(); buildErr != nil { return buildErr @@ -35,33 +32,9 @@ func doMain() error { } } -/* App factory */ - -func defaultAppFactory() (*mainfactory.AppFactory, error) { - if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { - return nil, pathErr - } else { - return newAppFactory().ForLocalMetaRepo(metaRepoPath), nil - } -} - -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } -} - -func newAppFactory() *mainfactory.AppFactory { - return &mainfactory.AppFactory{} -} - -/* CLI factory */ - -func newCliFactory(appFactory *mainfactory.AppFactory) (*mainfactory.CliFactory, error) { +func newCliFactory() (*mainfactory.CliFactory, error) { return mainfactory. - NewCliFactory(appFactory). + NewCliFactory(). WithStdIO(stdout, stderr). ForExecutable() } From 8031735ec3025f1822254a444450cf2c67f8a7af Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:58:32 -0500 Subject: [PATCH 30/43] Make AppFactory differently --- src/go/cukestep/meta_repo_steps.go | 2 +- src/go/cukestep/repository_steps.go | 5 +++-- src/go/mainfactory/app_factory.go | 9 ++++++--- .../register_remote_repositories_command_test.go | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/go/cukestep/meta_repo_steps.go b/src/go/cukestep/meta_repo_steps.go index 71604bb7..521d1bf4 100644 --- a/src/go/cukestep/meta_repo_steps.go +++ b/src/go/cukestep/meta_repo_steps.go @@ -17,7 +17,7 @@ func AddMetaRepoSteps(ctx *godog.ScenarioContext) { /* Steps */ func initNewMetaRepo(ctx *godog.ScenarioContext) error { - factory := &main.AppFactory{} + factory := main.NewAppFactory() if initCmd, factoryErr := factory.InitCommand(); factoryErr != nil { return fmt.Errorf("meta_repo_steps: failed to initialize; %w", factoryErr) } else if thatMetaRepo, initErr := support.InitThatMetaRepo(ctx); initErr != nil { diff --git a/src/go/cukestep/repository_steps.go b/src/go/cukestep/repository_steps.go index 10006e5e..7d115adb 100644 --- a/src/go/cukestep/repository_steps.go +++ b/src/go/cukestep/repository_steps.go @@ -9,6 +9,7 @@ import ( core "github.com/kkrull/marmot/corerepository" support "github.com/kkrull/marmot/cukesupport" main "github.com/kkrull/marmot/mainfactory" + "github.com/kkrull/marmot/svcfs" . "github.com/onsi/gomega" ) @@ -81,8 +82,8 @@ func factoryForThatMetaRepo() (*main.AppFactory, error) { if metaRepoPath, pathErr := support.ThatMetaRepo(); pathErr != nil { return nil, fmt.Errorf("repository_steps: failed to configure; %w", pathErr) } else { - factory := &main.AppFactory{} - factory.ForLocalMetaRepo(metaRepoPath) + factory := main.NewAppFactory() + factory.WithRepositorySource(svcfs.NewJsonMetaRepo(metaRepoPath)) return factory, nil } } diff --git a/src/go/mainfactory/app_factory.go b/src/go/mainfactory/app_factory.go index 274b2371..e44833a0 100644 --- a/src/go/mainfactory/app_factory.go +++ b/src/go/mainfactory/app_factory.go @@ -10,15 +10,18 @@ import ( repository "github.com/kkrull/marmot/userepository" ) +func NewAppFactory() *AppFactory { + return &AppFactory{MetaDataAdmin: svcfs.NewJsonMetaRepoAdmin()} +} + // Constructs application commands and queries with configurable services. type AppFactory struct { MetaDataAdmin coremetarepo.MetaDataAdmin RepositorySource corerepository.RepositorySource } -// Configure a local, file-based meta repo at the specified path -func (factory *AppFactory) ForLocalMetaRepo(metaRepoPath string) *AppFactory { - factory.RepositorySource = svcfs.NewJsonMetaRepo(metaRepoPath) +func (factory *AppFactory) WithRepositorySource(repositorySource corerepository.RepositorySource) *AppFactory { + factory.RepositorySource = repositorySource return factory } diff --git a/src/go/userepository/register_remote_repositories_command_test.go b/src/go/userepository/register_remote_repositories_command_test.go index 784c306d..19e68c2d 100644 --- a/src/go/userepository/register_remote_repositories_command_test.go +++ b/src/go/userepository/register_remote_repositories_command_test.go @@ -21,7 +21,7 @@ var _ = Describe("RegisterRepositoriesCommand", func() { BeforeEach(func() { source = mock.NewRepositorySource() - factory = &main.AppFactory{RepositorySource: source} + factory = main.NewAppFactory().WithRepositorySource(source) subject = expect.NoError(factory.RegisterRemoteRepositoriesCommand()) }) From 24c6ab794b68b6a8e1da42129236da39ef7ed1bf Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 11:58:58 -0500 Subject: [PATCH 31/43] Make commands differently --- src/go/cmdinit/init_command.go | 4 ++-- src/go/mainfactory/cli_factory.go | 23 +++++++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 87026bc0..c05c4f0f 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -11,8 +11,8 @@ import ( ) // Construct a CLI command to initialize a meta repo -func NewInitCommand(initApp *usemetarepo.InitCommand) *initCommand { - return &initCommand{initAppCmd: initApp} +func NewInitCommand(initAppCmd *usemetarepo.InitCommand) *initCommand { + return &initCommand{initAppCmd: initAppCmd} } type initCommand struct { diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index d0c868c7..d1b3bff2 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -13,16 +13,15 @@ import ( ) // Construct a factory to create CLI commands. -func NewCliFactory(appFactory *AppFactory) *CliFactory { - return &CliFactory{appFactory: appFactory} +func NewCliFactory() *CliFactory { + return &CliFactory{} } // Creates commands for the Command Line Interface (CLI). type CliFactory struct { - appFactory *AppFactory - stdout io.Writer - stderr io.Writer - version string + stdout io.Writer + stderr io.Writer + version string } func (cliFactory *CliFactory) WithStdIO(stdout io.Writer, stderr io.Writer) *CliFactory { @@ -35,14 +34,10 @@ func (cliFactory *CliFactory) WithStdIO(stdout io.Writer, stderr io.Writer) *Cli func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { rootCmd := cmd.NewRootCommand(cliFactory.stdout, cliFactory.stderr, cliFactory.version) - if initAppCmd, appFactoryErr := cliFactory.appFactory.InitCommand(); appFactoryErr != nil { - return nil, appFactoryErr - } else { - cmdinit. - NewInitCommand(initAppCmd). - RegisterWithCobra() - return rootCmd, nil - } + cmdinit. + NewInitCommand(). + RegisterWithCobra() + return rootCmd, nil } /* Version configuration */ From 4f5b0cc8ddf66d967bf59c4616f2b0dc9e51c11f Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 12:11:46 -0500 Subject: [PATCH 32/43] Make it compile --- src/go/mainfactory/cli_factory.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index d1b3bff2..243574f9 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -34,10 +34,14 @@ func (cliFactory *CliFactory) WithStdIO(stdout io.Writer, stderr io.Writer) *Cli func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { rootCmd := cmd.NewRootCommand(cliFactory.stdout, cliFactory.stderr, cliFactory.version) - cmdinit. - NewInitCommand(). - RegisterWithCobra() - return rootCmd, nil + if initAppCmd, initAppErr := NewAppFactory().InitCommand(); initAppErr != nil { + return nil, initAppErr + } else { + cmdinit. + NewInitCommand(initAppCmd). + RegisterWithCobra() + return rootCmd, nil + } } /* Version configuration */ From c2c412b6eb817216ec6b44590297d347b652ba1c Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 12:16:26 -0500 Subject: [PATCH 33/43] Next step --- src/go/cmdinit/init_command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index c05c4f0f..d25572b6 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -27,6 +27,7 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", RunE: func(cobraCmd *cobra.Command, _args []string) error { + //TODO KDK: Look up flags and apply default configuration, for meta repo path if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { return pathErr } else if runErr := cliCmd.initAppCmd.Run(metaRepoPath); runErr != nil { From 619c26292ab3014bd3d8f81cd9060a8c4b88b6e0 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 12:32:34 -0500 Subject: [PATCH 34/43] Move stuff around again --- src/go/cmd/config.go | 33 +++++++++++++++++++ src/go/cmdinit/init_command.go | 26 ++++----------- src/go/cukestep/meta_repo_steps.go | 9 +++-- src/go/cukestep/repository_steps.go | 9 +++-- src/go/mainfactory/cli_factory.go | 12 +++---- src/go/{mainfactory => use}/app_factory.go | 6 ++-- src/go/usemetarepo/init_command_test.go | 13 +++----- ...gister_remote_repositories_command_test.go | 6 ++-- 8 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 src/go/cmd/config.go rename src/go/{mainfactory => use}/app_factory.go (94%) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go new file mode 100644 index 00000000..85cdf4ad --- /dev/null +++ b/src/go/cmd/config.go @@ -0,0 +1,33 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/kkrull/marmot/use" + "github.com/spf13/cobra" +) + +func ParseFlags(cobraCmd *cobra.Command) *Config { + //TODO KDK: Look up flags and apply default configuration, for meta repo path + return &Config{ + AppFactory: *use.NewAppFactory(), + } +} + +type Config struct { + AppFactory use.AppFactory +} + +func (config Config) MetaRepoPath() (string, error) { + return defaultMetaRepoPath() +} + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } +} diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index d25572b6..ad77138f 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -2,22 +2,17 @@ package cmdinit import ( "fmt" - "os" - "path/filepath" "github.com/kkrull/marmot/cmd" - "github.com/kkrull/marmot/usemetarepo" "github.com/spf13/cobra" ) // Construct a CLI command to initialize a meta repo -func NewInitCommand(initAppCmd *usemetarepo.InitCommand) *initCommand { - return &initCommand{initAppCmd: initAppCmd} +func NewInitCommand() *initCommand { + return &initCommand{} } -type initCommand struct { - initAppCmd *usemetarepo.InitCommand -} +type initCommand struct{} func (cliCmd *initCommand) RegisterWithCobra() { cmd.AddMetaRepoCommand(*cliCmd.toCobraCommand()) @@ -27,10 +22,11 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", RunE: func(cobraCmd *cobra.Command, _args []string) error { - //TODO KDK: Look up flags and apply default configuration, for meta repo path - if metaRepoPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + config := cmd.ParseFlags(cobraCmd) + initAppCmd := config.AppFactory.InitCommand() + if metaRepoPath, pathErr := config.MetaRepoPath(); pathErr != nil { return pathErr - } else if runErr := cliCmd.initAppCmd.Run(metaRepoPath); runErr != nil { + } else if runErr := initAppCmd.Run(metaRepoPath); runErr != nil { return runErr } else { fmt.Printf("Initialized meta repo at %s\n", metaRepoPath) @@ -41,11 +37,3 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { Use: "init", } } - -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } -} diff --git a/src/go/cukestep/meta_repo_steps.go b/src/go/cukestep/meta_repo_steps.go index 521d1bf4..5505a60a 100644 --- a/src/go/cukestep/meta_repo_steps.go +++ b/src/go/cukestep/meta_repo_steps.go @@ -5,7 +5,7 @@ import ( "github.com/cucumber/godog" support "github.com/kkrull/marmot/cukesupport" - main "github.com/kkrull/marmot/mainfactory" + "github.com/kkrull/marmot/use" ) // Add step definitions to manage the life cycle of a meta repo. @@ -17,10 +17,9 @@ func AddMetaRepoSteps(ctx *godog.ScenarioContext) { /* Steps */ func initNewMetaRepo(ctx *godog.ScenarioContext) error { - factory := main.NewAppFactory() - if initCmd, factoryErr := factory.InitCommand(); factoryErr != nil { - return fmt.Errorf("meta_repo_steps: failed to initialize; %w", factoryErr) - } else if thatMetaRepo, initErr := support.InitThatMetaRepo(ctx); initErr != nil { + factory := use.NewAppFactory() + initCmd := factory.InitCommand() + if thatMetaRepo, initErr := support.InitThatMetaRepo(ctx); initErr != nil { return fmt.Errorf("meta_repo_steps: failed to initialize path to meta repo; %w", initErr) } else if runErr := initCmd.Run(thatMetaRepo); runErr != nil { return fmt.Errorf("meta_repo_steps: failed to initialize repository; %w", runErr) diff --git a/src/go/cukestep/repository_steps.go b/src/go/cukestep/repository_steps.go index 7d115adb..96d9ff53 100644 --- a/src/go/cukestep/repository_steps.go +++ b/src/go/cukestep/repository_steps.go @@ -8,8 +8,8 @@ import ( "github.com/cucumber/godog" core "github.com/kkrull/marmot/corerepository" support "github.com/kkrull/marmot/cukesupport" - main "github.com/kkrull/marmot/mainfactory" "github.com/kkrull/marmot/svcfs" + "github.com/kkrull/marmot/use" . "github.com/onsi/gomega" ) @@ -78,12 +78,11 @@ func registerRemote() error { /* Configuration */ -func factoryForThatMetaRepo() (*main.AppFactory, error) { +func factoryForThatMetaRepo() (*use.AppFactory, error) { if metaRepoPath, pathErr := support.ThatMetaRepo(); pathErr != nil { return nil, fmt.Errorf("repository_steps: failed to configure; %w", pathErr) } else { - factory := main.NewAppFactory() - factory.WithRepositorySource(svcfs.NewJsonMetaRepo(metaRepoPath)) - return factory, nil + factory := use.NewAppFactory() + return factory.WithRepositorySource(svcfs.NewJsonMetaRepo(metaRepoPath)), nil } } diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index 243574f9..d1b3bff2 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -34,14 +34,10 @@ func (cliFactory *CliFactory) WithStdIO(stdout io.Writer, stderr io.Writer) *Cli func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { rootCmd := cmd.NewRootCommand(cliFactory.stdout, cliFactory.stderr, cliFactory.version) - if initAppCmd, initAppErr := NewAppFactory().InitCommand(); initAppErr != nil { - return nil, initAppErr - } else { - cmdinit. - NewInitCommand(initAppCmd). - RegisterWithCobra() - return rootCmd, nil - } + cmdinit. + NewInitCommand(). + RegisterWithCobra() + return rootCmd, nil } /* Version configuration */ diff --git a/src/go/mainfactory/app_factory.go b/src/go/use/app_factory.go similarity index 94% rename from src/go/mainfactory/app_factory.go rename to src/go/use/app_factory.go index e44833a0..39014bc3 100644 --- a/src/go/mainfactory/app_factory.go +++ b/src/go/use/app_factory.go @@ -1,4 +1,4 @@ -package mainfactory +package use import ( "errors" @@ -27,8 +27,8 @@ func (factory *AppFactory) WithRepositorySource(repositorySource corerepository. /* Administration */ -func (factory *AppFactory) InitCommand() (*metarepo.InitCommand, error) { - return &metarepo.InitCommand{MetaDataAdmin: factory.MetaDataAdmin}, nil +func (factory *AppFactory) InitCommand() *metarepo.InitCommand { + return &metarepo.InitCommand{MetaDataAdmin: factory.MetaDataAdmin} } /* Repositories */ diff --git a/src/go/usemetarepo/init_command_test.go b/src/go/usemetarepo/init_command_test.go index ca2d8a02..8fec2f2c 100644 --- a/src/go/usemetarepo/init_command_test.go +++ b/src/go/usemetarepo/init_command_test.go @@ -4,8 +4,8 @@ import ( "errors" mock "github.com/kkrull/marmot/coremetarepomock" - main "github.com/kkrull/marmot/mainfactory" - use "github.com/kkrull/marmot/usemetarepo" + "github.com/kkrull/marmot/use" + "github.com/kkrull/marmot/usemetarepo" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -13,31 +13,28 @@ import ( var _ = Describe("InitCommand", func() { var ( - subject *use.InitCommand - factory *main.AppFactory + subject *usemetarepo.InitCommand metaDataAdmin *mock.MetaDataAdmin ) BeforeEach(func() { metaDataAdmin = &mock.MetaDataAdmin{} - factory = &main.AppFactory{MetaDataAdmin: metaDataAdmin} + factory := &use.AppFactory{MetaDataAdmin: metaDataAdmin} + subject = factory.InitCommand() }) Describe("#Run", func() { It("initializes the given meta data source", func() { - subject, _ = factory.InitCommand() _ = subject.Run("/tmp") metaDataAdmin.CreateExpected("/tmp") }) It("returns nil, when everything succeeds", func() { - subject, _ = factory.InitCommand() Expect(subject.Run("/tmp")).To(BeNil()) }) It("returns an error when failing to initialize the meta data source", func() { metaDataAdmin.CreateError = errors.New("bang!") - subject, _ = factory.InitCommand() Expect(subject.Run("/tmp")).To(MatchError("bang!")) }) }) diff --git a/src/go/userepository/register_remote_repositories_command_test.go b/src/go/userepository/register_remote_repositories_command_test.go index 19e68c2d..2c090d6c 100644 --- a/src/go/userepository/register_remote_repositories_command_test.go +++ b/src/go/userepository/register_remote_repositories_command_test.go @@ -4,9 +4,9 @@ import ( "net/url" mock "github.com/kkrull/marmot/corerepositorymock" - main "github.com/kkrull/marmot/mainfactory" testdata "github.com/kkrull/marmot/testsupportdata" expect "github.com/kkrull/marmot/testsupportexpect" + "github.com/kkrull/marmot/use" "github.com/kkrull/marmot/userepository" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -14,14 +14,14 @@ import ( var _ = Describe("RegisterRepositoriesCommand", func() { var ( - factory *main.AppFactory + factory *use.AppFactory source *mock.RepositorySource subject *userepository.RegisterRemoteRepositoriesCommand ) BeforeEach(func() { source = mock.NewRepositorySource() - factory = main.NewAppFactory().WithRepositorySource(source) + factory = use.NewAppFactory().WithRepositorySource(source) subject = expect.NoError(factory.RegisterRemoteRepositoriesCommand()) }) From 01dca9f32c743db16ecc0b07d483dccf58bedbc9 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 12:47:35 -0500 Subject: [PATCH 35/43] remove redundancy --- src/go/main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/go/main.go b/src/go/main.go index de58df37..fb1407e5 100644 --- a/src/go/main.go +++ b/src/go/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "io" "os" @@ -15,7 +14,6 @@ var ( func main() { if err := doMain(); err != nil { - fmt.Fprintln(stderr, err.Error()) os.Exit(1) } } From 281afd7b122a5230c7663cf7f092f0db955dd5d3 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 12:57:25 -0500 Subject: [PATCH 36/43] Apply default path --- src/go/cmd/config.go | 20 +++++------------- src/go/cmdinit/init_command.go | 37 ++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index 85cdf4ad..e5668aab 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -1,33 +1,23 @@ package cmd import ( - "fmt" - "os" - "path/filepath" - "github.com/kkrull/marmot/use" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) func ParseFlags(cobraCmd *cobra.Command) *Config { - //TODO KDK: Look up flags and apply default configuration, for meta repo path return &Config{ AppFactory: *use.NewAppFactory(), + flagSet: cobraCmd.Flags(), } } type Config struct { AppFactory use.AppFactory + flagSet *pflag.FlagSet } -func (config Config) MetaRepoPath() (string, error) { - return defaultMetaRepoPath() -} - -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } +func (config Config) MetaRepoPath() string { + return config.flagSet.Lookup("meta-repo").Value.String() } diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index ad77138f..252b3c69 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -2,6 +2,8 @@ package cmdinit import ( "fmt" + "os" + "path/filepath" "github.com/kkrull/marmot/cmd" "github.com/spf13/cobra" @@ -14,19 +16,23 @@ func NewInitCommand() *initCommand { type initCommand struct{} -func (cliCmd *initCommand) RegisterWithCobra() { - cmd.AddMetaRepoCommand(*cliCmd.toCobraCommand()) +func (cliCmd *initCommand) RegisterWithCobra() error { + if cobraCmd, cobraErr := cliCmd.toCobraCommand(); cobraErr != nil { + return cobraErr + } else { + cmd.AddMetaRepoCommand(*cobraCmd) + return nil + } } -func (cliCmd *initCommand) toCobraCommand() *cobra.Command { - return &cobra.Command{ - Long: "Initialize a new Meta Repo, if none is already present in the configured directory.", +func (cliCmd *initCommand) toCobraCommand() (*cobra.Command, error) { + cobraCmd := &cobra.Command{ + Long: "Initialize a new Meta Repo, if none is already present.", RunE: func(cobraCmd *cobra.Command, _args []string) error { config := cmd.ParseFlags(cobraCmd) initAppCmd := config.AppFactory.InitCommand() - if metaRepoPath, pathErr := config.MetaRepoPath(); pathErr != nil { - return pathErr - } else if runErr := initAppCmd.Run(metaRepoPath); runErr != nil { + metaRepoPath := config.MetaRepoPath() + if runErr := initAppCmd.Run(metaRepoPath); runErr != nil { return runErr } else { fmt.Printf("Initialized meta repo at %s\n", metaRepoPath) @@ -36,4 +42,19 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { Short: "Initialize a meta repo", Use: "init", } + + if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + return nil, pathErr + } else { + cobraCmd.Flags().String("meta-repo", defaultPath, "Meta repo to use") + return cobraCmd, nil + } +} + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } } From 60da0bcb13168f10769acd32828648b0fb5b11e3 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 13:10:56 -0500 Subject: [PATCH 37/43] Make meta-repo a persistent flag --- src/go/cmd/root_command.go | 19 +++++++++++++++++-- src/go/cmdinit/init_command.go | 31 +++++-------------------------- src/go/mainfactory/cli_factory.go | 13 ++++++++----- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 15f39163..8804f5be 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -3,6 +3,8 @@ package cmd import ( "fmt" "io" + "os" + "path/filepath" "github.com/spf13/cobra" ) @@ -13,7 +15,7 @@ var ( ) // Configure the root command with the given I/O and version identifier, then return for use. -func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.Command { +func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra.Command, error) { rootCmd = &cobra.Command{ Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", RunE: func(cmd *cobra.Command, args []string) error { @@ -34,6 +36,11 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C // Flags debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") rootCmd.PersistentFlags().Lookup("debug").Hidden = true + if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + return nil, pathErr + } else { + rootCmd.PersistentFlags().String("meta-repo", defaultPath, "Meta repo to use") + } // Groups rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) @@ -41,7 +48,15 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) *cobra.C // I/O rootCmd.SetOut(stdout) rootCmd.SetErr(stderr) - return rootCmd + return rootCmd, nil +} + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } } /* Child commands */ diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 252b3c69..34a62348 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -2,8 +2,6 @@ package cmdinit import ( "fmt" - "os" - "path/filepath" "github.com/kkrull/marmot/cmd" "github.com/spf13/cobra" @@ -16,17 +14,13 @@ func NewInitCommand() *initCommand { type initCommand struct{} -func (cliCmd *initCommand) RegisterWithCobra() error { - if cobraCmd, cobraErr := cliCmd.toCobraCommand(); cobraErr != nil { - return cobraErr - } else { - cmd.AddMetaRepoCommand(*cobraCmd) - return nil - } +func (cliCmd *initCommand) RegisterWithCobra() { + cobraCmd := cliCmd.toCobraCommand() + cmd.AddMetaRepoCommand(*cobraCmd) } -func (cliCmd *initCommand) toCobraCommand() (*cobra.Command, error) { - cobraCmd := &cobra.Command{ +func (cliCmd *initCommand) toCobraCommand() *cobra.Command { + return &cobra.Command{ Long: "Initialize a new Meta Repo, if none is already present.", RunE: func(cobraCmd *cobra.Command, _args []string) error { config := cmd.ParseFlags(cobraCmd) @@ -42,19 +36,4 @@ func (cliCmd *initCommand) toCobraCommand() (*cobra.Command, error) { Short: "Initialize a meta repo", Use: "init", } - - if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { - return nil, pathErr - } else { - cobraCmd.Flags().String("meta-repo", defaultPath, "Meta repo to use") - return cobraCmd, nil - } -} - -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } } diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index d1b3bff2..7263ba65 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -33,11 +33,14 @@ func (cliFactory *CliFactory) WithStdIO(stdout io.Writer, stderr io.Writer) *Cli /* Factory methods */ func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { - rootCmd := cmd.NewRootCommand(cliFactory.stdout, cliFactory.stderr, cliFactory.version) - cmdinit. - NewInitCommand(). - RegisterWithCobra() - return rootCmd, nil + if rootCmd, rootCmdErr := cmd.NewRootCommand(cliFactory.stdout, cliFactory.stderr, cliFactory.version); rootCmdErr != nil { + return nil, rootCmdErr + } else { + cmdinit. + NewInitCommand(). + RegisterWithCobra() + return rootCmd, nil + } } /* Version configuration */ From 1667d7088262c2d9b6f91e7412515ad54c8bcadb Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 13:36:14 -0500 Subject: [PATCH 38/43] Move debug flag to config --- src/go/cmd/config.go | 46 ++++++++++++++++++++++++++++++++++ src/go/cmd/root_command.go | 34 ++++--------------------- src/go/cmdinit/init_command.go | 5 ++++ 3 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index e5668aab..5a39001e 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -1,11 +1,41 @@ package cmd import ( + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "github.com/kkrull/marmot/use" "github.com/spf13/cobra" "github.com/spf13/pflag" ) +/* Configuration */ + +func AddFlags(cobraCmd *cobra.Command) error { + cobraCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") + cobraCmd.PersistentFlags().Lookup("debug").Hidden = true + + if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { + return pathErr + } else { + cobraCmd.PersistentFlags().String("meta-repo", defaultPath, "Meta repo to use") + return nil + } +} + +func defaultMetaRepoPath() (string, error) { + if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { + return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + } else { + return filepath.Join(homeDir, "meta"), nil + } +} + +/* Use */ + func ParseFlags(cobraCmd *cobra.Command) *Config { return &Config{ AppFactory: *use.NewAppFactory(), @@ -18,6 +48,22 @@ type Config struct { flagSet *pflag.FlagSet } +func (config Config) Debug() bool { + rawValue := config.flagSet.Lookup("debug").Value.String() + parsed, _ := strconv.ParseBool(rawValue) + return parsed +} + func (config Config) MetaRepoPath() string { return config.flagSet.Lookup("meta-repo").Value.String() } + +func (config Config) PrintDebug(writer io.Writer) { + fmt.Fprintf(writer, "Flags:\n") + + debugFlag := config.flagSet.Lookup("debug") + fmt.Fprintf(writer, "- debug [%v]: %v\n", debugFlag.DefValue, debugFlag.Value) + + metaRepoFlag := config.flagSet.Lookup("meta-repo") + fmt.Fprintf(writer, "- meta-repo [%v]: %v\n", metaRepoFlag.DefValue, metaRepoFlag.Value) +} diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 8804f5be..13c68474 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -1,17 +1,13 @@ package cmd import ( - "fmt" "io" - "os" - "path/filepath" "github.com/spf13/cobra" ) var ( - debugFlag *bool - rootCmd *cobra.Command + rootCmd *cobra.Command ) // Configure the root command with the given I/O and version identifier, then return for use. @@ -19,8 +15,9 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. rootCmd = &cobra.Command{ Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", RunE: func(cmd *cobra.Command, args []string) error { - if *debugFlag { - printDebug() + config := ParseFlags(cmd) + if config.Debug() { + config.PrintDebug(stdout) return nil } else if len(args) == 0 { return cmd.Help() @@ -34,13 +31,7 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. } // Flags - debugFlag = rootCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") - rootCmd.PersistentFlags().Lookup("debug").Hidden = true - if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { - return nil, pathErr - } else { - rootCmd.PersistentFlags().String("meta-repo", defaultPath, "Meta repo to use") - } + AddFlags(rootCmd) // Groups rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) @@ -51,14 +42,6 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. return rootCmd, nil } -func defaultMetaRepoPath() (string, error) { - if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) - } else { - return filepath.Join(homeDir, "meta"), nil - } -} - /* Child commands */ const ( @@ -69,10 +52,3 @@ func AddMetaRepoCommand(child cobra.Command) { child.GroupID = metaRepoGroup rootCmd.AddCommand(&child) } - -/* Pseudo-commands */ - -func printDebug() { - fmt.Printf("Flags:\n") - fmt.Printf("- debug [%v]: %v\n", rootCmd.Flags().Lookup("debug").DefValue, *debugFlag) -} diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 34a62348..ac8b10fb 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -24,6 +24,11 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { Long: "Initialize a new Meta Repo, if none is already present.", RunE: func(cobraCmd *cobra.Command, _args []string) error { config := cmd.ParseFlags(cobraCmd) + if config.Debug() { + config.PrintDebug(cobraCmd.OutOrStdout()) + return nil + } + initAppCmd := config.AppFactory.InitCommand() metaRepoPath := config.MetaRepoPath() if runErr := initAppCmd.Run(metaRepoPath); runErr != nil { From f12de5524568757920deea4a0ac25714db726184 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 13:41:25 -0500 Subject: [PATCH 39/43] Disallow arguments --- src/go/cmd/config.go | 1 - src/go/cmdinit/init_command.go | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index 5a39001e..48d09741 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -17,7 +17,6 @@ import ( func AddFlags(cobraCmd *cobra.Command) error { cobraCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") cobraCmd.PersistentFlags().Lookup("debug").Hidden = true - if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { return pathErr } else { diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index ac8b10fb..8f5631d0 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -21,6 +21,7 @@ func (cliCmd *initCommand) RegisterWithCobra() { func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ + Args: cobra.NoArgs, Long: "Initialize a new Meta Repo, if none is already present.", RunE: func(cobraCmd *cobra.Command, _args []string) error { config := cmd.ParseFlags(cobraCmd) From e6f9e375de524ed7ad6a47a9255a6b25968e2b47 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 13:58:57 -0500 Subject: [PATCH 40/43] Parse flags earlier --- src/go/cmd/config.go | 34 +++++++++++++++++----------------- src/go/cmd/root_command.go | 7 ++++--- src/go/cmdinit/init_command.go | 20 ++++++++++---------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index 48d09741..06b7400f 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -5,7 +5,6 @@ import ( "io" "os" "path/filepath" - "strconv" "github.com/kkrull/marmot/use" "github.com/spf13/cobra" @@ -35,26 +34,27 @@ func defaultMetaRepoPath() (string, error) { /* Use */ -func ParseFlags(cobraCmd *cobra.Command) *Config { - return &Config{ - AppFactory: *use.NewAppFactory(), - flagSet: cobraCmd.Flags(), +func ParseFlags(cobraCmd *cobra.Command) (*Config, error) { + flags := cobraCmd.Flags() + if debug, debugErr := flags.GetBool("debug"); debugErr != nil { + return nil, debugErr + } else if metaRepoPath, metaRepoPathErr := flags.GetString("meta-repo"); metaRepoPathErr != nil { + return nil, metaRepoPathErr + } else { + return &Config{ + AppFactory: *use.NewAppFactory(), + Debug: debug, + MetaRepoPath: metaRepoPath, + flagSet: flags, + }, nil } } type Config struct { - AppFactory use.AppFactory - flagSet *pflag.FlagSet -} - -func (config Config) Debug() bool { - rawValue := config.flagSet.Lookup("debug").Value.String() - parsed, _ := strconv.ParseBool(rawValue) - return parsed -} - -func (config Config) MetaRepoPath() string { - return config.flagSet.Lookup("meta-repo").Value.String() + AppFactory use.AppFactory + Debug bool + MetaRepoPath string + flagSet *pflag.FlagSet } func (config Config) PrintDebug(writer io.Writer) { diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index 13c68474..b0aef81c 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -15,8 +15,9 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. rootCmd = &cobra.Command{ Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", RunE: func(cmd *cobra.Command, args []string) error { - config := ParseFlags(cmd) - if config.Debug() { + if config, parseErr := ParseFlags(cmd); parseErr != nil { + return parseErr + } else if config.Debug { config.PrintDebug(stdout) return nil } else if len(args) == 0 { @@ -26,7 +27,7 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. } }, Short: "Meta Repo Management Tool", - Use: "marmot [--help|--version]", + Use: "marmot", Version: version, } diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 8f5631d0..9a78500c 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -24,19 +24,19 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { Args: cobra.NoArgs, Long: "Initialize a new Meta Repo, if none is already present.", RunE: func(cobraCmd *cobra.Command, _args []string) error { - config := cmd.ParseFlags(cobraCmd) - if config.Debug() { + if config, parseErr := cmd.ParseFlags(cobraCmd); parseErr != nil { + return parseErr + } else if config.Debug { config.PrintDebug(cobraCmd.OutOrStdout()) return nil - } - - initAppCmd := config.AppFactory.InitCommand() - metaRepoPath := config.MetaRepoPath() - if runErr := initAppCmd.Run(metaRepoPath); runErr != nil { - return runErr } else { - fmt.Printf("Initialized meta repo at %s\n", metaRepoPath) - return nil + initAppCmd := config.AppFactory.InitCommand() + if runErr := initAppCmd.Run(config.MetaRepoPath); runErr != nil { + return runErr + } else { + fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoPath) + return nil + } } }, Short: "Initialize a meta repo", From 5c72eba78e447e516ee166927cd802e74a7e3977 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 14:07:43 -0500 Subject: [PATCH 41/43] Clean up parsing and running --- src/go/cmd/config.go | 24 ++++++++++++++++-------- src/go/cmdinit/init_command.go | 16 +++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/go/cmd/config.go b/src/go/cmd/config.go index 06b7400f..bd8b17cd 100644 --- a/src/go/cmd/config.go +++ b/src/go/cmd/config.go @@ -14,21 +14,29 @@ import ( /* Configuration */ func AddFlags(cobraCmd *cobra.Command) error { - cobraCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") - cobraCmd.PersistentFlags().Lookup("debug").Hidden = true - if defaultPath, pathErr := defaultMetaRepoPath(); pathErr != nil { - return pathErr + addDebugFlag(cobraCmd) + if metaRepoErr := addMetaRepoFlag(cobraCmd); metaRepoErr != nil { + return metaRepoErr } else { - cobraCmd.PersistentFlags().String("meta-repo", defaultPath, "Meta repo to use") return nil } } -func defaultMetaRepoPath() (string, error) { +func addDebugFlag(cobraCmd *cobra.Command) { + cobraCmd.PersistentFlags().Bool("debug", false, "print CLI debugging information") + cobraCmd.PersistentFlags().Lookup("debug").Hidden = true +} + +func addMetaRepoFlag(cobraCmd *cobra.Command) error { if homeDir, homeErr := os.UserHomeDir(); homeErr != nil { - return "", fmt.Errorf("failed to locate home directory; %w", homeErr) + return fmt.Errorf("failed to locate home directory; %w", homeErr) } else { - return filepath.Join(homeDir, "meta"), nil + cobraCmd.PersistentFlags().String( + "meta-repo", + filepath.Join(homeDir, "meta"), + "Meta repo to use", + ) + return nil } } diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 9a78500c..b22b20e6 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -29,17 +29,19 @@ func (cliCmd *initCommand) toCobraCommand() *cobra.Command { } else if config.Debug { config.PrintDebug(cobraCmd.OutOrStdout()) return nil + } else if runErr := run(config); runErr != nil { + return runErr } else { - initAppCmd := config.AppFactory.InitCommand() - if runErr := initAppCmd.Run(config.MetaRepoPath); runErr != nil { - return runErr - } else { - fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoPath) - return nil - } + fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoPath) + return nil } }, Short: "Initialize a meta repo", Use: "init", } } + +func run(config *cmd.Config) error { + initAppCmd := config.AppFactory.InitCommand() + return initAppCmd.Run(config.MetaRepoPath) +} From 5e42d65c1f4069e82d187f40b4e0f17973e0e72c Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 14:18:55 -0500 Subject: [PATCH 42/43] Organize run --- src/go/cmd/root_command.go | 28 +++++++++++++------------ src/go/cmdinit/init_command.go | 38 +++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index b0aef81c..f0ea5562 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -13,19 +13,8 @@ var ( // Configure the root command with the given I/O and version identifier, then return for use. func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra.Command, error) { rootCmd = &cobra.Command{ - Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", - RunE: func(cmd *cobra.Command, args []string) error { - if config, parseErr := ParseFlags(cmd); parseErr != nil { - return parseErr - } else if config.Debug { - config.PrintDebug(stdout) - return nil - } else if len(args) == 0 { - return cmd.Help() - } else { - return nil - } - }, + Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", + RunE: runRoot, Short: "Meta Repo Management Tool", Use: "marmot", Version: version, @@ -43,6 +32,19 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. return rootCmd, nil } +func runRoot(cobraCmd *cobra.Command, args []string) error { + if config, parseErr := ParseFlags(cobraCmd); parseErr != nil { + return parseErr + } else if config.Debug { + config.PrintDebug(cobraCmd.OutOrStdout()) + return nil + } else if len(args) == 0 { + return cobraCmd.Help() + } else { + return nil + } +} + /* Child commands */ const ( diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index b22b20e6..009bd8dc 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -21,27 +21,31 @@ func (cliCmd *initCommand) RegisterWithCobra() { func (cliCmd *initCommand) toCobraCommand() *cobra.Command { return &cobra.Command{ - Args: cobra.NoArgs, - Long: "Initialize a new Meta Repo, if none is already present.", - RunE: func(cobraCmd *cobra.Command, _args []string) error { - if config, parseErr := cmd.ParseFlags(cobraCmd); parseErr != nil { - return parseErr - } else if config.Debug { - config.PrintDebug(cobraCmd.OutOrStdout()) - return nil - } else if runErr := run(config); runErr != nil { - return runErr - } else { - fmt.Printf("Initialized meta repo at %s\n", config.MetaRepoPath) - return nil - } - }, + Args: cobra.NoArgs, + Long: "Initialize a new Meta Repo, if none is already present.", + RunE: runInit, Short: "Initialize a meta repo", Use: "init", } } -func run(config *cmd.Config) error { +func runInit(cobraCmd *cobra.Command, _args []string) error { + if config, parseErr := cmd.ParseFlags(cobraCmd); parseErr != nil { + return parseErr + } else if config.Debug { + config.PrintDebug(cobraCmd.OutOrStdout()) + return nil + } else { + return runInitAppCmd(cobraCmd, config) + } +} + +func runInitAppCmd(cobraCmd *cobra.Command, config *cmd.Config) error { initAppCmd := config.AppFactory.InitCommand() - return initAppCmd.Run(config.MetaRepoPath) + if runErr := initAppCmd.Run(config.MetaRepoPath); runErr != nil { + return runErr + } else { + fmt.Fprintf(cobraCmd.OutOrStdout(), "Initialized meta repo at %s\n", config.MetaRepoPath) + return nil + } } From 1c5f87e7b38aa053c68e454ffe99db0045591b69 Mon Sep 17 00:00:00 2001 From: Kyle Krull Date: Wed, 24 Jul 2024 14:24:50 -0500 Subject: [PATCH 43/43] Get rid of global variable within package --- src/go/cmd/root_command.go | 21 ++++++++------------- src/go/cmdinit/init_command.go | 4 ++-- src/go/mainfactory/cli_factory.go | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/go/cmd/root_command.go b/src/go/cmd/root_command.go index f0ea5562..d7de64e3 100644 --- a/src/go/cmd/root_command.go +++ b/src/go/cmd/root_command.go @@ -6,13 +6,9 @@ import ( "github.com/spf13/cobra" ) -var ( - rootCmd *cobra.Command -) - // Configure the root command with the given I/O and version identifier, then return for use. func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra.Command, error) { - rootCmd = &cobra.Command{ + rootCmd := &cobra.Command{ Long: "marmot manages a Meta Repository that organizes content in other (Git) repositories.", RunE: runRoot, Short: "Meta Repo Management Tool", @@ -20,13 +16,8 @@ func NewRootCommand(stdout io.Writer, stderr io.Writer, version string) (*cobra. Version: version, } - // Flags AddFlags(rootCmd) - - // Groups - rootCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) - - // I/O + addGroups(rootCmd) rootCmd.SetOut(stdout) rootCmd.SetErr(stderr) return rootCmd, nil @@ -51,7 +42,11 @@ const ( metaRepoGroup = "meta-repo" ) -func AddMetaRepoCommand(child cobra.Command) { +func addGroups(cobraCmd *cobra.Command) { + cobraCmd.AddGroup(&cobra.Group{ID: metaRepoGroup, Title: "Meta Repo Commands"}) +} + +func AddMetaRepoCommand(parent *cobra.Command, child cobra.Command) { child.GroupID = metaRepoGroup - rootCmd.AddCommand(&child) + parent.AddCommand(&child) } diff --git a/src/go/cmdinit/init_command.go b/src/go/cmdinit/init_command.go index 009bd8dc..f6576833 100644 --- a/src/go/cmdinit/init_command.go +++ b/src/go/cmdinit/init_command.go @@ -14,9 +14,9 @@ func NewInitCommand() *initCommand { type initCommand struct{} -func (cliCmd *initCommand) RegisterWithCobra() { +func (cliCmd *initCommand) RegisterWithCobra(parentCmd *cobra.Command) { cobraCmd := cliCmd.toCobraCommand() - cmd.AddMetaRepoCommand(*cobraCmd) + cmd.AddMetaRepoCommand(parentCmd, *cobraCmd) } func (cliCmd *initCommand) toCobraCommand() *cobra.Command { diff --git a/src/go/mainfactory/cli_factory.go b/src/go/mainfactory/cli_factory.go index 7263ba65..367af3d2 100644 --- a/src/go/mainfactory/cli_factory.go +++ b/src/go/mainfactory/cli_factory.go @@ -38,7 +38,7 @@ func (cliFactory *CliFactory) CommandTree() (*cobra.Command, error) { } else { cmdinit. NewInitCommand(). - RegisterWithCobra() + RegisterWithCobra(rootCmd) return rootCmd, nil } }