diff --git a/scripts/nolint-revive-ginkgo-tests.sh b/scripts/nolint-revive-ginkgo-tests.sh index 0a71ef9..e927a82 100644 --- a/scripts/nolint-revive-ginkgo-tests.sh +++ b/scripts/nolint-revive-ginkgo-tests.sh @@ -85,7 +85,7 @@ nolint-revive-ginkgo-tests() { (( files_affected++ )) if $dry_run; then - printf '📁 %s — %d line(s) would be modified\n\n' "$file" "$file_mod_count" + printf '📁 %s - %d line(s) would be modified\n\n' "$file" "$file_mod_count" else # Write the modified content back directly. # Check for trailing newline before overwriting. diff --git a/src/agenor/composites_test.go b/src/agenor/composites_test.go index 10d06e7..ba2fc12 100644 --- a/src/agenor/composites_test.go +++ b/src/agenor/composites_test.go @@ -10,9 +10,9 @@ import ( "github.com/snivilised/jaywalk/src/agenor" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/director-error_test.go b/src/agenor/director-error_test.go index 965812a..d604210 100644 --- a/src/agenor/director-error_test.go +++ b/src/agenor/director-error_test.go @@ -14,10 +14,10 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/director-prime_test.go b/src/agenor/director-prime_test.go index a368f96..9a25cc5 100644 --- a/src/agenor/director-prime_test.go +++ b/src/agenor/director-prime_test.go @@ -12,11 +12,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" "github.com/snivilised/jaywalk/src/agenor/internal/opts" - "github.com/snivilised/jaywalk/src/internal/services" "github.com/snivilised/jaywalk/src/agenor/life" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/director-resume_test.go b/src/agenor/director-resume_test.go index 5d05a5f..892dc18 100644 --- a/src/agenor/director-resume_test.go +++ b/src/agenor/director-resume_test.go @@ -13,12 +13,12 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" "github.com/snivilised/jaywalk/src/agenor/life" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/feat/hiber/hibernate-simple-profile.go b/src/agenor/internal/feat/hiber/hibernate-simple-profile.go index cf7bacf..8622a60 100644 --- a/src/agenor/internal/feat/hiber/hibernate-simple-profile.go +++ b/src/agenor/internal/feat/hiber/hibernate-simple-profile.go @@ -8,7 +8,7 @@ import ( "github.com/snivilised/jaywalk/src/agenor/internal/enclave" "github.com/snivilised/jaywalk/src/agenor/internal/filtering" "github.com/snivilised/jaywalk/src/agenor/life" - "github.com/snivilised/jaywalk/locale" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/internal/feat/resume/resume-error_test.go b/src/agenor/internal/feat/resume/resume-error_test.go index fd4d5e0..d14daec 100644 --- a/src/agenor/internal/feat/resume/resume-error_test.go +++ b/src/agenor/internal/feat/resume/resume-error_test.go @@ -13,11 +13,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/feat/resume/resume-local-fs_test.go b/src/agenor/internal/feat/resume/resume-local-fs_test.go index bacf280..c80bea4 100644 --- a/src/agenor/internal/feat/resume/resume-local-fs_test.go +++ b/src/agenor/internal/feat/resume/resume-local-fs_test.go @@ -11,10 +11,10 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/internal/feat/resume/resume_test.go b/src/agenor/internal/feat/resume/resume_test.go index a066884..bb5da4e 100644 --- a/src/agenor/internal/feat/resume/resume_test.go +++ b/src/agenor/internal/feat/resume/resume_test.go @@ -12,13 +12,13 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/src/internal/third/lo" "github.com/snivilised/jaywalk/src/agenor/life" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/feat/resume/save_test.go b/src/agenor/internal/feat/resume/save_test.go index b2c2e1c..52bfbd0 100644 --- a/src/agenor/internal/feat/resume/save_test.go +++ b/src/agenor/internal/feat/resume/save_test.go @@ -12,11 +12,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" nef "github.com/snivilised/nefilim" "github.com/snivilised/nefilim/test/luna" diff --git a/src/agenor/internal/feat/sampling/navigator-sample_test.go b/src/agenor/internal/feat/sampling/navigator-sample_test.go index 3de3752..84c5404 100644 --- a/src/agenor/internal/feat/sampling/navigator-sample_test.go +++ b/src/agenor/internal/feat/sampling/navigator-sample_test.go @@ -10,12 +10,12 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/filtering/builders.go b/src/agenor/internal/filtering/builders.go index 90a34c8..7526935 100644 --- a/src/agenor/internal/filtering/builders.go +++ b/src/agenor/internal/filtering/builders.go @@ -5,9 +5,9 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" ) func buildNativeNodeFilter(definition *core.FilterDef) (core.TraverseFilter, error) { diff --git a/src/agenor/internal/filtering/child.go b/src/agenor/internal/filtering/child.go index 6ca3266..bf0248b 100644 --- a/src/agenor/internal/filtering/child.go +++ b/src/agenor/internal/filtering/child.go @@ -4,7 +4,7 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" + "github.com/snivilised/jaywalk/src/locale" ) // NewChild creates a new child filter. diff --git a/src/agenor/internal/filtering/filter-errata_test.go b/src/agenor/internal/filtering/filter-errata_test.go index 4af25ab..4c2a79f 100644 --- a/src/agenor/internal/filtering/filter-errata_test.go +++ b/src/agenor/internal/filtering/filter-errata_test.go @@ -8,11 +8,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/filtering/filter-hybrid_test.go b/src/agenor/internal/filtering/filter-hybrid_test.go index 87dd05f..484752d 100644 --- a/src/agenor/internal/filtering/filter-hybrid_test.go +++ b/src/agenor/internal/filtering/filter-hybrid_test.go @@ -8,11 +8,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/filtering/filter-poly_test.go b/src/agenor/internal/filtering/filter-poly_test.go index d862f9a..bd49ccb 100644 --- a/src/agenor/internal/filtering/filter-poly_test.go +++ b/src/agenor/internal/filtering/filter-poly_test.go @@ -10,12 +10,12 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/filtering/sample.go b/src/agenor/internal/filtering/sample.go index 19496e3..d00db1f 100644 --- a/src/agenor/internal/filtering/sample.go +++ b/src/agenor/internal/filtering/sample.go @@ -5,9 +5,9 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" nef "github.com/snivilised/nefilim" ) diff --git a/src/agenor/internal/kernel/navigator-agent.go b/src/agenor/internal/kernel/navigator-agent.go index 7193e16..e67fd78 100644 --- a/src/agenor/internal/kernel/navigator-agent.go +++ b/src/agenor/internal/kernel/navigator-agent.go @@ -8,10 +8,10 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/tapable" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" ) type readHooks struct { diff --git a/src/agenor/internal/kernel/navigator-async_test.go b/src/agenor/internal/kernel/navigator-async_test.go index a231a88..901f66d 100644 --- a/src/agenor/internal/kernel/navigator-async_test.go +++ b/src/agenor/internal/kernel/navigator-async_test.go @@ -14,12 +14,12 @@ import ( "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" "github.com/snivilised/pants" diff --git a/src/agenor/internal/kernel/navigator-cascade_test.go b/src/agenor/internal/kernel/navigator-cascade_test.go index b8f7e06..456b24d 100644 --- a/src/agenor/internal/kernel/navigator-cascade_test.go +++ b/src/agenor/internal/kernel/navigator-cascade_test.go @@ -7,11 +7,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/kernel/navigator-directories-with-files_test.go b/src/agenor/internal/kernel/navigator-directories-with-files_test.go index 4e75892..ec79e61 100644 --- a/src/agenor/internal/kernel/navigator-directories-with-files_test.go +++ b/src/agenor/internal/kernel/navigator-directories-with-files_test.go @@ -8,11 +8,11 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/kernel/navigator-factory.go b/src/agenor/internal/kernel/navigator-factory.go index 8c151a2..14e2de2 100644 --- a/src/agenor/internal/kernel/navigator-factory.go +++ b/src/agenor/internal/kernel/navigator-factory.go @@ -4,8 +4,8 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/locale" ) // PrimeArtefacts primes the artefacts for the navigator. diff --git a/src/agenor/internal/kernel/navigator-files_test.go b/src/agenor/internal/kernel/navigator-files_test.go index 6b75b3f..0b4e94c 100644 --- a/src/agenor/internal/kernel/navigator-files_test.go +++ b/src/agenor/internal/kernel/navigator-files_test.go @@ -8,9 +8,9 @@ import ( "github.com/snivilised/jaywalk/src/agenor" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/src/agenor/internal/kernel/navigator-vanilla_test.go b/src/agenor/internal/kernel/navigator-vanilla_test.go index e32df0b..be519b9 100644 --- a/src/agenor/internal/kernel/navigator-vanilla_test.go +++ b/src/agenor/internal/kernel/navigator-vanilla_test.go @@ -10,12 +10,12 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" lab "github.com/snivilised/jaywalk/src/agenor/internal/laboratory" - "github.com/snivilised/jaywalk/src/internal/services" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/test/hanno" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/services" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/internal/persist/comparison.go b/src/agenor/internal/persist/comparison.go index def5871..85f4243 100644 --- a/src/agenor/internal/persist/comparison.go +++ b/src/agenor/internal/persist/comparison.go @@ -6,8 +6,8 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" json "github.com/snivilised/jaywalk/src/agenor/internal/opts/jason" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/locale" ) // UnequalValueError represents a comparison error for a marshaled diff --git a/src/agenor/internal/persist/marshaler_test.go b/src/agenor/internal/persist/marshaler_test.go index 7656d2f..f5c67c9 100644 --- a/src/agenor/internal/persist/marshaler_test.go +++ b/src/agenor/internal/persist/marshaler_test.go @@ -17,9 +17,9 @@ import ( "github.com/snivilised/jaywalk/src/agenor/internal/opts" json "github.com/snivilised/jaywalk/src/agenor/internal/opts/jason" "github.com/snivilised/jaywalk/src/agenor/internal/persist" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/nefilim/test/luna" ) diff --git a/src/agenor/pref/facade.go b/src/agenor/pref/facade.go index eef08e3..99c6900 100644 --- a/src/agenor/pref/facade.go +++ b/src/agenor/pref/facade.go @@ -3,8 +3,8 @@ package pref import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/enums" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/locale" ) type ( diff --git a/src/agenor/scaffold.go b/src/agenor/scaffold.go index 0b508bc..084dd98 100644 --- a/src/agenor/scaffold.go +++ b/src/agenor/scaffold.go @@ -4,10 +4,10 @@ import ( "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" "github.com/snivilised/jaywalk/src/agenor/internal/opts" - "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" "github.com/snivilised/jaywalk/src/agenor/tfs" + "github.com/snivilised/jaywalk/src/internal/third/lo" + "github.com/snivilised/jaywalk/src/locale" ) type ( diff --git a/src/agenor/synchronise.go b/src/agenor/synchronise.go index cda8b53..9bf2f58 100644 --- a/src/agenor/synchronise.go +++ b/src/agenor/synchronise.go @@ -6,8 +6,8 @@ import ( "github.com/pkg/errors" "github.com/snivilised/jaywalk/src/agenor/core" "github.com/snivilised/jaywalk/src/agenor/internal/enclave" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/pants" ) diff --git a/src/app/command/internal/cfg/cfg_suite_test.go b/src/app/bedrock/bedrock_suite_test.go similarity index 57% rename from src/app/command/internal/cfg/cfg_suite_test.go rename to src/app/bedrock/bedrock_suite_test.go index f64fcee..08ac16c 100644 --- a/src/app/command/internal/cfg/cfg_suite_test.go +++ b/src/app/bedrock/bedrock_suite_test.go @@ -1,4 +1,4 @@ -package cfg_test +package bedrock_test import ( "testing" @@ -7,7 +7,7 @@ import ( . "github.com/onsi/gomega" ) -func TestCfg(t *testing.T) { +func TestBedrock(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "cfg Suite") + RunSpecs(t, "Bedrock Suite") } diff --git a/src/app/command/internal/cfg/doc.go b/src/app/bedrock/doc.go similarity index 73% rename from src/app/command/internal/cfg/doc.go rename to src/app/bedrock/doc.go index 57c0ca7..057a3ad 100644 --- a/src/app/command/internal/cfg/doc.go +++ b/src/app/bedrock/doc.go @@ -1,6 +1,6 @@ -// Package cfg handles all configuration concerns for jay, including loading, +// Package bedrock handles all configuration concerns for jay, including loading, // validation, and access to config values. Mapped sections (interaction, // advanced, logging) are decoded into strongly-typed Go structs via // mapstructure. Unstructured sections (actions, pipelines, flags) are // exposed as raw map values for consumer-driven handling. -package cfg +package bedrock diff --git a/src/app/command/internal/cfg/example-config.yml b/src/app/bedrock/example-config.yml similarity index 100% rename from src/app/command/internal/cfg/example-config.yml rename to src/app/bedrock/example-config.yml diff --git a/src/app/command/internal/cfg/fixtures_test.go b/src/app/bedrock/fixtures_test.go similarity index 99% rename from src/app/command/internal/cfg/fixtures_test.go rename to src/app/bedrock/fixtures_test.go index d0c8ff2..f52c418 100644 --- a/src/app/command/internal/cfg/fixtures_test.go +++ b/src/app/bedrock/fixtures_test.go @@ -1,4 +1,4 @@ -package cfg_test +package bedrock_test // fullYAML is a realistic complete config used as the baseline fixture. const fullYAML = ` diff --git a/src/app/command/internal/cfg/flags.go b/src/app/bedrock/flags.go similarity index 99% rename from src/app/command/internal/cfg/flags.go rename to src/app/bedrock/flags.go index 9893398..78202ba 100644 --- a/src/app/command/internal/cfg/flags.go +++ b/src/app/bedrock/flags.go @@ -1,4 +1,4 @@ -package cfg +package bedrock import ( "github.com/spf13/cobra" diff --git a/src/app/command/internal/cfg/flags_test.go b/src/app/bedrock/flags_test.go similarity index 81% rename from src/app/command/internal/cfg/flags_test.go rename to src/app/bedrock/flags_test.go index 1cc6291..6bc969c 100644 --- a/src/app/command/internal/cfg/flags_test.go +++ b/src/app/bedrock/flags_test.go @@ -1,13 +1,12 @@ -package cfg_test +package bedrock_test import ( "fmt" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + bedrock "github.com/snivilised/jaywalk/src/app/bedrock" "github.com/spf13/cobra" - - "github.com/snivilised/jaywalk/src/app/command/internal/cfg" ) var _ = Describe("FlagResolver", func() { @@ -28,21 +27,21 @@ var _ = Describe("FlagResolver", func() { Describe("ResolveInt", func() { var ( - resolver *cfg.FlagResolver - flags cfg.FlagsConfig + resolver *bedrock.FlagResolver + flags bedrock.FlagsConfig ) BeforeEach(func() { - flags = cfg.FlagsConfig{ - Invoke: cfg.FlagInvokeDefaults{ + flags = bedrock.FlagsConfig{ + Invoke: bedrock.FlagInvokeDefaults{ "walk": {"files": 10}, "any": {"files": 5, "folders": 3}, }, - Component: cfg.FlagComponentDefaults{ + Component: bedrock.FlagComponentDefaults{ "sampler": {"files": 7, "folders": 2}, }, } - resolver = cfg.NewFlagResolver(flags) + resolver = bedrock.NewFlagResolver(flags) }) Context("when the flag is explicitly set on the CLI", func() { @@ -80,13 +79,13 @@ var _ = Describe("FlagResolver", func() { Context("and no invoke default exists but a component default does", func() { It("uses the component default", func() { // No invoke entry for "run" - flags2 := cfg.FlagsConfig{ - Invoke: cfg.FlagInvokeDefaults{}, - Component: cfg.FlagComponentDefaults{ + flags2 := bedrock.FlagsConfig{ + Invoke: bedrock.FlagInvokeDefaults{}, + Component: bedrock.FlagComponentDefaults{ "sampler": {"files": 7}, }, } - r2 := cfg.NewFlagResolver(flags2) + r2 := bedrock.NewFlagResolver(flags2) cmd := newCmd("run", map[string]int{"files": 1}) val, ok := r2.ResolveInt(cmd, "files", "sampler") @@ -97,7 +96,7 @@ var _ = Describe("FlagResolver", func() { Context("and no config defaults exist at all", func() { It("falls back to the cobra default", func() { - r2 := cfg.NewFlagResolver(cfg.FlagsConfig{}) + r2 := bedrock.NewFlagResolver(bedrock.FlagsConfig{}) cmd := newCmd("run", map[string]int{"files": 42}) val, ok := r2.ResolveInt(cmd, "files", "") @@ -110,12 +109,12 @@ var _ = Describe("FlagResolver", func() { Describe("ApplyShortOverrides", func() { It("remaps the shorthand for the named command's flags", func() { - flags := cfg.FlagsConfig{ - Short: cfg.FlagShortOverride{ + flags := bedrock.FlagsConfig{ + Short: bedrock.FlagShortOverride{ "walk": {"foo": "F"}, }, } - resolver := cfg.NewFlagResolver(flags) + resolver := bedrock.NewFlagResolver(flags) cmd := &cobra.Command{Use: "walk"} cmd.Flags().StringP("foo", "f", "", "a flag") @@ -128,12 +127,12 @@ var _ = Describe("FlagResolver", func() { }) It("is a no-op for commands not in the short overrides", func() { - flags := cfg.FlagsConfig{ - Short: cfg.FlagShortOverride{ + flags := bedrock.FlagsConfig{ + Short: bedrock.FlagShortOverride{ "walk": {"foo": "F"}, }, } - resolver := cfg.NewFlagResolver(flags) + resolver := bedrock.NewFlagResolver(flags) cmd := &cobra.Command{Use: "run"} cmd.Flags().StringP("foo", "f", "", "a flag") diff --git a/src/app/command/internal/cfg/helpers_test.go b/src/app/bedrock/helpers_test.go similarity index 94% rename from src/app/command/internal/cfg/helpers_test.go rename to src/app/bedrock/helpers_test.go index 76d7cce..4f422a5 100644 --- a/src/app/command/internal/cfg/helpers_test.go +++ b/src/app/bedrock/helpers_test.go @@ -1,4 +1,4 @@ -package cfg_test +package bedrock_test import ( "strings" diff --git a/src/app/command/internal/cfg/loader.go b/src/app/bedrock/loader.go similarity index 97% rename from src/app/command/internal/cfg/loader.go rename to src/app/bedrock/loader.go index 5eceba1..46def20 100644 --- a/src/app/command/internal/cfg/loader.go +++ b/src/app/bedrock/loader.go @@ -1,4 +1,4 @@ -package cfg +package bedrock import ( "fmt" @@ -117,20 +117,20 @@ func Load(opts LoadOptions) (*Config, error) { applyEnvBindings(v, opts.EnvPrefix) } else { if err := configureViper(v, opts); err != nil { - return nil, fmt.Errorf("cfg.Load: viper setup: %w", err) + return nil, fmt.Errorf("bedrock.Load: viper setup: %w", err) } if err := v.ReadInConfig(); err != nil { - return nil, fmt.Errorf("cfg.Load: reading config: %w", err) + return nil, fmt.Errorf("bedrock.Load: reading config: %w", err) } } cfg, err := decode(v) if err != nil { - return nil, fmt.Errorf("cfg.Load: decoding: %w", err) + return nil, fmt.Errorf("bedrock.Load: decoding: %w", err) } if err := cfg.Validate(); err != nil { - return nil, fmt.Errorf("cfg.Load: validation: %w", err) + return nil, fmt.Errorf("bedrock.Load: validation: %w", err) } return cfg, nil diff --git a/src/app/command/internal/cfg/loader_test.go b/src/app/bedrock/loader_test.go similarity index 96% rename from src/app/command/internal/cfg/loader_test.go rename to src/app/bedrock/loader_test.go index e1b6e89..115b66b 100644 --- a/src/app/command/internal/cfg/loader_test.go +++ b/src/app/bedrock/loader_test.go @@ -1,12 +1,11 @@ -package cfg_test +package bedrock_test import ( "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "github.com/snivilised/jaywalk/src/app/command/internal/cfg" + "github.com/snivilised/jaywalk/src/app/bedrock" ) var _ = Describe("Load", func() { @@ -16,12 +15,12 @@ var _ = Describe("Load", func() { // ----------------------------------------------------------------------- Context("given a complete, valid YAML config", func() { var ( - config *cfg.Config + config *bedrock.Config err error ) BeforeEach(func() { - config, err = cfg.Load(cfg.LoadOptions{ + config, err = bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(fullYAML), }) }) @@ -134,7 +133,7 @@ var _ = Describe("Load", func() { // ----------------------------------------------------------------------- Context("given a minimal valid YAML config", func() { It("loads successfully with zero-value mapped sections", func() { - config, err := cfg.Load(cfg.LoadOptions{ + config, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(minimalYAML), }) Expect(err).To(BeNil()) diff --git a/src/app/command/internal/cfg/types.go b/src/app/bedrock/types.go similarity index 99% rename from src/app/command/internal/cfg/types.go rename to src/app/bedrock/types.go index 31dd866..bc890a0 100644 --- a/src/app/command/internal/cfg/types.go +++ b/src/app/bedrock/types.go @@ -1,4 +1,4 @@ -package cfg +package bedrock import ( "time" diff --git a/src/app/command/internal/cfg/validate.go b/src/app/bedrock/validate.go similarity index 99% rename from src/app/command/internal/cfg/validate.go rename to src/app/bedrock/validate.go index bb72ca3..280f469 100644 --- a/src/app/command/internal/cfg/validate.go +++ b/src/app/bedrock/validate.go @@ -1,4 +1,4 @@ -package cfg +package bedrock import ( "errors" diff --git a/src/app/command/internal/cfg/validate_test.go b/src/app/bedrock/validate_test.go similarity index 85% rename from src/app/command/internal/cfg/validate_test.go rename to src/app/bedrock/validate_test.go index 8c724cd..6bd56ea 100644 --- a/src/app/command/internal/cfg/validate_test.go +++ b/src/app/bedrock/validate_test.go @@ -1,10 +1,9 @@ -package cfg_test +package bedrock_test import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "github.com/snivilised/jaywalk/src/app/command/internal/cfg" + bedrock "github.com/snivilised/jaywalk/src/app/bedrock" ) var _ = Describe("Validate", func() { @@ -15,7 +14,7 @@ var _ = Describe("Validate", func() { Describe("LoggingConfig.Validate", func() { DescribeTable("invalid log levels", func(level string) { - c := cfg.LoggingConfig{Level: level} + c := bedrock.LoggingConfig{Level: level} Expect(c.Validate()).NotTo(Succeed()) }, Entry("verbose", "verbose"), @@ -25,7 +24,7 @@ var _ = Describe("Validate", func() { DescribeTable("valid log levels", func(level string) { - c := cfg.LoggingConfig{Level: level} + c := bedrock.LoggingConfig{Level: level} Expect(c.Validate()).To(Succeed()) }, Entry("trace", "trace"), @@ -39,29 +38,29 @@ var _ = Describe("Validate", func() { ) It("rejects negative max-size-in-mb", func() { - c := cfg.LoggingConfig{MaxSizeInMB: -1, Level: "info"} + c := bedrock.LoggingConfig{MaxSizeInMB: -1, Level: "info"} Expect(c.Validate()).NotTo(Succeed()) }) It("rejects negative max-backups", func() { - c := cfg.LoggingConfig{MaxBackups: -1, Level: "info"} + c := bedrock.LoggingConfig{MaxBackups: -1, Level: "info"} Expect(c.Validate()).NotTo(Succeed()) }) It("rejects negative max-age-in-days", func() { - c := cfg.LoggingConfig{MaxAgeInDays: -1, Level: "info"} + c := bedrock.LoggingConfig{MaxAgeInDays: -1, Level: "info"} Expect(c.Validate()).NotTo(Succeed()) }) It("accepts zero values", func() { - c := cfg.LoggingConfig{} + c := bedrock.LoggingConfig{} Expect(c.Validate()).To(Succeed()) }) }) Describe("InteractionConfig.Validate", func() { It("rejects bad log level", func() { - _, err := cfg.Load(cfg.LoadOptions{ + _, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(badLogLevelYAML), }) Expect(err).NotTo(BeNil()) @@ -74,7 +73,7 @@ var _ = Describe("Validate", func() { // ----------------------------------------------------------------------- Describe("InteractionConfig.Validate", func() { It("rejects negative per-item-delay", func() { - _, err := cfg.Load(cfg.LoadOptions{ + _, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(negativeDurationYAML), }) Expect(err).NotTo(BeNil()) @@ -87,7 +86,7 @@ var _ = Describe("Validate", func() { // ----------------------------------------------------------------------- Describe("FlagsConfig.Validate", func() { It("rejects multi-character short overrides", func() { - _, err := cfg.Load(cfg.LoadOptions{ + _, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(badShortYAML), }) Expect(err).NotTo(BeNil()) @@ -100,7 +99,7 @@ var _ = Describe("Validate", func() { // ----------------------------------------------------------------------- Describe("actions validation", func() { It("rejects an action with an empty cmd", func() { - _, err := cfg.Load(cfg.LoadOptions{ + _, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(emptyCmdYAML), }) Expect(err).NotTo(BeNil()) @@ -113,7 +112,7 @@ var _ = Describe("Validate", func() { // ----------------------------------------------------------------------- Describe("pipeline validation", func() { It("rejects a pipeline step referencing an unknown action", func() { - _, err := cfg.Load(cfg.LoadOptions{ + _, err := bedrock.Load(bedrock.LoadOptions{ ViperInstance: viperFromYAML(missingActionYAML), }) Expect(err).NotTo(BeNil()) @@ -126,7 +125,7 @@ var _ = Describe("Validate", func() { // ----------------------------------------------------------------------- Describe("aggregate errors", func() { It("reports all failures in one error", func() { - c := &cfg.Config{} + c := &bedrock.Config{} c.Mapped.Logging.Level = "bad-level" c.Mapped.Logging.MaxSizeInMB = -5 err := c.Validate() diff --git a/src/app/command/bootstrap.go b/src/app/command/bootstrap.go index dcf7f1a..52c2920 100644 --- a/src/app/command/bootstrap.go +++ b/src/app/command/bootstrap.go @@ -6,7 +6,7 @@ import ( "github.com/cubiest/jibberjabber" "github.com/snivilised/jaywalk/src/internal/third/lo" - "github.com/snivilised/jaywalk/locale" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" "github.com/snivilised/mamba/assist" macfg "github.com/snivilised/mamba/assist/cfg" @@ -16,7 +16,8 @@ import ( "github.com/spf13/viper" "golang.org/x/text/language" - "github.com/snivilised/jaywalk/src/app/command/internal/cfg" + bedrock "github.com/snivilised/jaywalk/src/app/bedrock" + jac "github.com/snivilised/jaywalk/src/app/controller" "github.com/snivilised/jaywalk/src/app/ui" ) @@ -43,8 +44,7 @@ func (j *Jabber) Scan() language.Tag { // ConfigureOptions // --------------------------------------------------------------------------- -// ConfigInfo describes the configuration file that should be loaded, -// including its name, type, path and the viper instance to use. +// ConfigInfo describes the configuration file that should be loaded. type ConfigInfo struct { Name string ConfigType string @@ -52,8 +52,8 @@ type ConfigInfo struct { Viper macfg.ViperConfig } -// ConfigureOptions groups configuration options that influence how -// Bootstrap initialises localisation and configuration. +// ConfigureOptions groups options that influence how Bootstrap +// initialises localisation and configuration. type ConfigureOptions struct { Detector LocaleDetector Config ConfigInfo @@ -67,24 +67,34 @@ type ConfigureOptionFn func(*ConfigureOptions) // Bootstrap // --------------------------------------------------------------------------- -// Bootstrap constructs the full cobra command tree and owns all -// mamba param-set registrations. It is the single entry point for -// application startup wiring. +// Bootstrap is a pure composition root. Its sole responsibility is +// wiring: it constructs the cobra command tree, registers param-sets, +// creates the ApplicationController, and connects everything together. +// It contains no business logic and no traversal decisions. +// +// Code smell checklist (should remain clean): +// - No direct calls to agenor from Bootstrap +// - No UI rendering logic in Bootstrap +// - No flag interpretation beyond resolving --tui into a ui.Manager type Bootstrap struct { container *assist.CobraContainer options ConfigureOptions // Cfg is populated after configure() reads viper. - Cfg *cfg.Config + Cfg *bedrock.Config - // UI is constructed from the --tui flag value in PersistentPreRunE - // and injected into every command's Inputs struct. + // UI is resolved from --tui in PersistentPreRunE and passed + // into requests; Bootstrap does not use it directly. UI ui.Manager - // root param-set - stashed so PersistentPreRunE and RunE can read it. + // coord is the single ApplicationController instance wired at + // startup and shared by all command handlers. + coord *jac.Coordinator + + // root param-set rootPs *assist.ParamSet[RootParameterSet] - // shared family param-sets (persistent, inherited by all sub-commands) + // shared persistent families previewFam *assist.ParamSet[store.PreviewParameterSet] cascadeFam *assist.ParamSet[store.CascadeParameterSet] samplingFam *assist.ParamSet[store.SamplingParameterSet] @@ -119,7 +129,8 @@ func (b *Bootstrap) prepare() { } // Root builds the command tree and returns the root command, ready -// to be executed. +// to be executed. This is the composition root: all wiring happens +// here and only here. func (b *Bootstrap) Root(options ...ConfigureOptionFn) *cobra.Command { b.prepare() @@ -129,6 +140,10 @@ func (b *Bootstrap) Root(options ...ConfigureOptionFn) *cobra.Command { b.configure() + // Construct the ApplicationController once. Command handlers receive + // it via b.ctrl - they never construct it themselves. + b.coord = jac.New() + b.container = assist.NewCobraContainer( &cobra.Command{ Use: ApplicationName, @@ -136,9 +151,10 @@ func (b *Bootstrap) Root(options ...ConfigureOptionFn) *cobra.Command { Long: li18ngo.Text(locale.RootCmdLongDescTemplData{}), Version: fmt.Sprintf("'%v'", Version), - // PersistentPreRunE runs after flag parsing but before any - // RunE handler. It resolves --tui into a UI manager so all - // sub-commands receive a fully constructed b.UI. + // PersistentPreRunE resolves --tui into a ui.Manager and + // stores it on Bootstrap so command handlers can include it + // in their requests. This is the only UI concern Bootstrap + // is permitted to touch. PersistentPreRunE: func(_ *cobra.Command, _ []string) error { mgr, err := ui.New(b.rootPs.Native.TUI) if err != nil { @@ -162,7 +178,7 @@ func (b *Bootstrap) Root(options ...ConfigureOptionFn) *cobra.Command { } // --------------------------------------------------------------------------- -// configure - viper + i18n (your existing logic, unchanged) +// configure // --------------------------------------------------------------------------- func (b *Bootstrap) configure() { @@ -185,11 +201,7 @@ func (b *Bootstrap) configure() { fmt.Fprintln(os.Stderr, msg) } - // Load jay's typed config on top of viper now that the file is read. - // GlobalViperConfig delegates to viper's global instance, so we use - // viper.GetViper() to obtain the underlying *viper.Viper directly, - // which allows cfg.Load to skip ReadInConfig on an already-read instance. - b.Cfg, err = cfg.Load(cfg.LoadOptions{ + b.Cfg, err = bedrock.Load(bedrock.LoadOptions{ ViperInstance: viper.GetViper(), }) if err != nil { @@ -231,17 +243,13 @@ func handleLangSetting() { } // --------------------------------------------------------------------------- -// buildRootCommand - root param-set and shared persistent families +// buildRootCommand // --------------------------------------------------------------------------- func (b *Bootstrap) buildRootCommand(container *assist.CobraContainer) { root := container.Root() - // root param-set: --tui (and any future root-level flags) b.rootPs = assist.NewParamSet[RootParameterSet](root) - - // --tui(-t) : selects the display renderer; defaults to "linear". - // Validated eagerly so a bad value is rejected before traversal starts. b.rootPs.BindString( assist.NewFlagInfoOnFlagSet( `tui display mode: "linear" (default) or a named Charm-based renderer`, @@ -251,26 +259,22 @@ func (b *Bootstrap) buildRootCommand(container *assist.CobraContainer) { ), &b.rootPs.Native.TUI, ) - container.MustRegisterParamSet(RootPsName, b.rootPs) - // family: preview [--dry-run(D)] b.previewFam = assist.NewParamSet[store.PreviewParameterSet](root) b.previewFam.Native.BindAll(b.previewFam, root.PersistentFlags()) container.MustRegisterParamSet(PreviewFamName, b.previewFam) - // family: cascade [--depth, --no-recurse] b.cascadeFam = assist.NewParamSet[store.CascadeParameterSet](root) b.cascadeFam.Native.BindAll(b.cascadeFam, root.PersistentFlags()) container.MustRegisterParamSet(CascadeFamName, b.cascadeFam) - // family: sampling [--sample, --no-files, --no-folders, --last] b.samplingFam = assist.NewParamSet[store.SamplingParameterSet](root) b.samplingFam.Native.BindAll(b.samplingFam, root.PersistentFlags()) container.MustRegisterParamSet(SamplingFamName, b.samplingFam) } -// sharedFamilies is a convenience accessor for RunE closures. +// sharedFamilies is a convenience accessor used by runWalk and runRun. func (b *Bootstrap) sharedFamilies() SharedFamilies { return SharedFamilies{ Preview: b.previewFam, diff --git a/src/app/command/options.go b/src/app/command/options.go new file mode 100644 index 0000000..038ba53 --- /dev/null +++ b/src/app/command/options.go @@ -0,0 +1,53 @@ +package command + +import ( + "fmt" + + "github.com/snivilised/jaywalk/src/agenor" + "github.com/snivilised/jaywalk/src/agenor/pref" +) + +// buildOptions translates shared flag values into agenor option functions. +// Shared between walk and run commands. +func buildOptions(families SharedFamilies) []pref.Option { + var opts []pref.Option + + if families.Cascade.Native.NoRecurse { + opts = append(opts, agenor.WithNoRecurse()) + } + + if d := families.Cascade.Native.Depth; d > 0 { + opts = append(opts, agenor.WithDepth(d)) + } + + // TODO: implement DryRun on agenor + // if families.Preview.Native.DryRun { + // opts = append(opts, agenor.WithDryRun()) + // } + + if families.Sampling.Native.IsSampling { + opts = append(opts, agenor.WithSamplingOptions(&pref.SamplingOptions{ + NoOf: pref.EntryQuantities{ + Files: families.Sampling.Native.NoFiles, + Directories: families.Sampling.Native.NoFolders, + }, + })) + } + + return opts +} + +// resolveResumeStrategy maps the --resume flag string to the agenor constant. +func resolveResumeStrategy(resume string) (agenor.ResumeStrategy, error) { + switch resume { + case ResumeStrategySpawn: + return agenor.ResumeStrategySpawn, nil + case ResumeStrategyFastward: + return agenor.ResumeStrategyFastward, nil + default: + return 0, fmt.Errorf( + "invalid --resume value %q: must be %q or %q", + resume, ResumeStrategySpawn, ResumeStrategyFastward, + ) + } +} diff --git a/src/app/command/param-sets.go b/src/app/command/param-sets.go index 9896c0f..904585e 100644 --- a/src/app/command/param-sets.go +++ b/src/app/command/param-sets.go @@ -1,6 +1,8 @@ package command -import "github.com/snivilised/mamba/store" +import ( + "github.com/snivilised/mamba/store" +) // --------------------------------------------------------------------------- // Subscription flag values - what the user types on the command line diff --git a/src/app/command/run-cmd.go b/src/app/command/run-cmd.go index 67029bc..7281679 100644 --- a/src/app/command/run-cmd.go +++ b/src/app/command/run-cmd.go @@ -1,8 +1,6 @@ package command import ( - "context" - "fmt" "sync" "github.com/snivilised/mamba/assist" @@ -10,8 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/snivilised/jaywalk/src/agenor" - "github.com/snivilised/jaywalk/src/agenor/enums" - "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/app/controller" ) const ( @@ -35,7 +32,6 @@ Use --action or --pipeline to name a config-defined operation.`, runPs := assist.NewParamSet[RunParameterSet](runCmd) // --subscribe(-s): which node types to visit - // runPs.BindString( assist.NewFlagInfo( "subscribe node types to visit: \"files\", \"dirs\" or \"all\" (default)", @@ -46,7 +42,6 @@ Use --action or --pipeline to name a config-defined operation.`, ) // --action(-a) - // runPs.BindString( assist.NewFlagInfo( "action name of the config-defined action to invoke for each matched node", @@ -57,7 +52,6 @@ Use --action or --pipeline to name a config-defined operation.`, ) // --pipeline(-p) - // runPs.BindString( assist.NewFlagInfo( "pipeline name of the config-defined pipeline to execute", @@ -68,7 +62,6 @@ Use --action or --pipeline to name a config-defined operation.`, ) // --resume(-r) - // runPs.BindString( assist.NewFlagInfo( `resume strategy for an interrupted traversal: "spawn" or "fastward"`, @@ -78,15 +71,13 @@ Use --action or --pipeline to name a config-defined operation.`, &runPs.Native.Resume, ) - // family: worker-pool [--cpu(C), --now] - // run-only, registered on the run command's local flags. - // + // family: worker-pool [--cpu, --now] + // Local to run, registered on the run command's own flags. workerPoolFam := assist.NewParamSet[store.WorkerPoolParameterSet](runCmd) workerPoolFam.Native.BindAll(workerPoolFam, runCmd.Flags()) container.MustRegisterParamSet(WorkerPoolFamName, workerPoolFam) // poly-filter family - local to run, not inherited. - // polyFam := assist.NewParamSet[store.PolyFilterParameterSet](runCmd) polyFam.Native.BindAll(polyFam) @@ -99,80 +90,58 @@ Use --action or --pipeline to name a config-defined operation.`, b.workerPoolFam = workerPoolFam } -// runRun is the RunE handler for the run command. +// runRun is the RunE handler for the run command. It parses flags, +// constructs the agenor.Hare scenario, and delegates to the coordinator. +// The WaitGroup is owned here — the adapter created it and waits on it +// after the coordinator returns. func (b *Bootstrap) runRun(cmd *cobra.Command, args []string) error { - inputs := &RunInputs{ - Tree: args[0], - UI: b.UI, - ParamSet: b.runPs, - PolyFam: b.runPolyFam, - SharedFamilies: b.sharedFamilies(), - WorkerPool: b.workerPoolFam, - } - - return executeRun(cmd.Context(), inputs) -} - -// executeRun builds and runs an agenor concurrent traversal using agenor.Hare, -// which supports both prime and resume modes with a worker pool. -func executeRun(ctx context.Context, inputs *RunInputs) error { - subscription, err := ResolveSubscription(inputs.ParamSet.Native.Subscribe) + subscription, err := ResolveSubscription(b.runPs.Native.Subscribe) if err != nil { return err } - isPrime := inputs.ParamSet.Native.Resume == "" - opts := buildOptions(inputs.SharedFamilies) + opts := buildOptions(b.sharedFamilies()) - if inputs.WorkerPool.Native.CPU { + // Worker pool options are appended here — they come from run-specific + // flags and the coordinator has no knowledge of them. + if b.workerPoolFam.Native.CPU { opts = append(opts, agenor.WithCPU()) - } else if n := inputs.WorkerPool.Native.NoWorkers; n > 0 { + } else if n := b.workerPoolFam.Native.NoWorkers; n > 0 { opts = append(opts, agenor.WithNoW(uint(n))) } - var facade pref.Facade + isPrime := b.runPs.Native.Resume == "" + wg := &sync.WaitGroup{} + + base := controller.Request{ + Subscription: subscription, + Options: opts, + ActionName: b.runPs.Native.Action, + PipelineName: b.runPs.Native.Pipeline, + Scenario: agenor.Hare(isPrime, wg), + UI: b.UI, + } + + var execErr error if isPrime { - facade = &pref.Using{ - Subscription: subscription, - Head: pref.Head{ - Handler: func(servant agenor.Servant) error { - return inputs.UI.OnNode(servant.Node()) - }, - }, - Tree: inputs.Tree, - } + execErr = b.coord.ExecutePrime(cmd.Context(), &controller.PrimeRequest{ + Request: base, + Tree: args[0], + }) } else { - strategy, e := resolveResumeStrategy(inputs.ParamSet.Native.Resume) + strategy, e := resolveResumeStrategy(b.runPs.Native.Resume) if e != nil { return e } - facade = &pref.Relic{ - Head: pref.Head{ - Handler: func(servant agenor.Servant) error { - return inputs.UI.OnNode(servant.Node()) - }, - }, + execErr = b.coord.ExecuteResume(cmd.Context(), &controller.ResumeRequest{ + Request: base, Strategy: strategy, - } + }) } - wg := sync.WaitGroup{} - - result, err := agenor.Hare(isPrime, &wg)(facade, opts...).Navigate(ctx) wg.Wait() - if err != nil { - inputs.UI.Error(fmt.Sprintf("run failed: %v", err)) - return err - } - - inputs.UI.Info(fmt.Sprintf( - "run complete: %d files, %d dirs visited", - result.Metrics().Count(enums.MetricNoFilesInvoked), - result.Metrics().Count(enums.MetricNoDirectoriesInvoked), - )) - - return nil + return execErr } diff --git a/src/app/command/walk-cmd.go b/src/app/command/walk-cmd.go index b4b2639..05c3068 100644 --- a/src/app/command/walk-cmd.go +++ b/src/app/command/walk-cmd.go @@ -1,16 +1,12 @@ package command import ( - "context" - "fmt" - "github.com/snivilised/mamba/assist" "github.com/snivilised/mamba/store" "github.com/spf13/cobra" "github.com/snivilised/jaywalk/src/agenor" - "github.com/snivilised/jaywalk/src/agenor/enums" - "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/app/controller" ) const ( @@ -35,7 +31,6 @@ Use --resume to re-enter a previously interrupted traversal.`, walkPs := assist.NewParamSet[WalkParameterSet](walkCmd) // --subscribe(-s): which node types to visit - // walkPs.BindString( assist.NewFlagInfo( "subscribe node types to visit: \"files\", \"dirs\" or \"all\" (default)", @@ -46,7 +41,6 @@ Use --resume to re-enter a previously interrupted traversal.`, ) // --action(-a): name of a config-defined action to run per node - // walkPs.BindString( assist.NewFlagInfo( "action name of the config-defined action to invoke for each matched node", @@ -57,7 +51,6 @@ Use --resume to re-enter a previously interrupted traversal.`, ) // --pipeline(-p): name of a config-defined pipeline to execute - // walkPs.BindString( assist.NewFlagInfo( "pipeline name of the config-defined pipeline to execute", @@ -68,7 +61,6 @@ Use --resume to re-enter a previously interrupted traversal.`, ) // --resume(-r): resume strategy for interrupted traversals - // walkPs.BindString( assist.NewFlagInfo( `resume strategy for an interrupted traversal: "spawn" or "fastward"`, @@ -78,9 +70,8 @@ Use --resume to re-enter a previously interrupted traversal.`, &walkPs.Native.Resume, ) - // poly-filter family [--files-glob(b), --files-rx, --folders-glob, --folders-rx] - // Not passed to PersistentFlags so it is local to walk only. - // + // poly-filter family [--files-glob, --files-rx, --folders-glob, --folders-rx] + // Local to walk only, not inherited by sub-commands. polyFam := assist.NewParamSet[store.PolyFilterParameterSet](walkCmd) polyFam.Native.BindAll(polyFam) @@ -92,114 +83,41 @@ Use --resume to re-enter a previously interrupted traversal.`, b.walkPolyFam = polyFam } -// runWalk is the RunE handler for the walk command. +// runWalk is the RunE handler for the walk command. It parses flags, +// constructs the agenor.Tortoise scenario, and delegates to the +// coordinator. No agenor traversal logic lives here. func (b *Bootstrap) runWalk(cmd *cobra.Command, args []string) error { - inputs := &WalkInputs{ - Tree: args[0], - UI: b.UI, - ParamSet: b.walkPs, - PolyFam: b.walkPolyFam, - SharedFamilies: b.sharedFamilies(), - } - - return executeWalk(cmd.Context(), inputs) -} - -// executeWalk builds and runs an agenor walk traversal using agenor.Tortoise, -// which supports both prime and resume modes for synchronous walking. -func executeWalk(ctx context.Context, inputs *WalkInputs) error { - subscription, err := ResolveSubscription(inputs.ParamSet.Native.Subscribe) + subscription, err := ResolveSubscription(b.walkPs.Native.Subscribe) if err != nil { return err } - isPrime := inputs.ParamSet.Native.Resume == "" - opts := buildOptions(inputs.SharedFamilies) + opts := buildOptions(b.sharedFamilies()) + isPrime := b.walkPs.Native.Resume == "" - var facade pref.Facade + base := controller.Request{ + Subscription: subscription, + Options: opts, + ActionName: b.walkPs.Native.Action, + PipelineName: b.walkPs.Native.Pipeline, + Scenario: agenor.Tortoise(isPrime), + UI: b.UI, + } if isPrime { - facade = &pref.Using{ - Subscription: subscription, - Head: pref.Head{ - Handler: func(servant agenor.Servant) error { - return inputs.UI.OnNode(servant.Node()) - }, - }, - Tree: inputs.Tree, - } - } else { - strategy, e := resolveResumeStrategy(inputs.ParamSet.Native.Resume) - if e != nil { - return e - } - - facade = &pref.Relic{ - Head: pref.Head{ - Handler: func(servant agenor.Servant) error { - return inputs.UI.OnNode(servant.Node()) - }, - }, - Strategy: strategy, - } + return b.coord.ExecutePrime(cmd.Context(), &controller.PrimeRequest{ + Request: base, + Tree: args[0], + }) } - result, err := agenor.Tortoise(isPrime)(facade, opts...).Navigate(ctx) + strategy, err := resolveResumeStrategy(b.walkPs.Native.Resume) if err != nil { - inputs.UI.Error(fmt.Sprintf("walk failed: %v", err)) return err } - inputs.UI.Info(fmt.Sprintf( - "walk complete: %d files, %d dirs visited", - result.Metrics().Count(enums.MetricNoFilesInvoked), - result.Metrics().Count(enums.MetricNoDirectoriesInvoked), - )) - - return nil -} - -// buildOptions translates shared flag values into agenor option functions. -// Shared between walk and run to avoid duplication. -func buildOptions(families SharedFamilies) []pref.Option { - var opts []pref.Option - - if families.Cascade.Native.NoRecurse { - opts = append(opts, agenor.WithNoRecurse()) - } - - if d := families.Cascade.Native.Depth; d > 0 { - opts = append(opts, agenor.WithDepth(d)) - } - - // TODO: implement DryRun on agenor - // if families.Preview.Native.DryRun { - // opts = append(opts, agenor.WithDryRun()) - // } - - if families.Sampling.Native.IsSampling { - opts = append(opts, agenor.WithSamplingOptions(&pref.SamplingOptions{ - NoOf: pref.EntryQuantities{ - Files: families.Sampling.Native.NoFiles, - Directories: families.Sampling.Native.NoFolders, - }, - })) - } - - return opts -} - -// resolveResumeStrategy maps the --resume string to the agenor constant. -func resolveResumeStrategy(resume string) (agenor.ResumeStrategy, error) { - switch resume { - case ResumeStrategySpawn: - return agenor.ResumeStrategySpawn, nil - case ResumeStrategyFastward: - return agenor.ResumeStrategyFastward, nil - default: - return 0, fmt.Errorf( - "invalid --resume value %q: must be %q or %q", - resume, ResumeStrategySpawn, ResumeStrategyFastward, - ) - } + return b.coord.ExecuteResume(cmd.Context(), &controller.ResumeRequest{ + Request: base, + Strategy: strategy, + }) } diff --git a/src/app/controller/coordinator.go b/src/app/controller/coordinator.go new file mode 100644 index 0000000..054923f --- /dev/null +++ b/src/app/controller/coordinator.go @@ -0,0 +1,74 @@ +package controller + +import ( + "context" + + "github.com/snivilised/jaywalk/src/agenor" + "github.com/snivilised/jaywalk/src/agenor/enums" + "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/app/report" +) + +// Coordinator coordinates the layers between the command adapters and +// the agenor traversal engine. It is the single place that constructs +// pref.Facade values and calls into agenor via the agenor.Scenario on +// the request. It never imports cobra, mamba, or the command package. +// +// Dependency direction: command → controller → agenor +type Coordinator struct{} + +// New returns a ready-to-use Coordinator. +func New() *Coordinator { + return &Coordinator{} +} + +// ExecutePrime runs a fresh directory traversal using the scenario +// provided on the request. The command adapter is responsible for +// constructing the correct agenor.Scenario (Tortoise or Hare). +func (c *Coordinator) ExecutePrime(ctx context.Context, req *PrimeRequest) error { + facade := &pref.Using{ + Subscription: req.Subscription, + Head: pref.Head{ + Handler: func(servant agenor.Servant) error { + return c.handleNode(servant.Node(), &req.Request) + }, + }, + Tree: req.Tree, + } + + return c.execute(ctx, &req.Request, facade) +} + +// ExecuteResume resumes an interrupted traversal using the scenario +// provided on the request. The command adapter is responsible for +// constructing the correct agenor.Scenario (Tortoise or Hare). +func (c *Coordinator) ExecuteResume(ctx context.Context, req *ResumeRequest) error { + facade := &pref.Relic{ + Head: pref.Head{ + Handler: func(servant agenor.Servant) error { + return c.handleNode(servant.Node(), &req.Request) + }, + }, + Strategy: req.Strategy, + } + + return c.execute(ctx, &req.Request, facade) +} + +// execute is the shared orchestration path for both prime and resume +// traversals. It calls the scenario, collects metrics, and notifies +// the UI via OnComplete. +func (c *Coordinator) execute(ctx context.Context, req *Request, facade pref.Facade) error { + result, err := req.Scenario(facade, req.Options...).Navigate(ctx) + + t := &report.Traversal{Err: err} + if result != nil { + t.FilesVisited = result.Metrics().Count(enums.MetricNoFilesInvoked) + t.DirsVisited = result.Metrics().Count(enums.MetricNoDirectoriesInvoked) + t.Elapsed = result.Session().Elapsed() + } + + req.UI.OnComplete(t) + + return err +} diff --git a/src/app/controller/dispatch.go b/src/app/controller/dispatch.go new file mode 100644 index 0000000..c408237 --- /dev/null +++ b/src/app/controller/dispatch.go @@ -0,0 +1,50 @@ +package controller + +import ( + "github.com/snivilised/jaywalk/src/agenor/core" + "github.com/snivilised/jaywalk/src/app/report" +) + +// handleNode dispatches to the appropriate per-node handler based on +// whether an action, pipeline, or neither is configured on the request. +func (c *Coordinator) handleNode(node *core.Node, req *Request) error { + switch { + case req.PipelineName != "": + e := c.executePipeline(node, req.PipelineName) + req.UI.OnPipelineEvent(e) + return e.Err + + case req.ActionName != "": + e := c.executeAction(node, req.ActionName) + req.UI.OnActionEvent(e) + return e.Err + + default: + req.UI.OnNodeEvent(&report.NeutralEvent{ + DisplayEvent: report.DisplayEvent{Node: node}, + }) + return nil + } +} + +// executeAction composes and executes a configured action against a node. +// Composition of the execution string is a future concern — this is a stub. +func (c *Coordinator) executeAction(node *core.Node, name string) *report.ActionEvent { + return &report.ActionEvent{ + DisplayEvent: report.DisplayEvent{ + Node: node, + Name: name, + }, + } +} + +// executePipeline composes and executes a configured pipeline against a node. +// Composition of the execution string is a future concern — this is a stub. +func (c *Coordinator) executePipeline(node *core.Node, name string) *report.PipelineEvent { + return &report.PipelineEvent{ + DisplayEvent: report.DisplayEvent{ + Node: node, + Name: name, + }, + } +} diff --git a/src/app/controller/requests.go b/src/app/controller/requests.go new file mode 100644 index 0000000..d8c2ee6 --- /dev/null +++ b/src/app/controller/requests.go @@ -0,0 +1,54 @@ +package controller + +import ( + "github.com/snivilised/jaywalk/src/agenor" + "github.com/snivilised/jaywalk/src/agenor/enums" + "github.com/snivilised/jaywalk/src/agenor/pref" + "github.com/snivilised/jaywalk/src/app/ui" +) + +// Request holds the fields common to all traversal requests. +// It is embedded as the first field in PrimeRequest and ResumeRequest. +type Request struct { + // Subscription controls which node types are visited. + Subscription enums.Subscription + + // Options are the agenor option functions derived from shared flags. + Options []pref.Option + + // ActionName is the name of the configured action to execute per node. + // Empty when no action is configured. + ActionName string + + // PipelineName is the name of the configured pipeline to execute per node. + // Empty when no pipeline is configured. + PipelineName string + + // Scenario is the agenor scenario provided by the command adapter. + // It encapsulates the walk/run distinction so the coordinator is + // unaware of it. Set to agenor.Tortoise(isPrime) for walk or + // agenor.Hare(isPrime, wg) for run. + Scenario agenor.Scenario + + // UI is the display manager injected by Bootstrap via PersistentPreRunE. + UI ui.Manager +} + +// PrimeRequest carries everything the coordinator needs to execute a +// fresh directory traversal. +type PrimeRequest struct { + Request + + // Tree is the root directory path to traverse. + Tree string +} + +// ResumeRequest carries everything the coordinator needs to resume an +// interrupted traversal. Strategy is agenor's internal resume strategy, +// distinct from the app-layer Scenario field on Request. +type ResumeRequest struct { + Request + + // Strategy controls how the resume proceeds within agenor. + Strategy enums.ResumeStrategy +} diff --git a/src/app/report/doc.go b/src/app/report/doc.go new file mode 100644 index 0000000..0058b16 --- /dev/null +++ b/src/app/report/doc.go @@ -0,0 +1,2 @@ +// Package report tbd +package report diff --git a/src/app/report/report-defs.go b/src/app/report/report-defs.go new file mode 100644 index 0000000..4b2ed35 --- /dev/null +++ b/src/app/report/report-defs.go @@ -0,0 +1,58 @@ +package report + +import ( + "time" + + "github.com/snivilised/jaywalk/src/agenor/core" +) + +// DisplayEvent is the base event embedded into all UI events. It carries +// the node that triggered the event and an optional name identifying the +// action or pipeline that was invoked. Name is empty for NodeEvent. +type DisplayEvent struct { + Node *core.Node + Name string +} + +// NeutralEvent is emitted per node visit when no action or pipeline is +// configured. The UI decides how to render the node information. +type NeutralEvent struct { + DisplayEvent +} + +// ActionEvent is emitted when a configured action has been executed +// against a node. ExecutionString is the composed CLI string that was +// (or would be) run - population of this field is a future concern. +type ActionEvent struct { + DisplayEvent + ExecutionString string + Err error +} + +// PipelineEvent is emitted when a configured pipeline has been executed +// against a node. A pipeline is a sequence of actions against the same +// node. ExecutionString is the composed CLI string - population of this +// field is a future concern. +type PipelineEvent struct { + DisplayEvent + ExecutionString string + Err error +} + +// Traversal captures the outcome of a completed directory traversal. +// It is populated by the controller and handed to the UI via OnComplete. +// The UI decides how to present each field - colour, layout, and +// formatting are entirely its own concern. +type Traversal struct { + // FilesVisited is the number of file nodes invoked during traversal. + FilesVisited core.MetricValue + + // DirsVisited is the number of directory nodes invoked during traversal. + DirsVisited core.MetricValue + + // Elapsed is the total wall-clock time taken for the traversal. + Elapsed time.Duration + + // Err holds the traversal error, if any. Nil on success. + Err error +} diff --git a/src/app/ui/linear.go b/src/app/ui/linear.go index bb76bda..c43e795 100644 --- a/src/app/ui/linear.go +++ b/src/app/ui/linear.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - "github.com/snivilised/jaywalk/src/agenor/core" + "github.com/snivilised/jaywalk/src/app/report" ) // linear is the default UI implementation. It writes plain text to stdout @@ -15,31 +15,53 @@ type linear struct { mu sync.Mutex } -// OnNode prints the visited node's path to stdout. -func (l *linear) OnNode(node *core.Node) error { +// OnNodeEvent prints the visited node's path to stdout. +func (l *linear) OnNodeEvent(e *report.NeutralEvent) { l.mu.Lock() defer l.mu.Unlock() - fmt.Printf("-> %v\n", node.Path) - return nil + fmt.Printf("-> %v\n", e.Node.Path) } -// Info writes a plain informational line to stdout. -func (l *linear) Info(msg string) { +// OnActionEvent prints the action name and node path to stdout. +func (l *linear) OnActionEvent(e *report.ActionEvent) { l.mu.Lock() defer l.mu.Unlock() - fmt.Println("i", msg) + + if e.Err != nil { + fmt.Printf("x action %q failed on %v: %v\n", e.Name, e.Node.Path, e.Err) + return + } + + fmt.Printf("a [%v] %v\n", e.Name, e.Node.Path) } -// Warn writes a warning line to stdout. -func (l *linear) Warn(msg string) { +// OnPipelineEvent prints the pipeline name and node path to stdout. +func (l *linear) OnPipelineEvent(e *report.PipelineEvent) { l.mu.Lock() defer l.mu.Unlock() - fmt.Println("!", msg) + + if e.Err != nil { + fmt.Printf("x pipeline %q failed on %v: %v\n", e.Name, e.Node.Path, e.Err) + return + } + + fmt.Printf("p [%v] %v\n", e.Name, e.Node.Path) } -// Error writes an error line to stdout. -func (l *linear) Error(msg string) { +// OnComplete renders the traversal outcome as plain text. +func (l *linear) OnComplete(t *report.Traversal) { l.mu.Lock() defer l.mu.Unlock() - fmt.Println("x", msg) + + if t.Err != nil { + fmt.Printf("x traversal failed: %v\n", t.Err) + return + } + + fmt.Printf( + "i complete: %d files, %d dirs visited in %s\n", + t.FilesVisited, + t.DirsVisited, + t.Elapsed.Round(1e6), + ) } diff --git a/src/app/ui/manager.go b/src/app/ui/manager.go index eb27482..ab059f3 100644 --- a/src/app/ui/manager.go +++ b/src/app/ui/manager.go @@ -3,7 +3,7 @@ package ui import ( "fmt" - "github.com/snivilised/jaywalk/src/agenor/core" + "github.com/snivilised/jaywalk/src/app/report" ) // --------------------------------------------------------------------------- @@ -24,23 +24,25 @@ const ( // --------------------------------------------------------------------------- // Manager is the single interface all UI implementations satisfy. -// Command handlers and agenor node callbacks interact only with this -// interface, never with a concrete type. +// It is purely reactive - all methods are event notifications. The UI +// decides how to render each event; no formatting logic lives outside +// the UI layer. type Manager interface { - // OnNode is called for every node the traversal visits. The node is - // obtained by the command layer via servant.Node() before being passed - // here. It is safe to call from multiple goroutines (implementations - // must ensure this). - OnNode(node *core.Node) error + // OnNodeEvent is called per node visit when no action or pipeline + // is configured. + OnNodeEvent(e *report.NeutralEvent) - // Info writes a general informational message to the display. - Info(msg string) + // OnActionEvent is called when a configured action has been executed + // against a node. + OnActionEvent(e *report.ActionEvent) - // Warn writes a warning message to the display. - Warn(msg string) + // OnPipelineEvent is called when a configured pipeline has been + // executed against a node. + OnPipelineEvent(e *report.PipelineEvent) - // Error writes an error message to the display. - Error(msg string) + // OnComplete is called once at the end of a traversal with the full + // structured outcome. + OnComplete(t *report.Traversal) } // --------------------------------------------------------------------------- diff --git a/src/app/ui/manager_test.go b/src/app/ui/manager_test.go index 69f0672..af225bb 100644 --- a/src/app/ui/manager_test.go +++ b/src/app/ui/manager_test.go @@ -1,11 +1,14 @@ package ui_test import ( + "errors" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/snivilised/jaywalk/src/app/ui" "github.com/snivilised/jaywalk/src/agenor/core" + "github.com/snivilised/jaywalk/src/app/report" + "github.com/snivilised/jaywalk/src/app/ui" ) // --------------------------------------------------------------------------- @@ -67,32 +70,82 @@ var _ = Describe("RegisterMode", func() { }) var _ = Describe("linear Manager", func() { - var m ui.Manager + var ( + m ui.Manager + node *core.Node + ) BeforeEach(func() { var err error m, err = ui.New(ui.ModeLinear) Expect(err).To(BeNil()) + node = &core.Node{Path: "/some/path/file.txt"} }) - Describe("OnNode", func() { - It("does not return an error for a valid node", func() { - node := &core.Node{Path: "/some/path/file.txt"} - Expect(m.OnNode(node)).To(BeNil()) + Describe("OnNodeEvent", func() { + It("does not panic for a valid node", func() { + Expect(func() { + m.OnNodeEvent(&report.NeutralEvent{ + DisplayEvent: report.DisplayEvent{Node: node}, + }) + }).NotTo(Panic()) }) }) - Describe("Info / Warn / Error", func() { - It("Info does not panic", func() { - Expect(func() { m.Info("all good") }).NotTo(Panic()) + Describe("OnActionEvent", func() { + It("does not panic on success", func() { + Expect(func() { + m.OnActionEvent(&report.ActionEvent{ + DisplayEvent: report.DisplayEvent{Node: node, Name: "my-action"}, + }) + }).NotTo(Panic()) }) - It("Warn does not panic", func() { - Expect(func() { m.Warn("something odd") }).NotTo(Panic()) + It("does not panic on failure", func() { + Expect(func() { + m.OnActionEvent(&report.ActionEvent{ + DisplayEvent: report.DisplayEvent{Node: node, Name: "my-action"}, + Err: errors.New("action failed"), + }) + }).NotTo(Panic()) }) + }) - It("Error does not panic", func() { - Expect(func() { m.Error("something broke") }).NotTo(Panic()) + Describe("OnPipelineEvent", func() { + It("does not panic on success", func() { + Expect(func() { + m.OnPipelineEvent(&report.PipelineEvent{ + DisplayEvent: report.DisplayEvent{Node: node, Name: "my-pipeline"}, + }) + }).NotTo(Panic()) + }) + + It("does not panic on failure", func() { + Expect(func() { + m.OnPipelineEvent(&report.PipelineEvent{ + DisplayEvent: report.DisplayEvent{Node: node, Name: "my-pipeline"}, + Err: errors.New("pipeline failed"), + }) + }).NotTo(Panic()) + }) + }) + + Describe("OnComplete", func() { + It("does not panic on a successful traversal", func() { + Expect(func() { + m.OnComplete(&report.Traversal{ + FilesVisited: 10, + DirsVisited: 3, + }) + }).NotTo(Panic()) + }) + + It("does not panic when the traversal contains an error", func() { + Expect(func() { + m.OnComplete(&report.Traversal{ + Err: errors.New("something broke"), + }) + }).NotTo(Panic()) }) }) }) @@ -103,7 +156,7 @@ var _ = Describe("linear Manager", func() { type stubManager struct{} -func (s *stubManager) OnNode(_ *core.Node) error { return nil } -func (s *stubManager) Info(_ string) {} -func (s *stubManager) Warn(_ string) {} -func (s *stubManager) Error(_ string) {} +func (s *stubManager) OnNodeEvent(_ *report.NeutralEvent) {} +func (s *stubManager) OnActionEvent(_ *report.ActionEvent) {} +func (s *stubManager) OnPipelineEvent(_ *report.PipelineEvent) {} +func (s *stubManager) OnComplete(_ *report.Traversal) {} diff --git a/cmd/jay/CLAUDE.md b/src/cmd/jay/CLAUDE.md similarity index 98% rename from cmd/jay/CLAUDE.md rename to src/cmd/jay/CLAUDE.md index 07dda7e..82d0fd3 100644 --- a/cmd/jay/CLAUDE.md +++ b/src/cmd/jay/CLAUDE.md @@ -26,7 +26,7 @@ All flags are defined in `cmd/internal/cfg/flags.go`. ## Viper & Configuration -- Use `viper.GetViper()` to obtain the global viper instance for `cfg.Load` +- Use `viper.GetViper()` to obtain the global viper instance for `bedrock.Load` - Use `viper.Get()` to access configuration values - In tests, use the `viperFromYAML` helper (defined in `./cmd/internal/config/helpers_test.go`) for in-memory viper fixtures instead of reading from disk @@ -53,7 +53,7 @@ All flags are defined in `cmd/internal/cfg/flags.go`. ## i18n -- Translation structs are defined in `github.com/snivilised/jaywalk/locale` +- Translation structs are defined in `github.com/snivilised/jaywalk/src/locale` - Follow the i18n conventions in `GO-USER-CONFIG.md`; locale struct placement is per the package above ## File References diff --git a/cmd/jay/doc.go b/src/cmd/jay/doc.go similarity index 100% rename from cmd/jay/doc.go rename to src/cmd/jay/doc.go diff --git a/cmd/jay/main.go b/src/cmd/jay/main.go similarity index 100% rename from cmd/jay/main.go rename to src/cmd/jay/main.go diff --git a/src/internal/third/bus/broker.go b/src/internal/third/bus/broker.go index 31a55d1..0794ad5 100644 --- a/src/internal/third/bus/broker.go +++ b/src/internal/third/bus/broker.go @@ -11,7 +11,7 @@ import ( "time" "github.com/snivilised/jaywalk/src/agenor/core" - "github.com/snivilised/jaywalk/locale" + "github.com/snivilised/jaywalk/src/locale" ) type ( diff --git a/locale/doc.go b/src/locale/doc.go similarity index 100% rename from locale/doc.go rename to src/locale/doc.go diff --git a/locale/locale-defs.go b/src/locale/locale-defs.go similarity index 100% rename from locale/locale-defs.go rename to src/locale/locale-defs.go diff --git a/locale/locale-suite_test.go b/src/locale/locale-suite_test.go similarity index 100% rename from locale/locale-suite_test.go rename to src/locale/locale-suite_test.go diff --git a/locale/messages-command.go b/src/locale/messages-command.go similarity index 100% rename from locale/messages-command.go rename to src/locale/messages-command.go diff --git a/locale/messages-errors.go b/src/locale/messages-errors.go similarity index 100% rename from locale/messages-errors.go rename to src/locale/messages-errors.go diff --git a/locale/messages-errors_test.go b/src/locale/messages-errors_test.go similarity index 98% rename from locale/messages-errors_test.go rename to src/locale/messages-errors_test.go index df3aad6..3e82a94 100644 --- a/locale/messages-errors_test.go +++ b/src/locale/messages-errors_test.go @@ -8,8 +8,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/snivilised/jaywalk/locale" "github.com/snivilised/jaywalk/src/agenor/test/hanno" + "github.com/snivilised/jaywalk/src/locale" "github.com/snivilised/li18ngo" ) diff --git a/locale/messages-general.go b/src/locale/messages-general.go similarity index 100% rename from locale/messages-general.go rename to src/locale/messages-general.go diff --git a/locale/words.go b/src/locale/words.go similarity index 100% rename from locale/words.go rename to src/locale/words.go diff --git a/tools/inspect/main.go b/tools/inspect/main.go index b314f74..7256a85 100644 --- a/tools/inspect/main.go +++ b/tools/inspect/main.go @@ -510,7 +510,7 @@ func typeParamsString(fset *token.FileSet, tparams *ast.FieldList) string { } // inferredType attempts to derive a human-readable type from a value expression. -// It's intentionally shallow — just enough for common const/var patterns. +// It's intentionally shallow - just enough for common const/var patterns. func inferredType(expr ast.Expr) string { switch e := expr.(type) { case *ast.BasicLit: @@ -524,7 +524,7 @@ func inferredType(expr ast.Expr) string { case token.CHAR: return "rune" default: - // token.IMAG and others — not useful for type inference. + // token.IMAG and others - not useful for type inference. } case *ast.Ident: switch e.Name { @@ -535,7 +535,7 @@ func inferredType(expr ast.Expr) string { } case *ast.CallExpr: if id, ok := e.Fun.(*ast.Ident); ok { - // e.g. errors.New(...) — just return the func name as a hint. + // e.g. errors.New(...) - just return the func name as a hint. return id.Name + "(...)" } if sel, ok := e.Fun.(*ast.SelectorExpr); ok { @@ -550,7 +550,7 @@ func inferredType(expr ast.Expr) string { // --- helpers --- func usage() { - fmt.Fprintln(os.Stderr, `inspect — extract exported declarations from a cached Go module + fmt.Fprintln(os.Stderr, `inspect - extract exported declarations from a cached Go module Usage: inspect [flags] [@version]